summary refs log tree commit diff
path: root/src/libnm-systemd-core
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2023-02-10 11:50:34 +0100
committerMichael Biebl <biebl@debian.org>2023-02-10 11:50:34 +0100
commit1372848511cb896b80b51ed1a3e9606bd9816631 (patch)
tree674792b9385bdef935988894b45f06b2af39f88c /src/libnm-systemd-core
parent40ec077ea305994c1fc2130add6787ca0c73e2c6 (diff)
New upstream version 1.42.0 upstream/1.42.0
Diffstat (limited to 'src/libnm-systemd-core')
-rw-r--r--src/libnm-systemd-core/meson.build3
-rw-r--r--src/libnm-systemd-core/nm-sd.h1
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c198
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.h12
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c11
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h1
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c798
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.h92
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/lldp-network.c72
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/lldp-network.h6
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/lldp-rx-internal.h48
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c160
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c4
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c528
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h1
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c134
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-event.h3
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-lldp-rx.h109
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-lldp.h123
19 files changed, 317 insertions, 1987 deletions
diff --git a/src/libnm-systemd-core/meson.build b/src/libnm-systemd-core/meson.build
index 70293a61..753ca149 100644
--- a/src/libnm-systemd-core/meson.build
+++ b/src/libnm-systemd-core/meson.build
@@ -7,12 +7,9 @@ libnm_systemd_core = static_library(
     'src/libsystemd-network/dhcp6-network.c',
     'src/libsystemd-network/dhcp6-option.c',
     'src/libsystemd-network/dhcp6-protocol.c',
-    'src/libsystemd-network/lldp-neighbor.c',
-    'src/libsystemd-network/lldp-network.c',
     'src/libsystemd-network/network-common.c',
     'src/libsystemd-network/sd-dhcp6-client.c',
     'src/libsystemd-network/sd-dhcp6-lease.c',
-    'src/libsystemd-network/sd-lldp-rx.c',
     'src/libsystemd/sd-event/event-util.c',
     'src/libsystemd/sd-event/sd-event.c',
     'src/libsystemd/sd-id128/id128-util.c',
diff --git a/src/libnm-systemd-core/nm-sd.h b/src/libnm-systemd-core/nm-sd.h
index 79bc5031..80af296e 100644
--- a/src/libnm-systemd-core/nm-sd.h
+++ b/src/libnm-systemd-core/nm-sd.h
@@ -7,7 +7,6 @@
 #define __NM_SD_H__
 
 #include "src/systemd/sd-dhcp6-client.h"
-#include "src/systemd/sd-lldp-rx.h"
 
 /*****************************************************************************/
 
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c
index 05f2a383..14e9c806 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c
@@ -213,47 +213,55 @@ bool dhcp6_option_can_request(uint16_t option) {
         }
 }
 
-static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode, size_t optlen) {
-        assert_return(buf, -EINVAL);
-        assert_return(*buf, -EINVAL);
-        assert_return(buflen, -EINVAL);
+static int option_append_hdr(uint8_t **buf, size_t *offset, uint16_t optcode, size_t optlen) {
+        assert(buf);
+        assert(*buf);
+        assert(offset);
 
-        if (optlen > 0xffff || *buflen < optlen + offsetof(DHCP6Option, data))
+        if (optlen > 0xffff)
                 return -ENOBUFS;
 
-        unaligned_write_be16(*buf + offsetof(DHCP6Option, code), optcode);
-        unaligned_write_be16(*buf + offsetof(DHCP6Option, len), optlen);
+        if (optlen + offsetof(DHCP6Option, data) > SIZE_MAX - *offset)
+                return -ENOBUFS;
 
-        *buf += offsetof(DHCP6Option, data);
-        *buflen -= offsetof(DHCP6Option, data);
+        if (!GREEDY_REALLOC(*buf, *offset + optlen + offsetof(DHCP6Option, data)))
+                return -ENOMEM;
+
+        unaligned_write_be16(*buf + *offset + offsetof(DHCP6Option, code), optcode);
+        unaligned_write_be16(*buf + *offset + offsetof(DHCP6Option, len), optlen);
 
+        *offset += offsetof(DHCP6Option, data);
         return 0;
 }
 
-int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
-                        size_t optlen, const void *optval) {
+int dhcp6_option_append(
+                uint8_t **buf,
+                size_t *offset,
+                uint16_t code,
+                size_t optlen,
+                const void *optval) {
+
         int r;
 
-        assert_return(optval || optlen == 0, -EINVAL);
+        assert(optval || optlen == 0);
 
-        r = option_append_hdr(buf, buflen, code, optlen);
+        r = option_append_hdr(buf, offset, code, optlen);
         if (r < 0)
                 return r;
 
-        *buf = mempcpy_safe(*buf, optval, optlen);
-        *buflen -= optlen;
+        memcpy_safe(*buf + *offset, optval, optlen);
+        *offset += optlen;
 
         return 0;
 }
 
-int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedSet *vendor_options) {
+int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *offset, OrderedSet *vendor_options) {
         sd_dhcp6_option *options;
         int r;
 
         assert(buf);
         assert(*buf);
-        assert(buflen);
-        assert(vendor_options);
+        assert(offset);
 
         ORDERED_SET_FOREACH(options, vendor_options) {
                 _cleanup_free_ uint8_t *p = NULL;
@@ -270,7 +278,7 @@ int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedSet
                 unaligned_write_be16(p + 6, options->length);
                 memcpy(p + 8, options->data, options->length);
 
-                r = dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_OPTS, total, p);
+                r = dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_VENDOR_OPTS, total, p);
                 if (r < 0)
                         return r;
         }
@@ -278,69 +286,48 @@ int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedSet
         return 0;
 }
 
-static int option_append_ia_address(uint8_t **buf, size_t *buflen, const struct iaaddr *address) {
-        struct iaaddr a;
-        int r;
-
+static int option_append_ia_address(uint8_t **buf, size_t *offset, const struct iaaddr *address) {
         assert(buf);
         assert(*buf);
-        assert(buflen);
+        assert(offset);
         assert(address);
 
         /* Do not append T1 and T2. */
-        a = (struct iaaddr) {
+        const struct iaaddr a = {
                 .address = address->address,
         };
 
-        r = option_append_hdr(buf, buflen, SD_DHCP6_OPTION_IAADDR, sizeof(struct iaaddr));
-        if (r < 0)
-                return r;
-
-        *buf = mempcpy(*buf, &a, sizeof(struct iaaddr));
-        *buflen -= sizeof(struct iaaddr);
-
-        return offsetof(DHCP6Option, data) + sizeof(struct iaaddr);
+        return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_IAADDR, sizeof(struct iaaddr), &a);
 }
 
-static int option_append_pd_prefix(uint8_t **buf, size_t *buflen, const struct iapdprefix *prefix) {
-        struct iapdprefix p;
-        int r;
-
+static int option_append_pd_prefix(uint8_t **buf, size_t *offset, const struct iapdprefix *prefix) {
         assert(buf);
         assert(*buf);
-        assert(buflen);
+        assert(offset);
         assert(prefix);
 
         if (prefix->prefixlen == 0)
                 return -EINVAL;
 
         /* Do not append T1 and T2. */
-        p = (struct iapdprefix) {
+        const struct iapdprefix p = {
                 .prefixlen = prefix->prefixlen,
                 .address = prefix->address,
         };
 
-        r = option_append_hdr(buf, buflen, SD_DHCP6_OPTION_IA_PD_PREFIX, sizeof(struct iapdprefix));
-        if (r < 0)
-                return r;
-
-        *buf = mempcpy(*buf, &p, sizeof(struct iapdprefix));
-        *buflen -= sizeof(struct iapdprefix);
-
-        return offsetof(DHCP6Option, data) + sizeof(struct iapdprefix);
+        return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_IA_PD_PREFIX, sizeof(struct iapdprefix), &p);
 }
 
-int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia) {
+int dhcp6_option_append_ia(uint8_t **buf, size_t *offset, const DHCP6IA *ia) {
+        _cleanup_free_ uint8_t *data = NULL;
         struct ia_header header;
-        size_t ia_buflen;
-        uint8_t *ia_hdr;
-        uint16_t len;
+        size_t len;
         int r;
 
-        assert_return(buf, -EINVAL);
-        assert_return(*buf, -EINVAL);
-        assert_return(buflen, -EINVAL);
-        assert_return(ia, -EINVAL);
+        assert(buf);
+        assert(*buf);
+        assert(offset);
+        assert(ia);
 
         /* client should not send set T1 and T2. See, RFC 8415, and issue #18090. */
 
@@ -364,43 +351,38 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia) {
                 assert_not_reached();
         }
 
-        if (*buflen < offsetof(DHCP6Option, data) + len)
-                return -ENOBUFS;
-
-        ia_hdr = *buf;
-        ia_buflen = *buflen;
-
-        /* The header will be written at the end of this function. */
-        *buf += offsetof(DHCP6Option, data);
-        *buflen -= offsetof(DHCP6Option, data);
+        if (!GREEDY_REALLOC(data, len))
+                return -ENOMEM;
 
-        *buf = mempcpy(*buf, &header, len);
-        *buflen -= len;
+        memcpy(data, &header, len);
 
         LIST_FOREACH(addresses, addr, ia->addresses) {
                 if (ia->type == SD_DHCP6_OPTION_IA_PD)
-                        r = option_append_pd_prefix(buf, buflen, &addr->iapdprefix);
+                        r = option_append_pd_prefix(&data, &len, &addr->iapdprefix);
                 else
-                        r = option_append_ia_address(buf, buflen, &addr->iaaddr);
+                        r = option_append_ia_address(&data, &len, &addr->iaaddr);
                 if (r < 0)
                         return r;
-
-                len += r;
         }
 
-        return option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len);
+        return dhcp6_option_append(buf, offset, ia->type, len, data);
 }
 
-int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
+int dhcp6_option_append_fqdn(uint8_t **buf, size_t *offset, const char *fqdn) {
         uint8_t buffer[1 + DNS_WIRE_FORMAT_HOSTNAME_MAX];
         int r;
 
-        assert_return(buf && *buf && buflen && fqdn, -EINVAL);
+        assert(buf);
+        assert(*buf);
+        assert(offset);
+
+        if (isempty(fqdn))
+                return 0;
 
         buffer[0] = DHCP6_FQDN_FLAG_S; /* Request server to perform AAAA RR DNS updates */
 
         /* Store domain name after flags field */
-        r = dns_name_to_wire_format(fqdn, buffer + 1, sizeof(buffer) - 1,  false);
+        r = dns_name_to_wire_format(fqdn, buffer + 1, sizeof(buffer) - 1, false);
         if (r <= 0)
                 return r;
 
@@ -413,82 +395,70 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
         if (dns_name_is_single_label(fqdn))
                 r--;
 
-        r = dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_CLIENT_FQDN, 1 + r, buffer);
-
-        return r;
+        return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_CLIENT_FQDN, 1 + r, buffer);
 }
 
-int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *user_class) {
+int dhcp6_option_append_user_class(uint8_t **buf, size_t *offset, char * const *user_class) {
         _cleanup_free_ uint8_t *p = NULL;
-        size_t total = 0, offset = 0;
+        size_t n = 0;
 
         assert(buf);
         assert(*buf);
-        assert(buflen);
-        assert(!strv_isempty(user_class));
+        assert(offset);
+
+        if (strv_isempty(user_class))
+                return 0;
 
         STRV_FOREACH(s, user_class) {
                 size_t len = strlen(*s);
-                uint8_t *q;
 
-                if (len > 0xffff || len == 0)
+                if (len > UINT16_MAX || len == 0)
                         return -EINVAL;
-                q = realloc(p, total + len + 2);
-                if (!q)
-                        return -ENOMEM;
 
-                p = q;
-
-                unaligned_write_be16(&p[offset], len);
-                memcpy(&p[offset + 2], *s, len);
+                if (!GREEDY_REALLOC(p, n + len + 2))
+                        return -ENOMEM;
 
-                offset += 2 + len;
-                total += 2 + len;
+                unaligned_write_be16(p + n, len);
+                memcpy(p + n + 2, *s, len);
+                n += len + 2;
         }
 
-        return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_USER_CLASS, total, p);
+        return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_USER_CLASS, n, p);
 }
 
-int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const *vendor_class) {
+int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *offset, char * const *vendor_class) {
         _cleanup_free_ uint8_t *p = NULL;
-        uint32_t enterprise_identifier;
-        size_t total, offset;
+        size_t n = 0;
 
         assert(buf);
         assert(*buf);
-        assert(buflen);
-        assert(!strv_isempty(vendor_class));
+        assert(offset);
 
-        enterprise_identifier = htobe32(SYSTEMD_PEN);
+        if (strv_isempty(vendor_class))
+                return 0;
 
-        p = memdup(&enterprise_identifier, sizeof(enterprise_identifier));
-        if (!p)
+        if (!GREEDY_REALLOC(p, sizeof(be32_t)))
                 return -ENOMEM;
 
-        total = sizeof(enterprise_identifier);
-        offset = total;
+        /* Enterprise Identifier */
+        unaligned_write_be32(p, SYSTEMD_PEN);
+        n += sizeof(be32_t);
 
         STRV_FOREACH(s, vendor_class) {
                 size_t len = strlen(*s);
-                uint8_t *q;
 
                 if (len > UINT16_MAX || len == 0)
                         return -EINVAL;
 
-                q = realloc(p, total + len + 2);
-                if (!q)
+                if (!GREEDY_REALLOC(p, n + len + 2))
                         return -ENOMEM;
 
-                p = q;
-
-                unaligned_write_be16(&p[offset], len);
-                memcpy(&p[offset + 2], *s, len);
-
-                offset += 2 + len;
-                total += 2 + len;
+                unaligned_write_be16(p + n, len);
+                memcpy(p + n + 2, *s, len);
+                n += len + 2;
         }
 
-        return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_CLASS, total, p);
+        return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_VENDOR_CLASS, n, p);
 }
 
 int dhcp6_option_parse(
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.h
index 80aba7f3..36841dd2 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.h
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.h
@@ -72,13 +72,13 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6IA*, dhcp6_ia_free);
 
 bool dhcp6_option_can_request(uint16_t option);
 
-int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
+int dhcp6_option_append(uint8_t **buf, size_t *offset, uint16_t code,
                         size_t optlen, const void *optval);
-int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia);
-int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn);
-int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *user_class);
-int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const *user_class);
-int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedSet *vendor_options);
+int dhcp6_option_append_ia(uint8_t **buf, size_t *offset, const DHCP6IA *ia);
+int dhcp6_option_append_fqdn(uint8_t **buf, size_t *offset, const char *fqdn);
+int dhcp6_option_append_user_class(uint8_t **buf, size_t *offset, char * const *user_class);
+int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *offset, char * const *vendor_class);
+int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *offset, OrderedSet *vendor_options);
 
 int dhcp6_option_parse(
                 const uint8_t *buf,
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c
index e19faa51..4e945777 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.c
@@ -84,3 +84,14 @@ static const char * const dhcp6_message_status_table[_DHCP6_STATUS_MAX] = {
 };
 
 DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, DHCP6Status);
+
+int dhcp6_message_status_to_errno(DHCP6Status s) {
+        switch (s) {
+        case DHCP6_STATUS_SUCCESS:
+                return 0;
+        case DHCP6_STATUS_NO_BINDING:
+                return -EADDRNOTAVAIL;
+        default:
+                return -EINVAL;
+        }
+}
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h
index f4e47857..18217691 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h
@@ -154,3 +154,4 @@ const char *dhcp6_message_type_to_string(DHCP6MessageType s) _const_;
 DHCP6MessageType dhcp6_message_type_from_string(const char *s) _pure_;
 const char *dhcp6_message_status_to_string(DHCP6Status s) _const_;
 DHCP6Status dhcp6_message_status_from_string(const char *s) _pure_;
+int dhcp6_message_status_to_errno(DHCP6Status s);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c b/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c
deleted file mode 100644
index d4aec944..00000000
--- a/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c
+++ /dev/null
@@ -1,798 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-core.h"
-
-#include "alloc-util.h"
-#include "escape.h"
-#include "ether-addr-util.h"
-#include "hexdecoct.h"
-#include "in-addr-util.h"
-#include "lldp-neighbor.h"
-#include "memory-util.h"
-#include "missing_network.h"
-#include "unaligned.h"
-
-static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash *state) {
-        assert(id);
-        assert(state);
-
-        siphash24_compress(id->chassis_id, id->chassis_id_size, state);
-        siphash24_compress(&id->chassis_id_size, sizeof(id->chassis_id_size), state);
-        siphash24_compress(id->port_id, id->port_id_size, state);
-        siphash24_compress(&id->port_id_size, sizeof(id->port_id_size), state);
-}
-
-int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y) {
-        assert(x);
-        assert(y);
-
-        return memcmp_nn(x->chassis_id, x->chassis_id_size, y->chassis_id, y->chassis_id_size)
-            ?: memcmp_nn(x->port_id, x->port_id_size, y->port_id, y->port_id_size);
-}
-
-DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
-        lldp_neighbor_hash_ops,
-        LLDPNeighborID,
-        lldp_neighbor_id_hash_func,
-        lldp_neighbor_id_compare_func,
-        sd_lldp_neighbor,
-        lldp_neighbor_unlink);
-
-int lldp_neighbor_prioq_compare_func(const void *a, const void *b) {
-        const sd_lldp_neighbor *x = a, *y = b;
-
-        assert(x);
-        assert(y);
-
-        return CMP(x->until, y->until);
-}
-
-sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) {
-        if (!n)
-                return NULL;
-
-        assert(n->n_ref > 0 || n->lldp_rx);
-        n->n_ref++;
-
-        return n;
-}
-
-static sd_lldp_neighbor *lldp_neighbor_free(sd_lldp_neighbor *n) {
-        if (!n)
-                return NULL;
-
-        free(n->id.port_id);
-        free(n->id.chassis_id);
-        free(n->port_description);
-        free(n->system_name);
-        free(n->system_description);
-        free(n->mud_url);
-        free(n->chassis_id_as_string);
-        free(n->port_id_as_string);
-        return mfree(n);
-}
-
-sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n) {
-
-        /* Drops one reference from the neighbor. Note that the object is not freed unless it is already unlinked from
-         * the sd_lldp object. */
-
-        if (!n)
-                return NULL;
-
-        assert(n->n_ref > 0);
-        n->n_ref--;
-
-        if (n->n_ref <= 0 && !n->lldp_rx)
-                lldp_neighbor_free(n);
-
-        return NULL;
-}
-
-sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n) {
-
-        /* Removes the neighbor object from the LLDP object, and frees it if it also has no other reference. */
-
-        if (!n)
-                return NULL;
-
-        if (!n->lldp_rx)
-                return NULL;
-
-        /* Only remove the neighbor object from the hash table if it's in there, don't complain if it isn't. This is
-         * because we are used as destructor call for hashmap_clear() and thus sometimes are called to de-register
-         * ourselves from the hashtable and sometimes are called after we already are de-registered. */
-
-        (void) hashmap_remove_value(n->lldp_rx->neighbor_by_id, &n->id, n);
-
-        assert_se(prioq_remove(n->lldp_rx->neighbor_by_expiry, n, &n->prioq_idx) >= 0);
-
-        n->lldp_rx = NULL;
-
-        if (n->n_ref <= 0)
-                lldp_neighbor_free(n);
-
-        return NULL;
-}
-
-sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size) {
-        sd_lldp_neighbor *n;
-
-        if (raw_size > SIZE_MAX - ALIGN(sizeof(sd_lldp_neighbor)))
-                return NULL;
-
-        n = malloc0(ALIGN(sizeof(sd_lldp_neighbor)) + raw_size);
-        if (!n)
-                return NULL;
-
-        n->raw_size = raw_size;
-        n->n_ref = 1;
-
-        return n;
-}
-
-static int parse_string(sd_lldp_rx *lldp_rx, char **s, const void *q, size_t n) {
-        const char *p = q;
-        char *k;
-
-        assert(s);
-        assert(p || n == 0);
-
-        if (*s) {
-                log_lldp_rx(lldp_rx, "Found duplicate string, ignoring field.");
-                return 0;
-        }
-
-        /* Strip trailing NULs, just to be nice */
-        while (n > 0 && p[n-1] == 0)
-                n--;
-
-        if (n <= 0) /* Ignore empty strings */
-                return 0;
-
-        /* Look for inner NULs */
-        if (memchr(p, 0, n)) {
-                log_lldp_rx(lldp_rx, "Found inner NUL in string, ignoring field.");
-                return 0;
-        }
-
-        /* Let's escape weird chars, for security reasons */
-        k = cescape_length(p, n);
-        if (!k)
-                return log_oom_debug();
-
-        free(*s);
-        *s = k;
-
-        return 1;
-}
-
-int lldp_neighbor_parse(sd_lldp_neighbor *n) {
-        struct ether_header h;
-        const uint8_t *p;
-        size_t left;
-        int r;
-
-        assert(n);
-
-        if (n->raw_size < sizeof(struct ether_header))
-                return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                         "Received truncated packet, ignoring.");
-
-        memcpy(&h, LLDP_NEIGHBOR_RAW(n), sizeof(h));
-
-        if (h.ether_type != htobe16(ETHERTYPE_LLDP))
-                return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                         "Received packet with wrong type, ignoring.");
-
-        if (h.ether_dhost[0] != 0x01 ||
-            h.ether_dhost[1] != 0x80 ||
-            h.ether_dhost[2] != 0xc2 ||
-            h.ether_dhost[3] != 0x00 ||
-            h.ether_dhost[4] != 0x00 ||
-            !IN_SET(h.ether_dhost[5], 0x00, 0x03, 0x0e))
-                return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                         "Received packet with wrong destination address, ignoring.");
-
-        memcpy(&n->source_address, h.ether_shost, sizeof(struct ether_addr));
-        memcpy(&n->destination_address, h.ether_dhost, sizeof(struct ether_addr));
-
-        p = (const uint8_t*) LLDP_NEIGHBOR_RAW(n) + sizeof(struct ether_header);
-        left = n->raw_size - sizeof(struct ether_header);
-
-        for (;;) {
-                uint8_t type;
-                uint16_t length;
-
-                if (left < 2)
-                        return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                              "TLV lacks header, ignoring.");
-
-                type = p[0] >> 1;
-                length = p[1] + (((uint16_t) (p[0] & 1)) << 8);
-                p += 2, left -= 2;
-
-                if (left < length)
-                        return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                                 "TLV truncated, ignoring datagram.");
-
-                switch (type) {
-
-                case SD_LLDP_TYPE_END:
-                        if (length != 0)
-                                return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                                         "End marker TLV not zero-sized, ignoring datagram.");
-
-                        /* Note that after processing the SD_LLDP_TYPE_END left could still be > 0
-                         * as the message may contain padding (see IEEE 802.1AB-2016, sec. 8.5.12) */
-
-                        goto end_marker;
-
-                case SD_LLDP_TYPE_CHASSIS_ID:
-                        if (length < 2 || length > 256)
-                                /* includes the chassis subtype, hence one extra byte */
-                                return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                                         "Chassis ID field size out of range, ignoring datagram.");
-
-                        if (n->id.chassis_id)
-                                return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                                         "Duplicate chassis ID field, ignoring datagram.");
-
-                        n->id.chassis_id = memdup(p, length);
-                        if (!n->id.chassis_id)
-                                return log_oom_debug();
-
-                        n->id.chassis_id_size = length;
-                        break;
-
-                case SD_LLDP_TYPE_PORT_ID:
-                        if (length < 2 || length > 256)
-                                /* includes the port subtype, hence one extra byte */
-                                return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                                         "Port ID field size out of range, ignoring datagram.");
-
-                        if (n->id.port_id)
-                                return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                                         "Duplicate port ID field, ignoring datagram.");
-
-                        n->id.port_id = memdup(p, length);
-                        if (!n->id.port_id)
-                                return log_oom_debug();
-
-                        n->id.port_id_size = length;
-                        break;
-
-                case SD_LLDP_TYPE_TTL:
-                        if (length != 2)
-                                return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                                         "TTL field has wrong size, ignoring datagram.");
-
-                        if (n->has_ttl)
-                                return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                                         "Duplicate TTL field, ignoring datagram.");
-
-                        n->ttl = unaligned_read_be16(p);
-                        n->has_ttl = true;
-                        break;
-
-                case SD_LLDP_TYPE_PORT_DESCRIPTION:
-                        r = parse_string(n->lldp_rx, &n->port_description, p, length);
-                        if (r < 0)
-                                return r;
-                        break;
-
-                case SD_LLDP_TYPE_SYSTEM_NAME:
-                        r = parse_string(n->lldp_rx, &n->system_name, p, length);
-                        if (r < 0)
-                                return r;
-                        break;
-
-                case SD_LLDP_TYPE_SYSTEM_DESCRIPTION:
-                        r = parse_string(n->lldp_rx, &n->system_description, p, length);
-                        if (r < 0)
-                                return r;
-                        break;
-
-                case SD_LLDP_TYPE_SYSTEM_CAPABILITIES:
-                        if (length != 4)
-                                return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                                         "System capabilities field has wrong size.");
-
-                        n->system_capabilities = unaligned_read_be16(p);
-                        n->enabled_capabilities = unaligned_read_be16(p + 2);
-                        n->has_capabilities = true;
-                        break;
-
-                case SD_LLDP_TYPE_PRIVATE:
-                        if (length < 4)
-                                return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                                         "Found private TLV that is too short, ignoring.");
-
-                        /* RFC 8520: MUD URL */
-                        if (memcmp(p, SD_LLDP_OUI_IANA_MUD, sizeof(SD_LLDP_OUI_IANA_MUD)) == 0) {
-                                r = parse_string(n->lldp_rx, &n->mud_url, p + sizeof(SD_LLDP_OUI_IANA_MUD),
-                                                 length - sizeof(SD_LLDP_OUI_IANA_MUD));
-                                if (r < 0)
-                                        return r;
-                        }
-                        break;
-                }
-
-                p += length, left -= length;
-        }
-
-end_marker:
-        if (!n->id.chassis_id || !n->id.port_id || !n->has_ttl)
-                return log_lldp_rx_errno(n->lldp_rx, SYNTHETIC_ERRNO(EBADMSG),
-                                         "One or more mandatory TLV missing in datagram. Ignoring.");
-
-        n->rindex = sizeof(struct ether_header);
-
-        return 0;
-}
-
-void lldp_neighbor_start_ttl(sd_lldp_neighbor *n) {
-        assert(n);
-
-        if (n->ttl > 0) {
-                usec_t base;
-
-                /* Use the packet's timestamp if there is one known */
-                base = triple_timestamp_by_clock(&n->timestamp, CLOCK_BOOTTIME);
-                if (!timestamp_is_set(base))
-                        base = now(CLOCK_BOOTTIME); /* Otherwise, take the current time */
-
-                n->until = usec_add(base, n->ttl * USEC_PER_SEC);
-        } else
-                n->until = 0;
-
-        if (n->lldp_rx)
-                prioq_reshuffle(n->lldp_rx->neighbor_by_expiry, n, &n->prioq_idx);
-}
-
-bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b) {
-        if (a == b)
-                return true;
-
-        if (!a || !b)
-                return false;
-
-        if (a->raw_size != b->raw_size)
-                return false;
-
-        return memcmp(LLDP_NEIGHBOR_RAW(a), LLDP_NEIGHBOR_RAW(b), a->raw_size) == 0;
-}
-
-int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address) {
-        assert_return(n, -EINVAL);
-        assert_return(address, -EINVAL);
-
-        *address = n->source_address;
-        return 0;
-}
-
-int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address) {
-        assert_return(n, -EINVAL);
-        assert_return(address, -EINVAL);
-
-        *address = n->destination_address;
-        return 0;
-}
-
-int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
-        assert_return(n, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(size, -EINVAL);
-
-        *ret = LLDP_NEIGHBOR_RAW(n);
-        *size = n->raw_size;
-
-        return 0;
-}
-
-int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
-        assert_return(n, -EINVAL);
-        assert_return(type, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(size, -EINVAL);
-
-        assert(n->id.chassis_id_size > 0);
-
-        *type = *(uint8_t*) n->id.chassis_id;
-        *ret = (uint8_t*) n->id.chassis_id + 1;
-        *size = n->id.chassis_id_size - 1;
-
-        return 0;
-}
-
-static int format_mac_address(const void *data, size_t sz, char **ret) {
-        struct ether_addr a;
-        char *k;
-
-        assert(data || sz <= 0);
-
-        if (sz != 7)
-                return 0;
-
-        memcpy(&a, (uint8_t*) data + 1, sizeof(a));
-
-        k = new(char, ETHER_ADDR_TO_STRING_MAX);
-        if (!k)
-                return -ENOMEM;
-
-        *ret = ether_addr_to_string(&a, k);
-        return 1;
-}
-
-static int format_network_address(const void *data, size_t sz, char **ret) {
-        union in_addr_union a;
-        int family, r;
-
-        if (sz == 6 && ((uint8_t*) data)[1] == 1) {
-                memcpy(&a.in, (uint8_t*) data + 2, sizeof(a.in));
-                family = AF_INET;
-        } else if (sz == 18 && ((uint8_t*) data)[1] == 2) {
-                memcpy(&a.in6, (uint8_t*) data + 2, sizeof(a.in6));
-                family = AF_INET6;
-        } else
-                return 0;
-
-        r = in_addr_to_string(family, &a, ret);
-        if (r < 0)
-                return r;
-        return 1;
-}
-
-int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) {
-        char *k;
-        int r;
-
-        assert_return(n, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (n->chassis_id_as_string) {
-                *ret = n->chassis_id_as_string;
-                return 0;
-        }
-
-        assert(n->id.chassis_id_size > 0);
-
-        switch (*(uint8_t*) n->id.chassis_id) {
-
-        case SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT:
-        case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS:
-        case SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT:
-        case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME:
-        case SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED:
-                k = cescape_length((char*) n->id.chassis_id + 1, n->id.chassis_id_size - 1);
-                if (!k)
-                        return -ENOMEM;
-
-                goto done;
-
-        case SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
-                r = format_mac_address(n->id.chassis_id, n->id.chassis_id_size, &k);
-                if (r < 0)
-                        return r;
-                if (r > 0)
-                        goto done;
-
-                break;
-
-        case SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS:
-                r = format_network_address(n->id.chassis_id, n->id.chassis_id_size, &k);
-                if (r < 0)
-                        return r;
-                if (r > 0)
-                        goto done;
-
-                break;
-        }
-
-        /* Generic fallback */
-        k = hexmem(n->id.chassis_id, n->id.chassis_id_size);
-        if (!k)
-                return -ENOMEM;
-
-done:
-        *ret = n->chassis_id_as_string = k;
-        return 0;
-}
-
-int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
-        assert_return(n, -EINVAL);
-        assert_return(type, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(size, -EINVAL);
-
-        assert(n->id.port_id_size > 0);
-
-        *type = *(uint8_t*) n->id.port_id;
-        *ret = (uint8_t*) n->id.port_id + 1;
-        *size = n->id.port_id_size - 1;
-
-        return 0;
-}
-
-int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret) {
-        char *k;
-        int r;
-
-        assert_return(n, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (n->port_id_as_string) {
-                *ret = n->port_id_as_string;
-                return 0;
-        }
-
-        assert(n->id.port_id_size > 0);
-
-        switch (*(uint8_t*) n->id.port_id) {
-
-        case SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
-        case SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT:
-        case SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME:
-        case SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED:
-                k = cescape_length((char*) n->id.port_id + 1, n->id.port_id_size - 1);
-                if (!k)
-                        return -ENOMEM;
-
-                goto done;
-
-        case SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS:
-                r = format_mac_address(n->id.port_id, n->id.port_id_size, &k);
-                if (r < 0)
-                        return r;
-                if (r > 0)
-                        goto done;
-
-                break;
-
-        case SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS:
-                r = format_network_address(n->id.port_id, n->id.port_id_size, &k);
-                if (r < 0)
-                        return r;
-                if (r > 0)
-                        goto done;
-
-                break;
-        }
-
-        /* Generic fallback */
-        k = hexmem(n->id.port_id, n->id.port_id_size);
-        if (!k)
-                return -ENOMEM;
-
-done:
-        *ret = n->port_id_as_string = k;
-        return 0;
-}
-
-int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec) {
-        assert_return(n, -EINVAL);
-        assert_return(ret_sec, -EINVAL);
-
-        *ret_sec = n->ttl;
-        return 0;
-}
-
-int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret) {
-        assert_return(n, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (!n->system_name)
-                return -ENODATA;
-
-        *ret = n->system_name;
-        return 0;
-}
-
-int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret) {
-        assert_return(n, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (!n->system_description)
-                return -ENODATA;
-
-        *ret = n->system_description;
-        return 0;
-}
-
-int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret) {
-        assert_return(n, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (!n->port_description)
-                return -ENODATA;
-
-        *ret = n->port_description;
-        return 0;
-}
-
-int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret) {
-        assert_return(n, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (!n->mud_url)
-                return -ENODATA;
-
-        *ret = n->mud_url;
-        return 0;
-}
-
-int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
-        assert_return(n, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (!n->has_capabilities)
-                return -ENODATA;
-
-        *ret = n->system_capabilities;
-        return 0;
-}
-
-int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
-        assert_return(n, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (!n->has_capabilities)
-                return -ENODATA;
-
-        *ret = n->enabled_capabilities;
-        return 0;
-}
-
-int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) {
-        _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
-        int r;
-
-        assert_return(ret, -EINVAL);
-        assert_return(raw || raw_size <= 0, -EINVAL);
-
-        n = lldp_neighbor_new(raw_size);
-        if (!n)
-                return -ENOMEM;
-
-        memcpy_safe(LLDP_NEIGHBOR_RAW(n), raw, raw_size);
-
-        r = lldp_neighbor_parse(n);
-        if (r < 0)
-                return r;
-
-        *ret = TAKE_PTR(n);
-
-        return r;
-}
-
-int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
-        assert_return(n, -EINVAL);
-
-        assert(n->raw_size >= sizeof(struct ether_header));
-        n->rindex = sizeof(struct ether_header);
-
-        return n->rindex < n->raw_size;
-}
-
-int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) {
-        size_t length;
-
-        assert_return(n, -EINVAL);
-
-        if (n->rindex == n->raw_size) /* EOF */
-                return -ESPIPE;
-
-        if (n->rindex + 2 > n->raw_size) /* Truncated message */
-                return -EBADMSG;
-
-        length = LLDP_NEIGHBOR_TLV_LENGTH(n);
-        if (n->rindex + 2 + length > n->raw_size)
-                return -EBADMSG;
-
-        n->rindex += 2 + length;
-        return n->rindex < n->raw_size;
-}
-
-int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) {
-        assert_return(n, -EINVAL);
-        assert_return(type, -EINVAL);
-
-        if (n->rindex == n->raw_size) /* EOF */
-                return -ESPIPE;
-
-        if (n->rindex + 2 > n->raw_size)
-                return -EBADMSG;
-
-        *type = LLDP_NEIGHBOR_TLV_TYPE(n);
-        return 0;
-}
-
-int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) {
-        uint8_t k;
-        int r;
-
-        assert_return(n, -EINVAL);
-
-        r = sd_lldp_neighbor_tlv_get_type(n, &k);
-        if (r < 0)
-                return r;
-
-        return type == k;
-}
-
-int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t *subtype) {
-        const uint8_t *d;
-        size_t length;
-        int r;
-
-        assert_return(n, -EINVAL);
-        assert_return(oui, -EINVAL);
-        assert_return(subtype, -EINVAL);
-
-        r = sd_lldp_neighbor_tlv_is_type(n, SD_LLDP_TYPE_PRIVATE);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                return -ENXIO;
-
-        length = LLDP_NEIGHBOR_TLV_LENGTH(n);
-        if (length < 4)
-                return -EBADMSG;
-
-        if (n->rindex + 2 + length > n->raw_size)
-                return -EBADMSG;
-
-        d = LLDP_NEIGHBOR_TLV_DATA(n);
-        memcpy(oui, d, 3);
-        *subtype = d[3];
-
-        return 0;
-}
-
-int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t subtype) {
-        uint8_t k[3], st;
-        int r;
-
-        r = sd_lldp_neighbor_tlv_get_oui(n, k, &st);
-        if (r == -ENXIO)
-                return 0;
-        if (r < 0)
-                return r;
-
-        return memcmp(k, oui, 3) == 0 && st == subtype;
-}
-
-int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
-        size_t length;
-
-        assert_return(n, -EINVAL);
-        assert_return(ret, -EINVAL);
-        assert_return(size, -EINVAL);
-
-        /* Note that this returns the full TLV, including the TLV header */
-
-        if (n->rindex + 2 > n->raw_size)
-                return -EBADMSG;
-
-        length = LLDP_NEIGHBOR_TLV_LENGTH(n);
-        if (n->rindex + 2 + length > n->raw_size)
-                return -EBADMSG;
-
-        *ret = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex;
-        *size = length + 2;
-
-        return 0;
-}
-
-int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret) {
-        assert_return(n, -EINVAL);
-        assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
-        assert_return(clock_supported(clock), -EOPNOTSUPP);
-        assert_return(ret, -EINVAL);
-
-        if (!triple_timestamp_is_set(&n->timestamp))
-                return -ENODATA;
-
-        *ret = triple_timestamp_by_clock(&n->timestamp, clock);
-        return 0;
-}
diff --git a/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.h b/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.h
deleted file mode 100644
index 016286b1..00000000
--- a/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <inttypes.h>
-#include <stdbool.h>
-#include <sys/types.h>
-
-#include "sd-lldp-rx.h"
-
-#include "hash-funcs.h"
-#include "lldp-rx-internal.h"
-#include "time-util.h"
-
-typedef struct LLDPNeighborID {
-        /* The spec calls this an "MSAP identifier" */
-        void *chassis_id;
-        size_t chassis_id_size;
-
-        void *port_id;
-        size_t port_id_size;
-} LLDPNeighborID;
-
-struct sd_lldp_neighbor {
-        /* Neighbor objects stay around as long as they are linked into an "sd_lldp_rx" object or n_ref > 0. */
-        sd_lldp_rx *lldp_rx;
-        unsigned n_ref;
-
-        triple_timestamp timestamp;
-
-        usec_t until;
-        unsigned prioq_idx;
-
-        struct ether_addr source_address;
-        struct ether_addr destination_address;
-
-        LLDPNeighborID id;
-
-        /* The raw packet size. The data is appended to the object, accessible via LLDP_NEIGHBOR_RAW() */
-        size_t raw_size;
-
-        /* The current read index for the iterative TLV interface */
-        size_t rindex;
-
-        /* And a couple of fields parsed out. */
-        bool has_ttl:1;
-        bool has_capabilities:1;
-        bool has_port_vlan_id:1;
-
-        uint16_t ttl;
-
-        uint16_t system_capabilities;
-        uint16_t enabled_capabilities;
-
-        char *port_description;
-        char *system_name;
-        char *system_description;
-        char *mud_url;
-
-        uint16_t port_vlan_id;
-
-        char *chassis_id_as_string;
-        char *port_id_as_string;
-};
-
-static inline void *LLDP_NEIGHBOR_RAW(const sd_lldp_neighbor *n) {
-        return (uint8_t*) n + ALIGN(sizeof(sd_lldp_neighbor));
-}
-
-static inline uint8_t LLDP_NEIGHBOR_TLV_TYPE(const sd_lldp_neighbor *n) {
-        return ((uint8_t*) LLDP_NEIGHBOR_RAW(n))[n->rindex] >> 1;
-}
-
-static inline size_t LLDP_NEIGHBOR_TLV_LENGTH(const sd_lldp_neighbor *n) {
-        uint8_t *p;
-
-        p = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex;
-        return p[1] + (((size_t) (p[0] & 1)) << 8);
-}
-
-static inline void* LLDP_NEIGHBOR_TLV_DATA(const sd_lldp_neighbor *n) {
-        return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2;
-}
-
-extern const struct hash_ops lldp_neighbor_hash_ops;
-int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y);
-int lldp_neighbor_prioq_compare_func(const void *a, const void *b);
-
-sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n);
-sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size);
-int lldp_neighbor_parse(sd_lldp_neighbor *n);
-void lldp_neighbor_start_ttl(sd_lldp_neighbor *n);
-bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/lldp-network.c b/src/libnm-systemd-core/src/libsystemd-network/lldp-network.c
deleted file mode 100644
index 00eb9703..00000000
--- a/src/libnm-systemd-core/src/libsystemd-network/lldp-network.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-core.h"
-
-#include <linux/filter.h>
-#include <netinet/if_ether.h>
-
-#include "fd-util.h"
-#include "lldp-network.h"
-#include "missing_network.h"
-#include "socket-util.h"
-
-int lldp_network_bind_raw_socket(int ifindex) {
-        static const struct sock_filter filter[] = {
-                BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ethhdr, h_dest)),      /* A <- 4 bytes of destination MAC */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0180c200, 1, 0),                    /* A != 01:80:c2:00 */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                             /* drop packet */
-                BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_dest) + 4),  /* A <- remaining 2 bytes of destination MAC */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0000, 3, 0),                        /* A != 00:00 */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0003, 2, 0),                        /* A != 00:03 */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x000e, 1, 0),                        /* A != 00:0e */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                             /* drop packet */
-                BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_proto)),     /* A <- protocol */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_LLDP, 1, 0),                /* A != ETHERTYPE_LLDP */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                             /* drop packet */
-                BPF_STMT(BPF_RET + BPF_K, UINT32_MAX),                                    /* accept packet */
-        };
-        static const struct sock_fprog fprog = {
-                .len = ELEMENTSOF(filter),
-                .filter = (struct sock_filter*) filter,
-        };
-        struct packet_mreq mreq = {
-                .mr_ifindex = ifindex,
-                .mr_type = PACKET_MR_MULTICAST,
-                .mr_alen = ETH_ALEN,
-                .mr_address = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00 }
-        };
-        union sockaddr_union saddrll = {
-                .ll.sll_family = AF_PACKET,
-                .ll.sll_ifindex = ifindex,
-        };
-        _cleanup_close_ int fd = -1;
-
-        assert(ifindex > 0);
-
-        fd = socket(AF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK,
-                    htobe16(ETHERTYPE_LLDP));
-        if (fd < 0)
-                return -errno;
-
-        if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0)
-                return -errno;
-
-        /* customer bridge */
-        if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
-                return -errno;
-
-        /* non TPMR bridge */
-        mreq.mr_address[ETH_ALEN - 1] = 0x03;
-        if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
-                return -errno;
-
-        /* nearest bridge */
-        mreq.mr_address[ETH_ALEN - 1] = 0x0E;
-        if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
-                return -errno;
-
-        if (bind(fd, &saddrll.sa, sizeof(saddrll.ll)) < 0)
-                return -errno;
-
-        return TAKE_FD(fd);
-}
diff --git a/src/libnm-systemd-core/src/libsystemd-network/lldp-network.h b/src/libnm-systemd-core/src/libsystemd-network/lldp-network.h
deleted file mode 100644
index bc69b324..00000000
--- a/src/libnm-systemd-core/src/libsystemd-network/lldp-network.h
+++ /dev/null
@@ -1,6 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include "sd-event.h"
-
-int lldp_network_bind_raw_socket(int ifindex);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/lldp-rx-internal.h b/src/libnm-systemd-core/src/libsystemd-network/lldp-rx-internal.h
deleted file mode 100644
index 83d0bc46..00000000
--- a/src/libnm-systemd-core/src/libsystemd-network/lldp-rx-internal.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include "sd-event.h"
-#include "sd-lldp-rx.h"
-
-#include "hashmap.h"
-#include "network-common.h"
-#include "prioq.h"
-
-struct sd_lldp_rx {
-        unsigned n_ref;
-
-        int ifindex;
-        char *ifname;
-        int fd;
-
-        sd_event *event;
-        int64_t event_priority;
-        sd_event_source *io_event_source;
-        sd_event_source *timer_event_source;
-
-        Prioq *neighbor_by_expiry;
-        Hashmap *neighbor_by_id;
-
-        uint64_t neighbors_max;
-
-        sd_lldp_rx_callback_t callback;
-        void *userdata;
-
-        uint16_t capability_mask;
-
-        struct ether_addr filter_address;
-};
-
-const char* lldp_rx_event_to_string(sd_lldp_rx_event_t e) _const_;
-sd_lldp_rx_event_t lldp_rx_event_from_string(const char *s) _pure_;
-
-#define log_lldp_rx_errno(lldp_rx, error, fmt, ...)     \
-        log_interface_prefix_full_errno(                \
-                "LLDP Rx: ",                            \
-                sd_lldp_rx, lldp_rx,                    \
-                error, fmt, ##__VA_ARGS__)
-#define log_lldp_rx(lldp_rx, fmt, ...)                  \
-        log_interface_prefix_full_errno_zerook(         \
-                "LLDP Rx: ",                            \
-                sd_lldp_rx, lldp_rx,                    \
-                0, fmt, ##__VA_ARGS__)
diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
index fbe15f00..db159660 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
@@ -213,7 +213,7 @@ static int dhcp6_client_set_duid_internal(
                         if (r < 0)
                                 return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m");
 
-                        log_dhcp6_client(client, "Using DUID of type %u of incorrect length, proceeding.", duid_type);
+                        log_dhcp6_client(client, "Using DUID of type %i of incorrect length, proceeding.", duid_type);
                 }
 
                 client->duid.type = htobe16(duid_type);
@@ -553,13 +553,9 @@ static void client_notify(sd_dhcp6_client *client, int event) {
                 client->callback(client, event, client->userdata);
 }
 
-static void client_stop(sd_dhcp6_client *client, int error) {
-        DHCP6_CLIENT_DONT_DESTROY(client);
-
+static void client_cleanup(sd_dhcp6_client *client) {
         assert(client);
 
-        client_notify(client, error);
-
         client->lease = sd_dhcp6_lease_unref(client->lease);
 
         /* Reset IRT here. Otherwise, we cannot restart the client in the information requesting mode,
@@ -576,10 +572,20 @@ static void client_stop(sd_dhcp6_client *client, int error) {
         client_set_state(client, DHCP6_STATE_STOPPED);
 }
 
+static void client_stop(sd_dhcp6_client *client, int error) {
+        DHCP6_CLIENT_DONT_DESTROY(client);
+
+        assert(client);
+
+        client_notify(client, error);
+
+        client_cleanup(client);
+}
+
 static int client_append_common_options_in_managed_mode(
                 sd_dhcp6_client *client,
-                uint8_t **opt,
-                size_t *optlen,
+                uint8_t **buf,
+                size_t *offset,
                 const DHCP6IA *ia_na,
                 const DHCP6IA *ia_pd) {
 
@@ -591,44 +597,37 @@ static int client_append_common_options_in_managed_mode(
                       DHCP6_STATE_REQUEST,
                       DHCP6_STATE_RENEW,
                       DHCP6_STATE_REBIND));
-        assert(opt);
-        assert(optlen);
+        assert(buf);
+        assert(*buf);
+        assert(offset);
 
         if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA) && ia_na) {
-                r = dhcp6_option_append_ia(opt, optlen, ia_na);
+                r = dhcp6_option_append_ia(buf, offset, ia_na);
                 if (r < 0)
                         return r;
         }
 
         if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD) && ia_pd) {
-                r = dhcp6_option_append_ia(opt, optlen, ia_pd);
+                r = dhcp6_option_append_ia(buf, offset, ia_pd);
                 if (r < 0)
                         return r;
         }
 
-        if (client->fqdn) {
-                r = dhcp6_option_append_fqdn(opt, optlen, client->fqdn);
-                if (r < 0)
-                        return r;
-        }
+        r = dhcp6_option_append_fqdn(buf, offset, client->fqdn);
+        if (r < 0)
+                return r;
 
-        if (client->user_class) {
-                r = dhcp6_option_append_user_class(opt, optlen, client->user_class);
-                if (r < 0)
-                        return r;
-        }
+        r = dhcp6_option_append_user_class(buf, offset, client->user_class);
+        if (r < 0)
+                return r;
 
-        if (client->vendor_class) {
-                r = dhcp6_option_append_vendor_class(opt, optlen, client->vendor_class);
-                if (r < 0)
-                        return r;
-        }
+        r = dhcp6_option_append_vendor_class(buf, offset, client->vendor_class);
+        if (r < 0)
+                return r;
 
-        if (!ordered_set_isempty(client->vendor_options)) {
-                r = dhcp6_option_append_vendor_option(opt, optlen, client->vendor_options);
-                if (r < 0)
-                        return r;
-        }
+        r = dhcp6_option_append_vendor_option(buf, offset, client->vendor_options);
+        if (r < 0)
+                return r;
 
         return 0;
 }
@@ -652,41 +651,42 @@ static DHCP6MessageType client_message_type_from_state(sd_dhcp6_client *client)
         }
 }
 
-static int client_append_oro(sd_dhcp6_client *client, uint8_t **opt, size_t *optlen) {
-        _cleanup_free_ be16_t *buf = NULL;
+static int client_append_oro(sd_dhcp6_client *client, uint8_t **buf, size_t *offset) {
+        _cleanup_free_ be16_t *p = NULL;
         be16_t *req_opts;
         size_t n;
 
         assert(client);
-        assert(opt);
-        assert(optlen);
+        assert(buf);
+        assert(*buf);
+        assert(offset);
 
         switch (client->state) {
         case DHCP6_STATE_INFORMATION_REQUEST:
                 n = client->n_req_opts;
-                buf = new(be16_t, n + 2);
-                if (!buf)
+                p = new(be16_t, n + 2);
+                if (!p)
                         return -ENOMEM;
 
-                memcpy_safe(buf, client->req_opts, n * sizeof(be16_t));
-                buf[n++] = htobe16(SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME); /* RFC 8415 section 21.23 */
-                buf[n++] = htobe16(SD_DHCP6_OPTION_INF_MAX_RT); /* RFC 8415 section 21.25 */
+                memcpy_safe(p, client->req_opts, n * sizeof(be16_t));
+                p[n++] = htobe16(SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME); /* RFC 8415 section 21.23 */
+                p[n++] = htobe16(SD_DHCP6_OPTION_INF_MAX_RT); /* RFC 8415 section 21.25 */
 
-                typesafe_qsort(buf, n, be16_compare_func);
-                req_opts = buf;
+                typesafe_qsort(p, n, be16_compare_func);
+                req_opts = p;
                 break;
 
         case DHCP6_STATE_SOLICITATION:
                 n = client->n_req_opts;
-                buf = new(be16_t, n + 1);
-                if (!buf)
+                p = new(be16_t, n + 1);
+                if (!p)
                         return -ENOMEM;
 
-                memcpy_safe(buf, client->req_opts, n * sizeof(be16_t));
-                buf[n++] = htobe16(SD_DHCP6_OPTION_SOL_MAX_RT); /* RFC 8415 section 21.24 */
+                memcpy_safe(p, client->req_opts, n * sizeof(be16_t));
+                p[n++] = htobe16(SD_DHCP6_OPTION_SOL_MAX_RT); /* RFC 8415 section 21.24 */
 
-                typesafe_qsort(buf, n, be16_compare_func);
-                req_opts = buf;
+                typesafe_qsort(p, n, be16_compare_func);
+                req_opts = p;
                 break;
 
         default:
@@ -694,18 +694,21 @@ static int client_append_oro(sd_dhcp6_client *client, uint8_t **opt, size_t *opt
                 req_opts = client->req_opts;
         }
 
-        return dhcp6_option_append(opt, optlen, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts);
+        if (n == 0)
+                return 0;
+
+        return dhcp6_option_append(buf, offset, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts);
 }
 
 int dhcp6_client_send_message(sd_dhcp6_client *client) {
-        _cleanup_free_ DHCP6Message *message = NULL;
+        _cleanup_free_ uint8_t *buf = NULL;
         struct in6_addr all_servers =
                 IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
         struct sd_dhcp6_option *j;
-        size_t len, optlen = 512;
-        uint8_t *opt;
         usec_t elapsed_usec, time_now;
         be16_t elapsed_time;
+        DHCP6Message *message;
+        size_t offset;
         int r;
 
         assert(client);
@@ -715,16 +718,13 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
         if (r < 0)
                 return r;
 
-        len = sizeof(DHCP6Message) + optlen;
-
-        message = malloc0(len);
-        if (!message)
+        if (!GREEDY_REALLOC0(buf, offsetof(DHCP6Message, options)))
                 return -ENOMEM;
 
-        opt = (uint8_t *)(message + 1);
-
+        message = (DHCP6Message*) buf;
         message->transaction_id = client->transaction_id;
         message->type = client_message_type_from_state(client);
+        offset = offsetof(DHCP6Message, options);
 
         switch (client->state) {
         case DHCP6_STATE_INFORMATION_REQUEST:
@@ -732,12 +732,12 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
 
         case DHCP6_STATE_SOLICITATION:
                 if (client->rapid_commit) {
-                        r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_RAPID_COMMIT, 0, NULL);
+                        r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_RAPID_COMMIT, 0, NULL);
                         if (r < 0)
                                 return r;
                 }
 
-                r = client_append_common_options_in_managed_mode(client, &opt, &optlen,
+                r = client_append_common_options_in_managed_mode(client, &buf, &offset,
                                                                  &client->ia_na, &client->ia_pd);
                 if (r < 0)
                         return r;
@@ -746,7 +746,7 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
         case DHCP6_STATE_REQUEST:
         case DHCP6_STATE_RENEW:
 
-                r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_SERVERID,
+                r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_SERVERID,
                                         client->lease->serverid_len,
                                         client->lease->serverid);
                 if (r < 0)
@@ -757,7 +757,7 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
 
                 assert(client->lease);
 
-                r = client_append_common_options_in_managed_mode(client, &opt, &optlen,
+                r = client_append_common_options_in_managed_mode(client, &buf, &offset,
                                                                  client->lease->ia_na, client->lease->ia_pd);
                 if (r < 0)
                         return r;
@@ -770,24 +770,24 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
         }
 
         if (client->mudurl) {
-                r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_MUD_URL_V6,
+                r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_MUD_URL_V6,
                                         strlen(client->mudurl), client->mudurl);
                 if (r < 0)
                         return r;
         }
 
-        r = client_append_oro(client, &opt, &optlen);
+        r = client_append_oro(client, &buf, &offset);
         if (r < 0)
                 return r;
 
-        assert(client->duid_len);
-        r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_CLIENTID,
+        assert(client->duid_len > 0);
+        r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_CLIENTID,
                                 client->duid_len, &client->duid);
         if (r < 0)
                 return r;
 
         ORDERED_HASHMAP_FOREACH(j, client->extra_options) {
-                r = dhcp6_option_append(&opt, &optlen, j->option, j->length, j->data);
+                r = dhcp6_option_append(&buf, &offset, j->option, j->length, j->data);
                 if (r < 0)
                         return r;
         }
@@ -797,18 +797,16 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
          * been trying to complete a DHCP message exchange. */
         elapsed_usec = MIN(usec_sub_unsigned(time_now, client->transaction_start) / USEC_PER_MSEC / 10, (usec_t) UINT16_MAX);
         elapsed_time = htobe16(elapsed_usec);
-        r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ELAPSED_TIME, sizeof(elapsed_time), &elapsed_time);
+        r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_ELAPSED_TIME, sizeof(elapsed_time), &elapsed_time);
         if (r < 0)
                 return r;
 
-        r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message,
-                                          len - optlen);
+        r = dhcp6_network_send_udp_socket(client->fd, &all_servers, buf, offset);
         if (r < 0)
                 return r;
 
         log_dhcp6_client(client, "Sent %s",
-                         dhcp6_message_type_to_string(message->type));
-
+                         dhcp6_message_type_to_string(client_message_type_from_state(client)));
         return 0;
 }
 
@@ -1143,6 +1141,20 @@ static int client_process_reply(
                 return log_invalid_message_type(client, message);
 
         r = dhcp6_lease_new_from_message(client, message, len, timestamp, server_address, &lease);
+        if (r == -EADDRNOTAVAIL) {
+
+                /* If NoBinding status code is received, we cannot request the address anymore.
+                 * Let's restart transaction from the beginning. */
+
+                if (client->state == DHCP6_STATE_REQUEST)
+                        /* The lease is not acquired yet, hence it is not necessary to notify the restart. */
+                        client_cleanup(client);
+                else
+                        /* We need to notify the previous lease was expired. */
+                        client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE);
+
+                return client_start_transaction(client, DHCP6_STATE_SOLICITATION);
+        }
         if (r < 0)
                 return log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
 
@@ -1291,7 +1303,7 @@ static int client_receive_message(
                 if (cmsg->cmsg_level == SOL_SOCKET &&
                     cmsg->cmsg_type == SO_TIMESTAMP &&
                     cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
-                        triple_timestamp_from_realtime(&t, timeval_load((struct timeval*) CMSG_DATA(cmsg)));
+                        triple_timestamp_from_realtime(&t, timeval_load((struct timeval*) (void *) CMSG_DATA(cmsg)));
         }
 
         if (client->transaction_id != (message->transaction_id & htobe32(0x00ffffff)))
diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c
index 55c7d627..5dcd2eb2 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c
@@ -514,7 +514,7 @@ static int dhcp6_lease_parse_message(
                                 return log_dhcp6_client_errno(client, r, "Failed to parse status code: %m");
 
                         if (r > 0)
-                                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
+                                return log_dhcp6_client_errno(client, dhcp6_message_status_to_errno(r),
                                                               "Received %s message with non-zero status: %s%s%s",
                                                               dhcp6_message_type_to_string(message->type),
                                                               strempty(msg), isempty(msg) ? "" : ": ",
@@ -621,7 +621,7 @@ static int dhcp6_lease_parse_message(
                                 return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
                                                               "Received information refresh time option with an invalid length (%zu).", optlen);
 
-                        irt = unaligned_read_be32((be32_t *) optval) * USEC_PER_SEC;
+                        irt = unaligned_read_be32(optval) * USEC_PER_SEC;
                         break;
                 }
         }
diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c b/src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c
deleted file mode 100644
index 496eb8f6..00000000
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c
+++ /dev/null
@@ -1,528 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-core.h"
-
-#include <arpa/inet.h>
-#include <linux/sockios.h>
-#include <sys/ioctl.h>
-
-#include "sd-lldp-rx.h"
-
-#include "alloc-util.h"
-#include "ether-addr-util.h"
-#include "event-util.h"
-#include "fd-util.h"
-#include "lldp-neighbor.h"
-#include "lldp-network.h"
-#include "lldp-rx-internal.h"
-#include "memory-util.h"
-#include "network-common.h"
-#include "socket-util.h"
-#include "sort-util.h"
-#include "string-table.h"
-
-#define LLDP_DEFAULT_NEIGHBORS_MAX 128U
-
-static const char * const lldp_rx_event_table[_SD_LLDP_RX_EVENT_MAX] = {
-        [SD_LLDP_RX_EVENT_ADDED]     = "added",
-        [SD_LLDP_RX_EVENT_REMOVED]   = "removed",
-        [SD_LLDP_RX_EVENT_UPDATED]   = "updated",
-        [SD_LLDP_RX_EVENT_REFRESHED] = "refreshed",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(lldp_rx_event, sd_lldp_rx_event_t);
-
-static void lldp_rx_flush_neighbors(sd_lldp_rx *lldp_rx) {
-        assert(lldp_rx);
-
-        hashmap_clear(lldp_rx->neighbor_by_id);
-}
-
-static void lldp_rx_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_event_t event, sd_lldp_neighbor *n) {
-        assert(lldp_rx);
-        assert(event >= 0 && event < _SD_LLDP_RX_EVENT_MAX);
-
-        if (!lldp_rx->callback)
-                return (void) log_lldp_rx(lldp_rx, "Received '%s' event.", lldp_rx_event_to_string(event));
-
-        log_lldp_rx(lldp_rx, "Invoking callback for '%s' event.", lldp_rx_event_to_string(event));
-        lldp_rx->callback(lldp_rx, event, n, lldp_rx->userdata);
-}
-
-static int lldp_rx_make_space(sd_lldp_rx *lldp_rx, size_t extra) {
-        usec_t t = USEC_INFINITY;
-        bool changed = false;
-
-        assert(lldp_rx);
-
-        /* Remove all entries that are past their TTL, and more until at least the specified number of extra entries
-         * are free. */
-
-        for (;;) {
-                _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
-
-                n = prioq_peek(lldp_rx->neighbor_by_expiry);
-                if (!n)
-                        break;
-
-                sd_lldp_neighbor_ref(n);
-
-                if (hashmap_size(lldp_rx->neighbor_by_id) > LESS_BY(lldp_rx->neighbors_max, extra))
-                        goto remove_one;
-
-                if (t == USEC_INFINITY)
-                        t = now(CLOCK_BOOTTIME);
-
-                if (n->until > t)
-                        break;
-
-        remove_one:
-                lldp_neighbor_unlink(n);
-                lldp_rx_callback(lldp_rx, SD_LLDP_RX_EVENT_REMOVED, n);
-                changed = true;
-        }
-
-        return changed;
-}
-
-static bool lldp_rx_keep_neighbor(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *n) {
-        assert(lldp_rx);
-        assert(n);
-
-        /* Don't keep data with a zero TTL */
-        if (n->ttl <= 0)
-                return false;
-
-        /* Filter out data from the filter address */
-        if (!ether_addr_is_null(&lldp_rx->filter_address) &&
-            ether_addr_equal(&lldp_rx->filter_address, &n->source_address))
-                return false;
-
-        /* Only add if the neighbor has a capability we are interested in. Note that we also store all neighbors with
-         * no caps field set. */
-        if (n->has_capabilities &&
-            (n->enabled_capabilities & lldp_rx->capability_mask) == 0)
-                return false;
-
-        /* Keep everything else */
-        return true;
-}
-
-static int lldp_rx_start_timer(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *neighbor);
-
-static int lldp_rx_add_neighbor(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *n) {
-        _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *old = NULL;
-        bool keep;
-        int r;
-
-        assert(lldp_rx);
-        assert(n);
-        assert(!n->lldp_rx);
-
-        keep = lldp_rx_keep_neighbor(lldp_rx, n);
-
-        /* First retrieve the old entry for this MSAP */
-        old = hashmap_get(lldp_rx->neighbor_by_id, &n->id);
-        if (old) {
-                sd_lldp_neighbor_ref(old);
-
-                if (!keep) {
-                        lldp_neighbor_unlink(old);
-                        lldp_rx_callback(lldp_rx, SD_LLDP_RX_EVENT_REMOVED, old);
-                        return 0;
-                }
-
-                if (lldp_neighbor_equal(n, old)) {
-                        /* Is this equal, then restart the TTL counter, but don't do anything else. */
-                        old->timestamp = n->timestamp;
-                        lldp_rx_start_timer(lldp_rx, old);
-                        lldp_rx_callback(lldp_rx, SD_LLDP_RX_EVENT_REFRESHED, old);
-                        return 0;
-                }
-
-                /* Data changed, remove the old entry, and add a new one */
-                lldp_neighbor_unlink(old);
-
-        } else if (!keep)
-                return 0;
-
-        /* Then, make room for at least one new neighbor */
-        lldp_rx_make_space(lldp_rx, 1);
-
-        r = hashmap_ensure_put(&lldp_rx->neighbor_by_id, &lldp_neighbor_hash_ops, &n->id, n);
-        if (r < 0)
-                goto finish;
-
-        r = prioq_ensure_put(&lldp_rx->neighbor_by_expiry, lldp_neighbor_prioq_compare_func, n, &n->prioq_idx);
-        if (r < 0) {
-                assert_se(hashmap_remove(lldp_rx->neighbor_by_id, &n->id) == n);
-                goto finish;
-        }
-
-        n->lldp_rx = lldp_rx;
-
-        lldp_rx_start_timer(lldp_rx, n);
-        lldp_rx_callback(lldp_rx, old ? SD_LLDP_RX_EVENT_UPDATED : SD_LLDP_RX_EVENT_ADDED, n);
-
-        return 1;
-
-finish:
-        if (old)
-                lldp_rx_callback(lldp_rx, SD_LLDP_RX_EVENT_REMOVED, old);
-
-        return r;
-}
-
-static int lldp_rx_handle_datagram(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *n) {
-        int r;
-
-        assert(lldp_rx);
-        assert(n);
-
-        r = lldp_neighbor_parse(n);
-        if (r < 0)
-                return r;
-
-        r = lldp_rx_add_neighbor(lldp_rx, n);
-        if (r < 0)
-                return log_lldp_rx_errno(lldp_rx, r, "Failed to add datagram. Ignoring.");
-
-        log_lldp_rx(lldp_rx, "Successfully processed LLDP datagram.");
-        return 0;
-}
-
-static int lldp_rx_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
-        ssize_t space, length;
-        sd_lldp_rx *lldp_rx = userdata;
-        struct timespec ts;
-
-        assert(fd >= 0);
-        assert(lldp_rx);
-
-        space = next_datagram_size_fd(fd);
-        if (space < 0) {
-                if (ERRNO_IS_TRANSIENT(space) || ERRNO_IS_DISCONNECT(space))
-                        return 0;
-
-                log_lldp_rx_errno(lldp_rx, space, "Failed to determine datagram size to read, ignoring: %m");
-                return 0;
-        }
-
-        n = lldp_neighbor_new(space);
-        if (!n) {
-                log_oom_debug();
-                return 0;
-        }
-
-        length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT);
-        if (length < 0) {
-                if (ERRNO_IS_TRANSIENT(errno) || ERRNO_IS_DISCONNECT(errno))
-                        return 0;
-
-                log_lldp_rx_errno(lldp_rx, errno, "Failed to read LLDP datagram, ignoring: %m");
-                return 0;
-        }
-
-        if ((size_t) length != n->raw_size) {
-                log_lldp_rx(lldp_rx, "Packet size mismatch, ignoring");
-                return 0;
-        }
-
-        /* Try to get the timestamp of this packet if it is known */
-        if (ioctl(fd, SIOCGSTAMPNS, &ts) >= 0)
-                triple_timestamp_from_realtime(&n->timestamp, timespec_load(&ts));
-        else
-                triple_timestamp_get(&n->timestamp);
-
-        (void) lldp_rx_handle_datagram(lldp_rx, n);
-        return 0;
-}
-
-static void lldp_rx_reset(sd_lldp_rx *lldp_rx) {
-        assert(lldp_rx);
-
-        (void) event_source_disable(lldp_rx->timer_event_source);
-        lldp_rx->io_event_source = sd_event_source_disable_unref(lldp_rx->io_event_source);
-        lldp_rx->fd = safe_close(lldp_rx->fd);
-}
-
-int sd_lldp_rx_is_running(sd_lldp_rx *lldp_rx) {
-        if (!lldp_rx)
-                return false;
-
-        return lldp_rx->fd >= 0;
-}
-
-int sd_lldp_rx_start(sd_lldp_rx *lldp_rx) {
-        int r;
-
-        assert_return(lldp_rx, -EINVAL);
-        assert_return(lldp_rx->event, -EINVAL);
-        assert_return(lldp_rx->ifindex > 0, -EINVAL);
-
-        if (sd_lldp_rx_is_running(lldp_rx))
-                return 0;
-
-        assert(!lldp_rx->io_event_source);
-
-        lldp_rx->fd = lldp_network_bind_raw_socket(lldp_rx->ifindex);
-        if (lldp_rx->fd < 0)
-                return lldp_rx->fd;
-
-        r = sd_event_add_io(lldp_rx->event, &lldp_rx->io_event_source, lldp_rx->fd, EPOLLIN, lldp_rx_receive_datagram, lldp_rx);
-        if (r < 0)
-                goto fail;
-
-        r = sd_event_source_set_priority(lldp_rx->io_event_source, lldp_rx->event_priority);
-        if (r < 0)
-                goto fail;
-
-        (void) sd_event_source_set_description(lldp_rx->io_event_source, "lldp-rx-io");
-
-        log_lldp_rx(lldp_rx, "Started LLDP client");
-        return 1;
-
-fail:
-        lldp_rx_reset(lldp_rx);
-        return r;
-}
-
-int sd_lldp_rx_stop(sd_lldp_rx *lldp_rx) {
-        if (!sd_lldp_rx_is_running(lldp_rx))
-                return 0;
-
-        log_lldp_rx(lldp_rx, "Stopping LLDP client");
-
-        lldp_rx_reset(lldp_rx);
-        lldp_rx_flush_neighbors(lldp_rx);
-
-        return 1;
-}
-
-int sd_lldp_rx_attach_event(sd_lldp_rx *lldp_rx, sd_event *event, int64_t priority) {
-        int r;
-
-        assert_return(lldp_rx, -EINVAL);
-        assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
-        assert_return(!lldp_rx->event, -EBUSY);
-
-        if (event)
-                lldp_rx->event = sd_event_ref(event);
-        else {
-                r = sd_event_default(&lldp_rx->event);
-                if (r < 0)
-                        return r;
-        }
-
-        lldp_rx->event_priority = priority;
-
-        return 0;
-}
-
-int sd_lldp_rx_detach_event(sd_lldp_rx *lldp_rx) {
-        assert_return(lldp_rx, -EINVAL);
-        assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
-
-        lldp_rx->io_event_source = sd_event_source_disable_unref(lldp_rx->io_event_source);
-        lldp_rx->timer_event_source = sd_event_source_disable_unref(lldp_rx->timer_event_source);
-        lldp_rx->event = sd_event_unref(lldp_rx->event);
-        return 0;
-}
-
-sd_event* sd_lldp_rx_get_event(sd_lldp_rx *lldp_rx) {
-        assert_return(lldp_rx, NULL);
-
-        return lldp_rx->event;
-}
-
-int sd_lldp_rx_set_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_callback_t cb, void *userdata) {
-        assert_return(lldp_rx, -EINVAL);
-
-        lldp_rx->callback = cb;
-        lldp_rx->userdata = userdata;
-
-        return 0;
-}
-
-int sd_lldp_rx_set_ifindex(sd_lldp_rx *lldp_rx, int ifindex) {
-        assert_return(lldp_rx, -EINVAL);
-        assert_return(ifindex > 0, -EINVAL);
-        assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
-
-        lldp_rx->ifindex = ifindex;
-        return 0;
-}
-
-int sd_lldp_rx_set_ifname(sd_lldp_rx *lldp_rx, const char *ifname) {
-        assert_return(lldp_rx, -EINVAL);
-        assert_return(ifname, -EINVAL);
-
-        if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
-                return -EINVAL;
-
-        return free_and_strdup(&lldp_rx->ifname, ifname);
-}
-
-int sd_lldp_rx_get_ifname(sd_lldp_rx *lldp_rx, const char **ret) {
-        int r;
-
-        assert_return(lldp_rx, -EINVAL);
-
-        r = get_ifname(lldp_rx->ifindex, &lldp_rx->ifname);
-        if (r < 0)
-                return r;
-
-        if (ret)
-                *ret = lldp_rx->ifname;
-
-        return 0;
-}
-
-static sd_lldp_rx *lldp_rx_free(sd_lldp_rx *lldp_rx) {
-        if (!lldp_rx)
-                return NULL;
-
-        lldp_rx_reset(lldp_rx);
-
-        sd_lldp_rx_detach_event(lldp_rx);
-
-        lldp_rx_flush_neighbors(lldp_rx);
-
-        hashmap_free(lldp_rx->neighbor_by_id);
-        prioq_free(lldp_rx->neighbor_by_expiry);
-        free(lldp_rx->ifname);
-        return mfree(lldp_rx);
-}
-
-DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_lldp_rx, sd_lldp_rx, lldp_rx_free);
-
-int sd_lldp_rx_new(sd_lldp_rx **ret) {
-        _cleanup_(sd_lldp_rx_unrefp) sd_lldp_rx *lldp_rx = NULL;
-
-        assert_return(ret, -EINVAL);
-
-        lldp_rx = new(sd_lldp_rx, 1);
-        if (!lldp_rx)
-                return -ENOMEM;
-
-        *lldp_rx = (sd_lldp_rx) {
-                .n_ref = 1,
-                .fd = -1,
-                .neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX,
-                .capability_mask = UINT16_MAX,
-        };
-
-        *ret = TAKE_PTR(lldp_rx);
-        return 0;
-}
-
-static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) {
-        sd_lldp_rx *lldp_rx = userdata;
-        int r;
-
-        r = lldp_rx_make_space(lldp_rx, 0);
-        if (r < 0) {
-                log_lldp_rx_errno(lldp_rx, r, "Failed to make space, ignoring: %m");
-                return 0;
-        }
-
-        r = lldp_rx_start_timer(lldp_rx, NULL);
-        if (r < 0) {
-                log_lldp_rx_errno(lldp_rx, r, "Failed to restart timer, ignoring: %m");
-                return 0;
-        }
-
-        return 0;
-}
-
-static int lldp_rx_start_timer(sd_lldp_rx *lldp_rx, sd_lldp_neighbor *neighbor) {
-        sd_lldp_neighbor *n;
-
-        assert(lldp_rx);
-        assert(lldp_rx->event);
-
-        if (neighbor)
-                lldp_neighbor_start_ttl(neighbor);
-
-        n = prioq_peek(lldp_rx->neighbor_by_expiry);
-        if (!n)
-                return event_source_disable(lldp_rx->timer_event_source);
-
-        return event_reset_time(lldp_rx->event, &lldp_rx->timer_event_source,
-                                CLOCK_BOOTTIME,
-                                n->until, 0,
-                                on_timer_event, lldp_rx,
-                                lldp_rx->event_priority, "lldp-rx-timer", true);
-}
-
-static inline int neighbor_compare_func(sd_lldp_neighbor * const *a, sd_lldp_neighbor * const *b) {
-        assert(a);
-        assert(b);
-        assert(*a);
-        assert(*b);
-
-        return lldp_neighbor_id_compare_func(&(*a)->id, &(*b)->id);
-}
-
-int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***ret) {
-        _cleanup_free_ sd_lldp_neighbor **l = NULL;
-        sd_lldp_neighbor *n;
-        int k = 0;
-
-        assert_return(lldp_rx, -EINVAL);
-        assert_return(ret, -EINVAL);
-
-        if (hashmap_isempty(lldp_rx->neighbor_by_id)) { /* Special shortcut */
-                *ret = NULL;
-                return 0;
-        }
-
-        l = new0(sd_lldp_neighbor*, hashmap_size(lldp_rx->neighbor_by_id));
-        if (!l)
-                return -ENOMEM;
-
-        HASHMAP_FOREACH(n, lldp_rx->neighbor_by_id)
-                l[k++] = sd_lldp_neighbor_ref(n);
-
-        assert((size_t) k == hashmap_size(lldp_rx->neighbor_by_id));
-
-        /* Return things in a stable order */
-        typesafe_qsort(l, k, neighbor_compare_func);
-        *ret = TAKE_PTR(l);
-
-        return k;
-}
-
-int sd_lldp_rx_set_neighbors_max(sd_lldp_rx *lldp_rx, uint64_t m) {
-        assert_return(lldp_rx, -EINVAL);
-        assert_return(m > 0, -EINVAL);
-
-        lldp_rx->neighbors_max = m;
-        lldp_rx_make_space(lldp_rx, 0);
-
-        return 0;
-}
-
-int sd_lldp_rx_match_capabilities(sd_lldp_rx *lldp_rx, uint16_t mask) {
-        assert_return(lldp_rx, -EINVAL);
-        assert_return(mask != 0, -EINVAL);
-
-        lldp_rx->capability_mask = mask;
-
-        return 0;
-}
-
-int sd_lldp_rx_set_filter_address(sd_lldp_rx *lldp_rx, const struct ether_addr *addr) {
-        assert_return(lldp_rx, -EINVAL);
-
-        /* In order to deal nicely with bridges that send back our own packets, allow one address to be filtered, so
-         * that our own can be filtered out here. */
-
-        if (addr)
-                lldp_rx->filter_address = *addr;
-        else
-                zero(lldp_rx->filter_address);
-
-        return 0;
-}
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h b/src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h
index 74cbc269..6092652d 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h
+++ b/src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h
@@ -99,6 +99,7 @@ struct sd_event_source {
                         sd_event_signal_handler_t callback;
                         struct signalfd_siginfo siginfo;
                         int sig;
+                        bool unblock;
                 } signal;
                 struct {
                         sd_event_child_handler_t callback;
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
index 8b2c554c..70776077 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
@@ -155,6 +155,8 @@ struct sd_event {
 
         LIST_HEAD(sd_event_source, sources);
 
+        sd_event_source *sigint_event_source, *sigterm_event_source;
+
         usec_t last_run_usec, last_log_usec;
         unsigned delays[sizeof(usec_t) * 8];
 };
@@ -325,6 +327,9 @@ static sd_event *event_free(sd_event *e) {
 
         assert(e);
 
+        e->sigterm_event_source = sd_event_source_unref(e->sigterm_event_source);
+        e->sigint_event_source = sd_event_source_unref(e->sigint_event_source);
+
         while ((s = e->sources)) {
                 assert(s->floating);
                 source_disconnect(s);
@@ -815,6 +820,7 @@ static void event_source_time_prioq_remove(
 
 static void source_disconnect(sd_event_source *s) {
         sd_event *event;
+        int r;
 
         assert(s);
 
@@ -855,6 +861,20 @@ static void source_disconnect(sd_event_source *s) {
                                 s->event->signal_sources[s->signal.sig] = NULL;
 
                         event_gc_signal_data(s->event, &s->priority, s->signal.sig);
+
+                        if (s->signal.unblock) {
+                                sigset_t new_ss;
+
+                                if (sigemptyset(&new_ss) < 0)
+                                        log_debug_errno(errno, "Failed to reset signal set, ignoring: %m");
+                                else if (sigaddset(&new_ss, s->signal.sig) < 0)
+                                        log_debug_errno(errno, "Failed to add signal %i to signal mask, ignoring: %m", s->signal.sig);
+                                else {
+                                        r = pthread_sigmask(SIG_UNBLOCK, &new_ss, NULL);
+                                        if (r != 0)
+                                                log_debug_errno(r, "Failed to unblock signal %i, ignoring: %m", s->signal.sig);
+                                }
+                        }
                 }
 
                 break;
@@ -1331,23 +1351,38 @@ _public_ int sd_event_add_signal(
 
         _cleanup_(source_freep) sd_event_source *s = NULL;
         struct signal_data *d;
+        sigset_t new_ss;
+        bool block_it;
         int r;
 
         assert_return(e, -EINVAL);
         assert_return(e = event_resolve(e), -ENOPKG);
-        assert_return(SIGNAL_VALID(sig), -EINVAL);
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
+        /* Let's make sure our special flag stays outside of the valid signal range */
+        assert_cc(_NSIG < SD_EVENT_SIGNAL_PROCMASK);
+
+        if (sig & SD_EVENT_SIGNAL_PROCMASK) {
+                sig &= ~SD_EVENT_SIGNAL_PROCMASK;
+                assert_return(SIGNAL_VALID(sig), -EINVAL);
+
+                block_it = true;
+        } else {
+                assert_return(SIGNAL_VALID(sig), -EINVAL);
+
+                r = signal_is_blocked(sig);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return -EBUSY;
+
+                block_it = false;
+        }
+
         if (!callback)
                 callback = signal_exit_callback;
 
-        r = signal_is_blocked(sig);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                return -EBUSY;
-
         if (!e->signal_sources) {
                 e->signal_sources = new0(sd_event_source*, _NSIG);
                 if (!e->signal_sources)
@@ -1366,9 +1401,34 @@ _public_ int sd_event_add_signal(
 
         e->signal_sources[sig] = s;
 
+        if (block_it) {
+                sigset_t old_ss;
+
+                if (sigemptyset(&new_ss) < 0)
+                        return -errno;
+
+                if (sigaddset(&new_ss, sig) < 0)
+                        return -errno;
+
+                r = pthread_sigmask(SIG_BLOCK, &new_ss, &old_ss);
+                if (r != 0)
+                        return -r;
+
+                r = sigismember(&old_ss, sig);
+                if (r < 0)
+                        return -errno;
+
+                s->signal.unblock = !r;
+        } else
+                s->signal.unblock = false;
+
         r = event_make_signal_data(e, sig, &d);
-        if (r < 0)
+        if (r < 0) {
+                if (s->signal.unblock)
+                        (void) pthread_sigmask(SIG_UNBLOCK, &new_ss, NULL);
+
                 return r;
+        }
 
         /* Use the signal name as description for the event source by default */
         (void) sd_event_source_set_description(s, signal_to_string(sig));
@@ -3827,7 +3887,7 @@ static void event_close_inode_data_fds(sd_event *e) {
 
         /* Close the fds pointing to the inodes to watch now. We need to close them as they might otherwise pin
          * filesystems. But we can't close them right-away as we need them as long as the user still wants to make
-         * adjustments to the even source, such as changing the priority (which requires us to remove and re-add a watch
+         * adjustments to the event source, such as changing the priority (which requires us to remove and re-add a watch
          * for the inode). Hence, let's close them when entering the first iteration after they were added, as a
          * compromise. */
 
@@ -4538,8 +4598,8 @@ _public_ int sd_event_source_set_ratelimit_expire_callback(sd_event_source *s, s
 _public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) {
         assert_return(s, -EINVAL);
 
-        /* Querying whether an event source has ratelimiting configured is not a loggable offsense, hence
-         * don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error */
+        /* Querying whether an event source has ratelimiting configured is not a loggable offense, hence
+         * don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error. */
         if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type))
                 return -EDOM;
 
@@ -4565,4 +4625,56 @@ _public_ int sd_event_source_is_ratelimited(sd_event_source *s) {
 
         return s->ratelimited;
 }
+
+_public_ int sd_event_set_signal_exit(sd_event *e, int b) {
+        bool change = false;
+        int r;
+
+        assert_return(e, -EINVAL);
+
+        if (b) {
+                /* We want to maintain pointers to these event sources, so that we can destroy them when told
+                 * so. But we also don't want them to pin the event loop itself. Hence we mark them as
+                 * floating after creation (and undo this before deleting them again). */
+
+                if (!e->sigint_event_source) {
+                        r = sd_event_add_signal(e, &e->sigint_event_source, SIGINT | SD_EVENT_SIGNAL_PROCMASK, NULL, NULL);
+                        if (r < 0)
+                                return r;
+
+                        assert(sd_event_source_set_floating(e->sigint_event_source, true) >= 0);
+                        change = true;
+                }
+
+                if (!e->sigterm_event_source) {
+                        r = sd_event_add_signal(e, &e->sigterm_event_source, SIGTERM | SD_EVENT_SIGNAL_PROCMASK, NULL, NULL);
+                        if (r < 0) {
+                                if (change) {
+                                        assert(sd_event_source_set_floating(e->sigint_event_source, false) >= 0);
+                                        e->sigint_event_source = sd_event_source_unref(e->sigint_event_source);
+                                }
+
+                                return r;
+                        }
+
+                        assert(sd_event_source_set_floating(e->sigterm_event_source, true) >= 0);
+                        change = true;
+                }
+
+        } else {
+                if (e->sigint_event_source) {
+                        assert(sd_event_source_set_floating(e->sigint_event_source, false) >= 0);
+                        e->sigint_event_source = sd_event_source_unref(e->sigint_event_source);
+                        change = true;
+                }
+
+                if (e->sigterm_event_source) {
+                        assert(sd_event_source_set_floating(e->sigterm_event_source, false) >= 0);
+                        e->sigterm_event_source = sd_event_source_unref(e->sigterm_event_source);
+                        change = true;
+                }
+        }
+
+        return change;
+}
 #endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-core/src/systemd/sd-event.h b/src/libnm-systemd-core/src/systemd/sd-event.h
index e782339c..cae4c867 100644
--- a/src/libnm-systemd-core/src/systemd/sd-event.h
+++ b/src/libnm-systemd-core/src/systemd/sd-event.h
@@ -68,6 +68,8 @@ enum {
         SD_EVENT_PRIORITY_IDLE = 100
 };
 
+#define SD_EVENT_SIGNAL_PROCMASK (1 << 30)
+
 typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata);
 typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata);
 typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata);
@@ -114,6 +116,7 @@ int sd_event_get_exit_code(sd_event *e, int *code);
 int sd_event_set_watchdog(sd_event *e, int b);
 int sd_event_get_watchdog(sd_event *e);
 int sd_event_get_iteration(sd_event *e, uint64_t *ret);
+int sd_event_set_signal_exit(sd_event *e, int b);
 
 sd_event_source* sd_event_source_ref(sd_event_source *s);
 sd_event_source* sd_event_source_unref(sd_event_source *s);
diff --git a/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h b/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h
deleted file mode 100644
index 504d7f59..00000000
--- a/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#ifndef foosdlldprxhfoo
-#define foosdlldprxhfoo
-
-/***
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <https://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <inttypes.h>
-#include <net/ethernet.h>
-#include <sys/types.h>
-
-#include "sd-event.h"
-#include "sd-lldp.h"
-
-#include "_sd-common.h"
-
-_SD_BEGIN_DECLARATIONS;
-
-typedef struct sd_lldp_rx sd_lldp_rx;
-typedef struct sd_lldp_neighbor sd_lldp_neighbor;
-
-__extension__ typedef enum sd_lldp_rx_event_t {
-        SD_LLDP_RX_EVENT_ADDED,
-        SD_LLDP_RX_EVENT_REMOVED,
-        SD_LLDP_RX_EVENT_UPDATED,
-        SD_LLDP_RX_EVENT_REFRESHED,
-        _SD_LLDP_RX_EVENT_MAX,
-        _SD_LLDP_RX_EVENT_INVALID = -EINVAL,
-        _SD_ENUM_FORCE_S64(LLDP_RX_EVENT)
-} sd_lldp_rx_event_t;
-
-typedef void (*sd_lldp_rx_callback_t)(sd_lldp_rx *lldp_rx, sd_lldp_rx_event_t event, sd_lldp_neighbor *n, void *userdata);
-
-int sd_lldp_rx_new(sd_lldp_rx **ret);
-sd_lldp_rx *sd_lldp_rx_ref(sd_lldp_rx *lldp_rx);
-sd_lldp_rx *sd_lldp_rx_unref(sd_lldp_rx *lldp_rx);
-
-int sd_lldp_rx_start(sd_lldp_rx *lldp_rx);
-int sd_lldp_rx_stop(sd_lldp_rx *lldp_rx);
-int sd_lldp_rx_is_running(sd_lldp_rx *lldp_rx);
-
-int sd_lldp_rx_attach_event(sd_lldp_rx *lldp_rx, sd_event *event, int64_t priority);
-int sd_lldp_rx_detach_event(sd_lldp_rx *lldp_rx);
-sd_event *sd_lldp_rx_get_event(sd_lldp_rx *lldp_rx);
-
-int sd_lldp_rx_set_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_callback_t cb, void *userdata);
-int sd_lldp_rx_set_ifindex(sd_lldp_rx *lldp_rx, int ifindex);
-int sd_lldp_rx_set_ifname(sd_lldp_rx *lldp_rx, const char *ifname);
-int sd_lldp_rx_get_ifname(sd_lldp_rx *lldp_rx, const char **ret);
-
-/* Controls how much and what to store in the neighbors database */
-int sd_lldp_rx_set_neighbors_max(sd_lldp_rx *lldp_rx, uint64_t n);
-int sd_lldp_rx_match_capabilities(sd_lldp_rx *lldp_rx, uint16_t mask);
-int sd_lldp_rx_set_filter_address(sd_lldp_rx *lldp_rx, const struct ether_addr *address);
-
-int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***neighbors);
-
-int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size);
-sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n);
-sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n);
-
-/* Access to LLDP frame metadata */
-int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address);
-int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address);
-int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret);
-int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size);
-
-/* High-level, direct, parsed out field access. These fields exist at most once, hence may be queried directly. */
-int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size);
-int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret);
-int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size);
-int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret);
-int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec);
-int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret);
-int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret);
-int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret);
-int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret);
-int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret);
-int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret);
-
-/* Low-level, iterative TLV access. This is for everything else, it iteratively goes through all available TLVs
- * (including the ones covered with the calls above), and allows multiple TLVs for the same fields. */
-int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n);
-int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n);
-int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type);
-int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type);
-int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t *subtype);
-int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t subtype);
-int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size);
-
-_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_rx, sd_lldp_rx_unref);
-_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_neighbor, sd_lldp_neighbor_unref);
-
-_SD_END_DECLARATIONS;
-
-#endif
diff --git a/src/libnm-systemd-core/src/systemd/sd-lldp.h b/src/libnm-systemd-core/src/systemd/sd-lldp.h
deleted file mode 100644
index 4069c5b2..00000000
--- a/src/libnm-systemd-core/src/systemd/sd-lldp.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#ifndef foosdlldphfoo
-#define foosdlldphfoo
-
-/***
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <https://www.gnu.org/licenses/>.
-***/
-
-#include <inttypes.h>
-
-#include "_sd-common.h"
-
-_SD_BEGIN_DECLARATIONS;
-
-/* IEEE 802.1AB-2009 Clause 8: TLV Types */
-enum {
-        SD_LLDP_TYPE_END                 = 0,
-        SD_LLDP_TYPE_CHASSIS_ID          = 1,
-        SD_LLDP_TYPE_PORT_ID             = 2,
-        SD_LLDP_TYPE_TTL                 = 3,
-        SD_LLDP_TYPE_PORT_DESCRIPTION    = 4,
-        SD_LLDP_TYPE_SYSTEM_NAME         = 5,
-        SD_LLDP_TYPE_SYSTEM_DESCRIPTION  = 6,
-        SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7,
-        SD_LLDP_TYPE_MGMT_ADDRESS        = 8,
-        SD_LLDP_TYPE_PRIVATE             = 127
-};
-
-/* IEEE 802.1AB-2009 Clause 8.5.2: Chassis subtypes */
-enum {
-        SD_LLDP_CHASSIS_SUBTYPE_RESERVED            = 0,
-        SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT   = 1,
-        SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS     = 2,
-        SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT      = 3,
-        SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS         = 4,
-        SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS     = 5,
-        SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME      = 6,
-        SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED    = 7
-};
-
-/* IEEE 802.1AB-2009 Clause 8.5.3: Port subtype */
-enum {
-        SD_LLDP_PORT_SUBTYPE_RESERVED         = 0,
-        SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS  = 1,
-        SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT   = 2,
-        SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS      = 3,
-        SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS  = 4,
-        SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME   = 5,
-        SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6,
-        SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7
-};
-
-/* IEEE 802.1AB-2009 Clause 8.5.8: System capabilities */
-enum {
-        SD_LLDP_SYSTEM_CAPABILITIES_OTHER    = 1 << 0,
-        SD_LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1,
-        SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE   = 1 << 2,
-        SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP  = 1 << 3,
-        SD_LLDP_SYSTEM_CAPABILITIES_ROUTER   = 1 << 4,
-        SD_LLDP_SYSTEM_CAPABILITIES_PHONE    = 1 << 5,
-        SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS   = 1 << 6,
-        SD_LLDP_SYSTEM_CAPABILITIES_STATION  = 1 << 7,
-        SD_LLDP_SYSTEM_CAPABILITIES_CVLAN    = 1 << 8,
-        SD_LLDP_SYSTEM_CAPABILITIES_SVLAN    = 1 << 9,
-        SD_LLDP_SYSTEM_CAPABILITIES_TPMR     = 1 << 10
-};
-
-#define SD_LLDP_SYSTEM_CAPABILITIES_ALL UINT16_MAX
-
-#define SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS                         \
-        ((uint16_t)                                                     \
-         (SD_LLDP_SYSTEM_CAPABILITIES_REPEATER |                        \
-          SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE |                          \
-          SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP |                         \
-          SD_LLDP_SYSTEM_CAPABILITIES_ROUTER |                          \
-          SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS |                          \
-          SD_LLDP_SYSTEM_CAPABILITIES_CVLAN |                           \
-          SD_LLDP_SYSTEM_CAPABILITIES_SVLAN |                           \
-          SD_LLDP_SYSTEM_CAPABILITIES_TPMR))
-
-#define SD_LLDP_OUI_802_1 (const uint8_t[]) { 0x00, 0x80, 0xc2 }
-#define SD_LLDP_OUI_802_3 (const uint8_t[]) { 0x00, 0x12, 0x0f }
-
-#define _SD_LLDP_OUI_IANA 0x00, 0x00, 0x5E
-#define SD_LLDP_OUI_IANA  (const uint8_t[]) { _SD_LLDP_OUI_IANA }
-
-#define SD_LLDP_OUI_IANA_SUBTYPE_MUD  0x01
-#define SD_LLDP_OUI_IANA_MUD                                            \
-        (const uint8_t[]) { _SD_LLDP_OUI_IANA, SD_LLDP_OUI_IANA_SUBTYPE_MUD }
-
-/* IEEE 802.1AB-2009 Annex E */
-enum {
-        SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID          = 1,
-        SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2,
-        SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME             = 3,
-        SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY     = 4,
-        SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST      = 5,
-        SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID        = 6,
-        SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION      = 7
-};
-
-/* IEEE 802.1AB-2009 Annex F */
-enum {
-        SD_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS = 1,
-        SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI         = 2,
-        SD_LLDP_OUI_802_3_SUBTYPE_LINK_AGGREGATION      = 3,
-        SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE    = 4
-};
-
-_SD_END_DECLARATIONS;
-
-#endif