summary refs log tree commit diff
path: root/src/systemd
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2020-04-11 21:28:04 +0200
committerMichael Biebl <biebl@debian.org>2020-04-11 21:28:04 +0200
commit1e5977b62f896e844b548c3007ace9e1dfa7f9ed (patch)
tree7a7416ed410e72b6200f3d860fd315ec11cc106b /src/systemd
parentb012fa6e1d808e0736c009799c62d835cbfcc1dd (diff)
New upstream version 1.23.90 upstream/1.23.90
Diffstat (limited to 'src/systemd')
-rw-r--r--src/systemd/meson.build2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-lease-internal.h6
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.c55
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.h7
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-client.c120
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-lease.c58
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp6-client.c63
-rw-r--r--src/systemd/src/libsystemd-network/sd-ipv4acd.c6
-rw-r--r--src/systemd/src/libsystemd-network/sd-ipv4ll.c2
-rw-r--r--src/systemd/src/libsystemd/sd-event/event-source.h8
-rw-r--r--src/systemd/src/libsystemd/sd-event/sd-event.c531
-rw-r--r--src/systemd/src/libsystemd/sd-id128/id128-util.c15
-rw-r--r--src/systemd/src/libsystemd/sd-id128/id128-util.h6
-rw-r--r--src/systemd/src/libsystemd/sd-id128/sd-id128.c17
-rw-r--r--src/systemd/src/systemd/_sd-common.h12
-rw-r--r--src/systemd/src/systemd/sd-dhcp-client.h10
-rw-r--r--src/systemd/src/systemd/sd-dhcp-lease.h2
-rw-r--r--src/systemd/src/systemd/sd-dhcp6-client.h4
-rw-r--r--src/systemd/src/systemd/sd-event.h12
-rw-r--r--src/systemd/src/systemd/sd-ipv4acd.h3
20 files changed, 820 insertions, 119 deletions
diff --git a/src/systemd/meson.build b/src/systemd/meson.build
index 5c4fa3e2..9b87d772 100644
--- a/src/systemd/meson.build
+++ b/src/systemd/meson.build
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: LGPL-2.1+
+
 sources = files(
   'src/libsystemd-network/arp-util.c',
   'src/libsystemd-network/dhcp-identifier.c',
diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
index a2d0f8bd..5cbebb4a 100644
--- a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
+++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
@@ -61,6 +61,12 @@ struct sd_dhcp_lease {
         struct in_addr *sip;
         size_t sip_size;
 
+        struct in_addr *pop3_server;
+        size_t pop3_server_size;
+
+        struct in_addr *smtp_server;
+        size_t smtp_server_size;
+
         struct sd_dhcp_route *static_route;
         size_t static_route_size, static_route_allocated;
 
diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c
index 7d22e754..94a6236a 100644
--- a/src/systemd/src/libsystemd-network/network-internal.c
+++ b/src/systemd/src/libsystemd-network/network-internal.c
@@ -10,6 +10,7 @@
 #include "sd-ndisc.h"
 
 #include "alloc-util.h"
+#include "arphrd-list.h"
 #include "condition.h"
 #include "conf-parser.h"
 #include "device-util.h"
@@ -106,6 +107,18 @@ static bool net_condition_test_strv(char * const *patterns, const char *string)
         return has_positive_rule ? match : true;
 }
 
+static bool net_condition_test_ifname(char * const *patterns, const char *ifname, char * const *alternative_names) {
+        if (net_condition_test_strv(patterns, ifname))
+                return true;
+
+        char * const *p;
+        STRV_FOREACH(p, alternative_names)
+                if (net_condition_test_strv(patterns, *p))
+                        return true;
+
+        return false;
+}
+
 static int net_condition_test_property(char * const *match_property, sd_device *device) {
         char * const *p;
 
@@ -157,7 +170,29 @@ static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = {
 
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype);
 
+char *link_get_type_string(unsigned short iftype, sd_device *device) {
+        const char *t, *devtype;
+        char *p;
+
+        if (device &&
+            sd_device_get_devtype(device, &devtype) >= 0 &&
+            !isempty(devtype))
+                return strdup(devtype);
+
+        t = arphrd_to_name(iftype);
+        if (!t)
+                return NULL;
+
+        p = strdup(t);
+        if (!p)
+                return NULL;
+
+        ascii_strlower(p);
+        return p;
+}
+
 bool net_match_config(Set *match_mac,
+                      Set *match_permanent_mac,
                       char * const *match_paths,
                       char * const *match_drivers,
                       char * const *match_types,
@@ -166,20 +201,24 @@ bool net_match_config(Set *match_mac,
                       char * const *match_wifi_iftype,
                       char * const *match_ssid,
                       Set *match_bssid,
+                      unsigned short iftype,
                       sd_device *device,
                       const struct ether_addr *dev_mac,
+                      const struct ether_addr *dev_permanent_mac,
                       const char *dev_name,
+                      char * const *alternative_names,
                       enum nl80211_iftype wifi_iftype,
                       const char *ssid,
                       const struct ether_addr *bssid) {
 
-        const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str;
+        const char *dev_path = NULL, *dev_driver = NULL, *mac_str;
+        _cleanup_free_ char *dev_type;
+
+        dev_type = link_get_type_string(iftype, device);
 
         if (device) {
                 (void) sd_device_get_property_value(device, "ID_PATH", &dev_path);
                 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver);
-                (void) sd_device_get_devtype(device, &dev_type);
-
                 if (!dev_name)
                         (void) sd_device_get_sysname(device, &dev_name);
                 if (!dev_mac &&
@@ -190,6 +229,12 @@ bool net_match_config(Set *match_mac,
         if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
                 return false;
 
+        if (match_permanent_mac &&
+            (!dev_permanent_mac ||
+             ether_addr_is_null(dev_permanent_mac) ||
+             !set_contains(match_permanent_mac, dev_permanent_mac)))
+                return false;
+
         if (!net_condition_test_strv(match_paths, dev_path))
                 return false;
 
@@ -199,7 +244,7 @@ bool net_match_config(Set *match_mac,
         if (!net_condition_test_strv(match_types, dev_type))
                 return false;
 
-        if (!net_condition_test_strv(match_names, dev_name))
+        if (!net_condition_test_ifname(match_names, dev_name, alternative_names))
                 return false;
 
         if (!net_condition_test_property(match_property, device))
@@ -352,7 +397,7 @@ int config_parse_match_ifnames(
                         return 0;
                 }
 
-                if (!ifname_valid(word)) {
+                if (!ifname_valid_full(word, ltype)) {
                         log_syntax(unit, LOG_ERR, filename, line, 0,
                                    "Interface name is not valid or too long, ignoring assignment: %s", word);
                         continue;
diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h
index 2eb0cba5..6724cbbf 100644
--- a/src/systemd/src/libsystemd-network/network-internal.h
+++ b/src/systemd/src/libsystemd-network/network-internal.h
@@ -8,7 +8,6 @@
 #include "sd-dhcp-lease.h"
 
 #include "conf-parser.h"
-#include "def.h"
 #include "set.h"
 #include "strv.h"
 
@@ -17,6 +16,7 @@
 
 #if 0 /* NM_IGNORED */
 bool net_match_config(Set *match_mac,
+                      Set *match_permanent_mac,
                       char * const *match_path,
                       char * const *match_driver,
                       char * const *match_type,
@@ -25,9 +25,12 @@ bool net_match_config(Set *match_mac,
                       char * const *match_wifi_iftype,
                       char * const *match_ssid,
                       Set *match_bssid,
+                      unsigned short iftype,
                       sd_device *device,
                       const struct ether_addr *dev_mac,
+                      const struct ether_addr *dev_permanent_mac,
                       const char *dev_name,
+                      char * const *alternative_names,
                       enum nl80211_iftype wifi_iftype,
                       const char *ssid,
                       const struct ether_addr *bssid);
@@ -63,5 +66,3 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t
 
 /* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */
 int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size);
-
-#define NETWORK_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/network"))
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
index 0266161d..63321cca 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
@@ -29,6 +29,7 @@
 #include "random-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "web-util.h"
 
 #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN)  /* Arbitrary limit */
 #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
@@ -85,13 +86,15 @@ struct sd_dhcp_client {
         size_t client_id_len;
         char *hostname;
         char *vendor_class_identifier;
+        char *mudurl;
         char **user_class;
         uint32_t mtu;
         uint32_t xid;
         usec_t start_time;
         uint64_t attempt;
         uint64_t max_attempts;
-        OrderedHashmap *options;
+        OrderedHashmap *extra_options;
+        OrderedHashmap *vendor_options;
         usec_t request_sent;
         sd_event_source *timeout_t1;
         sd_event_source *timeout_t2;
@@ -497,6 +500,18 @@ int sd_dhcp_client_set_vendor_class_identifier(
         return free_and_strdup(&client->vendor_class_identifier, vci);
 }
 
+int sd_dhcp_client_set_mud_url(
+                sd_dhcp_client *client,
+                const char *mudurl) {
+
+        assert_return(client, -EINVAL);
+        assert_return(mudurl, -EINVAL);
+        assert_return(strlen(mudurl) <= 255, -EINVAL);
+        assert_return(http_url_is_valid(mudurl), -EINVAL);
+
+        return free_and_strdup(&client->mudurl, mudurl);
+}
+
 int sd_dhcp_client_set_user_class(
                 sd_dhcp_client *client,
                 const char* const* user_class) {
@@ -545,17 +560,17 @@ int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempt
         return 0;
 }
 
-int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v) {
+int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v) {
         int r;
 
         assert_return(client, -EINVAL);
         assert_return(v, -EINVAL);
 
-        r = ordered_hashmap_ensure_allocated(&client->options, &dhcp_option_hash_ops);
+        r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp_option_hash_ops);
         if (r < 0)
                 return r;
 
-        r = ordered_hashmap_put(client->options, UINT_TO_PTR(v->option), v);
+        r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v);
         if (r < 0)
                 return r;
 
@@ -563,6 +578,25 @@ int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v) {
         return 0;
 }
 
+int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v) {
+        int r;
+
+        assert_return(client, -EINVAL);
+        assert_return(v, -EINVAL);
+
+        r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp_option_hash_ops);
+        if (r < 0)
+                return -ENOMEM;
+
+        r = ordered_hashmap_put(client->vendor_options, v, v);
+        if (r < 0)
+                return r;
+
+        sd_dhcp_option_ref(v);
+
+        return 1;
+}
+
 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
         assert_return(client, -EINVAL);
 
@@ -648,7 +682,7 @@ static int client_message_init(
         assert(ret);
         assert(_optlen);
         assert(_optoffset);
-        assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE));
+        assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE, DHCP_DECLINE));
 
         optlen = DHCP_MIN_OPTIONS_SIZE;
         size = sizeof(DHCPPacket) + optlen;
@@ -880,6 +914,15 @@ static int client_send_discover(sd_dhcp_client *client) {
                         return r;
         }
 
+        if (client->mudurl) {
+                r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+                                       SD_DHCP_OPTION_MUD_URL,
+                                       strlen(client->mudurl),
+                                       client->mudurl);
+                if (r < 0)
+                        return r;
+        }
+
         if (client->user_class) {
                 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
                                        SD_DHCP_OPTION_USER_CLASS,
@@ -889,13 +932,22 @@ static int client_send_discover(sd_dhcp_client *client) {
                         return r;
         }
 
-        ORDERED_HASHMAP_FOREACH(j, client->options, i) {
+        ORDERED_HASHMAP_FOREACH(j, client->extra_options, i) {
                 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
                                        j->option, j->length, j->data);
                 if (r < 0)
                         return r;
         }
 
+        if (!ordered_hashmap_isempty(client->vendor_options)) {
+                r = dhcp_option_append(
+                                &discover->dhcp, optlen, &optoffset, 0,
+                                SD_DHCP_OPTION_VENDOR_SPECIFIC,
+                                ordered_hashmap_size(client->vendor_options), client->vendor_options);
+                if (r < 0)
+                        return r;
+        }
+
         r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
                                SD_DHCP_OPTION_END, 0, NULL);
         if (r < 0)
@@ -1008,6 +1060,16 @@ static int client_send_request(sd_dhcp_client *client) {
                         return r;
         }
 
+        if (client->mudurl) {
+                r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
+                                       SD_DHCP_OPTION_MUD_URL,
+                                       strlen(client->mudurl),
+                                       client->mudurl);
+                if (r < 0)
+                        return r;
+        }
+
+
         r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
                                SD_DHCP_OPTION_END, 0, NULL);
         if (r < 0)
@@ -1971,6 +2033,48 @@ int sd_dhcp_client_send_release(sd_dhcp_client *client) {
         return 0;
 }
 
+int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
+        assert_return(client, -EINVAL);
+        assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE);
+        assert_return(client->lease, -EUNATCH);
+
+        _cleanup_free_ DHCPPacket *release = NULL;
+        size_t optoffset, optlen;
+        int r;
+
+        r = client_message_init(client, &release, DHCP_DECLINE, &optlen, &optoffset);
+        if (r < 0)
+                return r;
+
+        release->dhcp.ciaddr = client->lease->address;
+        memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
+
+        r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
+                               SD_DHCP_OPTION_END, 0, NULL);
+        if (r < 0)
+                return r;
+
+        r = dhcp_network_send_udp_socket(client->fd,
+                                         client->lease->server_address,
+                                         DHCP_PORT_SERVER,
+                                         &release->dhcp,
+                                         sizeof(DHCPMessage) + optoffset);
+        if (r < 0)
+                return r;
+
+        log_dhcp_client(client, "DECLINE");
+
+        client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
+
+        if (client->state != DHCP_STATE_STOPPED) {
+                r = sd_dhcp_client_start(client);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
 int sd_dhcp_client_stop(sd_dhcp_client *client) {
         DHCP_CLIENT_DONT_DESTROY(client);
 
@@ -2035,8 +2139,10 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
         free(client->req_opts);
         free(client->hostname);
         free(client->vendor_class_identifier);
+        free(client->mudurl);
         client->user_class = strv_free(client->user_class);
-        ordered_hashmap_free(client->options);
+        ordered_hashmap_free(client->extra_options);
+        ordered_hashmap_free(client->vendor_options);
         return mfree(client);
 }
 
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
index ac6fe3f4..86f21290 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
@@ -131,6 +131,28 @@ int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr) {
         return (int) lease->sip_size;
 }
 
+int sd_dhcp_lease_get_pop3_server(sd_dhcp_lease *lease, const struct in_addr **addr) {
+        assert_return(lease, -EINVAL);
+        assert_return(addr, -EINVAL);
+
+        if (lease->pop3_server_size <= 0)
+                return -ENODATA;
+
+        *addr = lease->pop3_server;
+        return (int) lease->pop3_server_size;
+}
+
+int sd_dhcp_lease_get_smtp_server(sd_dhcp_lease *lease, const struct in_addr **addr) {
+        assert_return(lease, -EINVAL);
+        assert_return(addr, -EINVAL);
+
+        if (lease->smtp_server_size <= 0)
+                return -ENODATA;
+
+        *addr = lease->smtp_server;
+        return (int) lease->smtp_server_size;
+}
+
 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
         assert_return(lease, -EINVAL);
         assert_return(domainname, -EINVAL);
@@ -281,6 +303,8 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
         free(lease->dns);
         free(lease->ntp);
         free(lease->sip);
+        free(lease->pop3_server);
+        free(lease->smtp_server);
         free(lease->static_route);
         free(lease->client_id);
         free(lease->vendor_specific);
@@ -603,6 +627,18 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
                         log_debug_errno(r, "Failed to parse SIP server, ignoring: %m");
                 break;
 
+        case SD_DHCP_OPTION_POP3_SERVER:
+                r = lease_parse_in_addrs(option, len, &lease->pop3_server, &lease->pop3_server_size);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to parse POP3 server, ignoring: %m");
+                break;
+
+        case SD_DHCP_OPTION_SMTP_SERVER:
+                r = lease_parse_in_addrs(option, len, &lease->smtp_server, &lease->smtp_server_size);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to parse SMTP server, ignoring: %m");
+                break;
+
         case SD_DHCP_OPTION_STATIC_ROUTE:
                 r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated);
                 if (r < 0)
@@ -1039,6 +1075,8 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
                 *dns = NULL,
                 *ntp = NULL,
                 *sip = NULL,
+                *pop3_server = NULL,
+                *smtp_server = NULL,
                 *mtu = NULL,
                 *routes = NULL,
                 *domains = NULL,
@@ -1068,6 +1106,8 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
                            "DNS", &dns,
                            "NTP", &ntp,
                            "SIP", &sip,
+                           "POP3_SERVERS", &pop3_server,
+                           "SMTP_SERVERS", &smtp_server,
                            "MTU", &mtu,
                            "DOMAINNAME", &lease->domainname,
                            "HOSTNAME", &lease->hostname,
@@ -1177,7 +1217,23 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
                 if (r < 0)
                         log_debug_errno(r, "Failed to deserialize SIP servers %s, ignoring: %m", sip);
                 else
-                        lease->ntp_size = r;
+                        lease->sip_size = r;
+        }
+
+        if (pop3_server) {
+                r = deserialize_in_addrs(&lease->pop3_server, pop3_server);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to deserialize POP3 server %s, ignoring: %m", pop3_server);
+                else
+                        lease->pop3_server_size = r;
+        }
+
+        if (smtp_server) {
+                r = deserialize_in_addrs(&lease->smtp_server, smtp_server);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to deserialize SMTP server %s, ignoring: %m", smtp_server);
+                else
+                        lease->smtp_server_size = r;
         }
 
         if (mtu) {
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
index e1150f98..826ad56a 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
@@ -27,6 +27,7 @@
 #include "socket-util.h"
 #include "string-table.h"
 #include "util.h"
+#include "web-util.h"
 
 #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
 
@@ -67,6 +68,7 @@ struct sd_dhcp6_client {
         size_t req_opts_allocated;
         size_t req_opts_len;
         char *fqdn;
+        char *mudurl;
         sd_event_source *receive_message;
         usec_t retransmit_time;
         uint8_t retransmit_count;
@@ -369,6 +371,17 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
         return 0;
 }
 
+int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, char *mudurl) {
+
+        assert_return(client, -EINVAL);
+        assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
+        assert_return(mudurl, -EINVAL);
+        assert_return(strlen(mudurl) <= 255, -EINVAL);
+        assert_return(http_url_is_valid(mudurl), -EINVAL);
+
+        return free_and_strdup(&client->mudurl, mudurl);
+}
+
 int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) {
         assert_return(client, -EINVAL);
         assert_return(delegation, -EINVAL);
@@ -490,6 +503,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
         case DHCP6_STATE_INFORMATION_REQUEST:
                 message->type = DHCP6_INFORMATION_REQUEST;
 
+                if (client->mudurl) {
+                        r = dhcp6_option_append(&opt, &optlen,
+                                                SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
+                                                client->mudurl);
+                        if (r < 0)
+                                return r;
+                }
+
                 break;
 
         case DHCP6_STATE_SOLICITATION:
@@ -513,6 +534,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
+                if (client->mudurl) {
+                        r = dhcp6_option_append(&opt, &optlen,
+                                                SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
+                                                client->mudurl);
+                        if (r < 0)
+                                return r;
+                }
+
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
                         r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix);
                         if (r < 0)
@@ -551,6 +580,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
+                if (client->mudurl) {
+                        r = dhcp6_option_append(&opt, &optlen,
+                                                SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
+                                                client->mudurl);
+                        if (r < 0)
+                                return r;
+                }
+
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
                         r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
                         if (r < 0)
@@ -577,6 +614,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                                 return r;
                 }
 
+                if (client->mudurl) {
+                        r = dhcp6_option_append(&opt, &optlen,
+                                                SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
+                                                client->mudurl);
+                        if (r < 0)
+                                return r;
+                }
+
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
                         r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
                         if (r < 0)
@@ -681,8 +726,7 @@ static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void
 }
 
 static usec_t client_timeout_compute_random(usec_t val) {
-        return val - val / 10 +
-                (random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC;
+        return val - (random_u32() % USEC_PER_SEC) * val / 10 / USEC_PER_SEC;
 }
 
 static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userdata) {
@@ -692,7 +736,6 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
         usec_t max_retransmit_duration = 0;
         uint8_t max_retransmit_count = 0;
         char time_string[FORMAT_TIMESPAN_MAX];
-        uint32_t expire = 0;
 
         assert(s);
         assert(client);
@@ -741,8 +784,9 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
                 max_retransmit_time = DHCP6_REB_MAX_RT;
 
                 if (event_source_is_enabled(client->timeout_resend_expire) <= 0) {
-                        r = dhcp6_lease_ia_rebind_expire(&client->lease->ia,
-                                                         &expire);
+                        uint32_t expire = 0;
+
+                        r = dhcp6_lease_ia_rebind_expire(&client->lease->ia, &expire);
                         if (r < 0) {
                                 client_stop(client, r);
                                 return 0;
@@ -757,7 +801,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
                 return 0;
         }
 
-        if (max_retransmit_count &&
+        if (max_retransmit_count > 0 &&
             client->retransmit_count >= max_retransmit_count) {
                 client_stop(client, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX);
                 return 0;
@@ -771,7 +815,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
         if (r >= 0)
                 client->retransmit_count++;
 
-        if (!client->retransmit_time) {
+        if (client->retransmit_time == 0) {
                 client->retransmit_time =
                         client_timeout_compute_random(init_retransmit_time);
 
@@ -779,7 +823,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
                         client->retransmit_time += init_retransmit_time / 10;
 
         } else {
-                if (max_retransmit_time &&
+                if (max_retransmit_time > 0 &&
                     client->retransmit_time > max_retransmit_time / 2)
                         client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
                 else
@@ -797,7 +841,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
         if (r < 0)
                 goto error;
 
-        if (max_retransmit_duration && event_source_is_enabled(client->timeout_resend_expire) <= 0) {
+        if (max_retransmit_duration > 0 && event_source_is_enabled(client->timeout_resend_expire) <= 0) {
 
                 log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs",
                                  max_retransmit_duration / USEC_PER_SEC);
@@ -1528,6 +1572,7 @@ static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) {
 
         free(client->req_opts);
         free(client->fqdn);
+        free(client->mudurl);
         return mfree(client);
 }
 
diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c
index 3efa8170..9f69088d 100644
--- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c
+++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c
@@ -443,7 +443,7 @@ int sd_ipv4acd_is_running(sd_ipv4acd *acd) {
         return acd->state != IPV4ACD_STATE_INIT;
 }
 
-int sd_ipv4acd_start(sd_ipv4acd *acd) {
+int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts) {
         int r;
 
         assert_return(acd, -EINVAL);
@@ -460,7 +460,9 @@ int sd_ipv4acd_start(sd_ipv4acd *acd) {
         safe_close(acd->fd);
         acd->fd = r;
         acd->defend_window = 0;
-        acd->n_conflict = 0;
+
+        if (reset_conflicts)
+                acd->n_conflict = 0;
 
         r = sd_event_add_io(acd->event, &acd->receive_message_event_source, acd->fd, EPOLLIN, ipv4acd_on_packet, acd);
         if (r < 0)
diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c
index 2d17b4fe..a610546c 100644
--- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c
@@ -243,7 +243,7 @@ static int ipv4ll_start_internal(sd_ipv4ll *ll, bool reset_generation) {
                 picked_address = true;
         }
 
-        r = sd_ipv4acd_start(ll->acd);
+        r = sd_ipv4acd_start(ll->acd, reset_generation);
         if (r < 0) {
 
                 /* We couldn't start? If so, let's forget the picked address again, the user might make a change and
diff --git a/src/systemd/src/libsystemd/sd-event/event-source.h b/src/systemd/src/libsystemd/sd-event/event-source.h
index 99ab8fc1..08eb9b6a 100644
--- a/src/systemd/src/libsystemd/sd-event/event-source.h
+++ b/src/systemd/src/libsystemd/sd-event/event-source.h
@@ -34,7 +34,7 @@ typedef enum EventSourceType {
  * we know how to dispatch it */
 typedef enum WakeupType {
         WAKEUP_NONE,
-        WAKEUP_EVENT_SOURCE,
+        WAKEUP_EVENT_SOURCE, /* either I/O or pidfd wakeup */
         WAKEUP_CLOCK_DATA,
         WAKEUP_SIGNAL_DATA,
         WAKEUP_INOTIFY_DATA,
@@ -96,6 +96,12 @@ struct sd_event_source {
                         siginfo_t siginfo;
                         pid_t pid;
                         int options;
+                        int pidfd;
+                        bool registered:1; /* whether the pidfd is registered in the epoll */
+                        bool pidfd_owned:1; /* close pidfd when event source is freed */
+                        bool process_owned:1; /* kill+reap process when event source is freed */
+                        bool exited:1; /* true if process exited (i.e. if there's value in SIGKILLing it if we want to get rid of it) */
+                        bool waited:1; /* true if process was waited for (i.e. if there's value in waitid(P_PID)'ing it if we want to get rid of it) */
                 } child;
                 struct {
                         sd_event_handler_t callback;
diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c
index 7c4566e3..3e56e807 100644
--- a/src/systemd/src/libsystemd/sd-event/sd-event.c
+++ b/src/systemd/src/libsystemd/sd-event/sd-event.c
@@ -11,6 +11,7 @@
 #include "sd-id128.h"
 
 #include "alloc-util.h"
+#include "env-util.h"
 #include "event-source.h"
 #include "fd-util.h"
 #include "fs-util.h"
@@ -30,6 +31,14 @@
 
 #define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
 
+static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) {
+        /* Returns true if this is a PID event source and can be implemented by watching EPOLLIN */
+        return s &&
+                s->type == SOURCE_CHILD &&
+                s->child.pidfd >= 0 &&
+                s->child.options == WEXITED;
+}
+
 static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = {
         [SOURCE_IO] = "io",
         [SOURCE_TIME_REALTIME] = "realtime",
@@ -108,6 +117,9 @@ struct sd_event {
 
         unsigned n_sources;
 
+        struct epoll_event *event_queue;
+        size_t event_queue_allocated;
+
         LIST_HEAD(sd_event_source, sources);
 
         usec_t last_run, last_log;
@@ -279,6 +291,8 @@ static sd_event *event_free(sd_event *e) {
         hashmap_free(e->child_sources);
         set_free(e->post_sources);
 
+        free(e->event_queue);
+
         return mfree(e);
 }
 
@@ -358,8 +372,6 @@ static bool event_pid_changed(sd_event *e) {
 }
 
 static void source_io_unregister(sd_event_source *s) {
-        int r;
-
         assert(s);
         assert(s->type == SOURCE_IO);
 
@@ -369,8 +381,7 @@ static void source_io_unregister(sd_event_source *s) {
         if (!s->io.registered)
                 return;
 
-        r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL);
-        if (r < 0)
+        if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0)
                 log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m",
                                 strna(s->description), event_source_type_to_string(s->type));
 
@@ -382,22 +393,20 @@ static int source_io_register(
                 int enabled,
                 uint32_t events) {
 
-        struct epoll_event ev;
-        int r;
-
         assert(s);
         assert(s->type == SOURCE_IO);
         assert(enabled != SD_EVENT_OFF);
 
-        ev = (struct epoll_event) {
+        struct epoll_event ev = {
                 .events = events | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0),
                 .data.ptr = s,
         };
+        int r;
 
-        if (s->io.registered)
-                r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->io.fd, &ev);
-        else
-                r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->io.fd, &ev);
+        r = epoll_ctl(s->event->epoll_fd,
+                      s->io.registered ? EPOLL_CTL_MOD : EPOLL_CTL_ADD,
+                      s->io.fd,
+                      &ev);
         if (r < 0)
                 return -errno;
 
@@ -406,6 +415,49 @@ static int source_io_register(
         return 0;
 }
 
+static void source_child_pidfd_unregister(sd_event_source *s) {
+        assert(s);
+        assert(s->type == SOURCE_CHILD);
+
+        if (event_pid_changed(s->event))
+                return;
+
+        if (!s->child.registered)
+                return;
+
+        if (EVENT_SOURCE_WATCH_PIDFD(s))
+                if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->child.pidfd, NULL) < 0)
+                        log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m",
+                                        strna(s->description), event_source_type_to_string(s->type));
+
+        s->child.registered = false;
+}
+
+static int source_child_pidfd_register(sd_event_source *s, int enabled) {
+        int r;
+
+        assert(s);
+        assert(s->type == SOURCE_CHILD);
+        assert(enabled != SD_EVENT_OFF);
+
+        if (EVENT_SOURCE_WATCH_PIDFD(s)) {
+                struct epoll_event ev = {
+                        .events = EPOLLIN | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0),
+                        .data.ptr = s,
+                };
+
+                if (s->child.registered)
+                        r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->child.pidfd, &ev);
+                else
+                        r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->child.pidfd, &ev);
+                if (r < 0)
+                        return -errno;
+        }
+
+        s->child.registered = true;
+        return 0;
+}
+
 static clockid_t event_source_type_to_clock(EventSourceType t) {
 
         switch (t) {
@@ -495,7 +547,6 @@ static int event_make_signal_data(
                 int sig,
                 struct signal_data **ret) {
 
-        struct epoll_event ev;
         struct signal_data *d;
         bool added = false;
         sigset_t ss_copy;
@@ -562,7 +613,7 @@ static int event_make_signal_data(
 
         d->fd = fd_move_above_stdio(r);
 
-        ev = (struct epoll_event) {
+        struct epoll_event ev = {
                 .events = EPOLLIN,
                 .data.ptr = d,
         };
@@ -616,9 +667,8 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig)
 
         assert(e);
 
-        /* Rechecks if the specified signal is still something we are
-         * interested in. If not, we'll unmask it, and possibly drop
-         * the signalfd for it. */
+        /* Rechecks if the specified signal is still something we are interested in. If not, we'll unmask it,
+         * and possibly drop the signalfd for it. */
 
         if (sig == SIGCHLD &&
             e->n_enabled_child_sources > 0)
@@ -709,9 +759,13 @@ static void source_disconnect(sd_event_source *s) {
                         }
 
                         (void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid));
-                        event_gc_signal_data(s->event, &s->priority, SIGCHLD);
                 }
 
+                if (EVENT_SOURCE_WATCH_PIDFD(s))
+                        source_child_pidfd_unregister(s);
+                else
+                        event_gc_signal_data(s->event, &s->priority, SIGCHLD);
+
                 break;
 
         case SOURCE_DEFER:
@@ -771,9 +825,7 @@ static void source_disconnect(sd_event_source *s) {
         if (s->prepare)
                 prioq_remove(s->event->prepare, s, &s->prepare_index);
 
-        event = s->event;
-
-        s->event = NULL;
+        event = TAKE_PTR(s->event);
         LIST_REMOVE(sources, event->sources, s);
         event->n_sources--;
 
@@ -792,6 +844,44 @@ static void source_free(sd_event_source *s) {
         if (s->type == SOURCE_IO && s->io.owned)
                 s->io.fd = safe_close(s->io.fd);
 
+        if (s->type == SOURCE_CHILD) {
+                /* Eventually the kernel will do this automatically for us, but for now let's emulate this (unreliably) in userspace. */
+
+                if (s->child.process_owned) {
+
+                        if (!s->child.exited) {
+                                bool sent = false;
+
+                                if (s->child.pidfd >= 0) {
+                                        if (pidfd_send_signal(s->child.pidfd, SIGKILL, NULL, 0) < 0) {
+                                                if (errno == ESRCH) /* Already dead */
+                                                        sent = true;
+                                                else if (!ERRNO_IS_NOT_SUPPORTED(errno))
+                                                        log_debug_errno(errno, "Failed to kill process " PID_FMT " via pidfd_send_signal(), re-trying via kill(): %m",
+                                                                        s->child.pid);
+                                        } else
+                                                sent = true;
+                                }
+
+                                if (!sent)
+                                        if (kill(s->child.pid, SIGKILL) < 0)
+                                                if (errno != ESRCH) /* Already dead */
+                                                        log_debug_errno(errno, "Failed to kill process " PID_FMT " via kill(), ignoring: %m",
+                                                                        s->child.pid);
+                        }
+
+                        if (!s->child.waited) {
+                                siginfo_t si = {};
+
+                                /* Reap the child if we can */
+                                (void) waitid(P_PID, s->child.pid, &si, WEXITED);
+                        }
+                }
+
+                if (s->child.pidfd_owned)
+                        s->child.pidfd = safe_close(s->child.pidfd);
+        }
+
         if (s->destroy_callback)
                 s->destroy_callback(s->userdata);
 
@@ -949,33 +1039,31 @@ static int event_setup_timer_fd(
                 struct clock_data *d,
                 clockid_t clock) {
 
-        struct epoll_event ev;
-        int r, fd;
-
         assert(e);
         assert(d);
 
         if (_likely_(d->fd >= 0))
                 return 0;
 
+        _cleanup_close_ int fd = -1;
+        int r;
+
         fd = timerfd_create(clock, TFD_NONBLOCK|TFD_CLOEXEC);
         if (fd < 0)
                 return -errno;
 
         fd = fd_move_above_stdio(fd);
 
-        ev = (struct epoll_event) {
+        struct epoll_event ev = {
                 .events = EPOLLIN,
                 .data.ptr = d,
         };
 
         r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev);
-        if (r < 0) {
-                safe_close(fd);
+        if (r < 0)
                 return -errno;
-        }
 
-        d->fd = fd;
+        d->fd = TAKE_FD(fd);
         return 0;
 }
 
@@ -1076,7 +1164,6 @@ _public_ int sd_event_add_signal(
 
         _cleanup_(source_freep) sd_event_source *s = NULL;
         struct signal_data *d;
-        sigset_t ss;
         int r;
 
         assert_return(e, -EINVAL);
@@ -1088,11 +1175,10 @@ _public_ int sd_event_add_signal(
         if (!callback)
                 callback = signal_exit_callback;
 
-        r = pthread_sigmask(SIG_SETMASK, NULL, &ss);
-        if (r != 0)
-                return -r;
-
-        if (!sigismember(&ss, sig))
+        r = signal_is_blocked(sig);
+        if (r < 0)
+                return r;
+        if (r == 0)
                 return -EBUSY;
 
         if (!e->signal_sources) {
@@ -1126,7 +1212,11 @@ _public_ int sd_event_add_signal(
 
         return 0;
 }
-#endif /* NM_IGNORED */
+
+static bool shall_use_pidfd(void) {
+        /* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */
+        return getenv_bool_secure("SYSTEMD_PIDFD") != 0;
+}
 
 _public_ int sd_event_add_child(
                 sd_event *e,
@@ -1148,6 +1238,20 @@ _public_ int sd_event_add_child(
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
+        if (e->n_enabled_child_sources == 0) {
+                /* Caller must block SIGCHLD before using us to watch children, even if pidfd is available,
+                 * for compatibility with pre-pidfd and because we don't want the reap the child processes
+                 * ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to
+                 * take effect.
+                 *
+                 * (As an optimization we only do this check on the first child event source created.) */
+                r = signal_is_blocked(SIGCHLD);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return -EBUSY;
+        }
+
         r = hashmap_ensure_allocated(&e->child_sources, NULL);
         if (r < 0)
                 return r;
@@ -1159,32 +1263,147 @@ _public_ int sd_event_add_child(
         if (!s)
                 return -ENOMEM;
 
+        s->wakeup = WAKEUP_EVENT_SOURCE;
         s->child.pid = pid;
         s->child.options = options;
         s->child.callback = callback;
         s->userdata = userdata;
         s->enabled = SD_EVENT_ONESHOT;
 
+        /* We always take a pidfd here if we can, even if we wait for anything else than WEXITED, so that we
+         * pin the PID, and make regular waitid() handling race-free. */
+
+        if (shall_use_pidfd()) {
+                s->child.pidfd = pidfd_open(s->child.pid, 0);
+                if (s->child.pidfd < 0) {
+                        /* Propagate errors unless the syscall is not supported or blocked */
+                        if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
+                                return -errno;
+                } else
+                        s->child.pidfd_owned = true; /* If we allocate the pidfd we own it by default */
+        } else
+                s->child.pidfd = -1;
+
         r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s);
         if (r < 0)
                 return r;
 
         e->n_enabled_child_sources++;
 
-        r = event_make_signal_data(e, SIGCHLD, NULL);
-        if (r < 0) {
-                e->n_enabled_child_sources--;
-                return r;
-        }
+        if (EVENT_SOURCE_WATCH_PIDFD(s)) {
+                /* We have a pidfd and we only want to watch for exit */
 
-        e->need_process_child = true;
+                r = source_child_pidfd_register(s, s->enabled);
+                if (r < 0) {
+                        e->n_enabled_child_sources--;
+                        return r;
+                }
+        } else {
+                /* We have no pidfd or we shall wait for some other event than WEXITED */
+
+                r = event_make_signal_data(e, SIGCHLD, NULL);
+                if (r < 0) {
+                        e->n_enabled_child_sources--;
+                        return r;
+                }
+
+                e->need_process_child = true;
+        }
 
         if (ret)
                 *ret = s;
+
         TAKE_PTR(s);
+        return 0;
+}
+
+_public_ int sd_event_add_child_pidfd(
+                sd_event *e,
+                sd_event_source **ret,
+                int pidfd,
+                int options,
+                sd_event_child_handler_t callback,
+                void *userdata) {
+
+
+        _cleanup_(source_freep) sd_event_source *s = NULL;
+        pid_t pid;
+        int r;
+
+        assert_return(e, -EINVAL);
+        assert_return(e = event_resolve(e), -ENOPKG);
+        assert_return(pidfd >= 0, -EBADF);
+        assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL);
+        assert_return(options != 0, -EINVAL);
+        assert_return(callback, -EINVAL);
+        assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
+        assert_return(!event_pid_changed(e), -ECHILD);
+
+        if (e->n_enabled_child_sources == 0) {
+                r = signal_is_blocked(SIGCHLD);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return -EBUSY;
+        }
+
+        r = hashmap_ensure_allocated(&e->child_sources, NULL);
+        if (r < 0)
+                return r;
+
+        r = pidfd_get_pid(pidfd, &pid);
+        if (r < 0)
+                return r;
+
+        if (hashmap_contains(e->child_sources, PID_TO_PTR(pid)))
+                return -EBUSY;
+
+        s = source_new(e, !ret, SOURCE_CHILD);
+        if (!s)
+                return -ENOMEM;
+
+        s->wakeup = WAKEUP_EVENT_SOURCE;
+        s->child.pidfd = pidfd;
+        s->child.pid = pid;
+        s->child.options = options;
+        s->child.callback = callback;
+        s->child.pidfd_owned = false; /* If we got the pidfd passed in we don't own it by default (similar to the IO fd case) */
+        s->userdata = userdata;
+        s->enabled = SD_EVENT_ONESHOT;
 
+        r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s);
+        if (r < 0)
+                return r;
+
+        e->n_enabled_child_sources++;
+
+        if (EVENT_SOURCE_WATCH_PIDFD(s)) {
+                /* We only want to watch for WEXITED */
+
+                r = source_child_pidfd_register(s, s->enabled);
+                if (r < 0) {
+                        e->n_enabled_child_sources--;
+                        return r;
+                }
+        } else {
+                /* We shall wait for some other event than WEXITED */
+
+                r = event_make_signal_data(e, SIGCHLD, NULL);
+                if (r < 0) {
+                        e->n_enabled_child_sources--;
+                        return r;
+                }
+
+                e->need_process_child = true;
+        }
+
+        if (ret)
+                *ret = s;
+
+        TAKE_PTR(s);
         return 0;
 }
+#endif /* NM_IGNORED */
 
 _public_ int sd_event_add_defer(
                 sd_event *e,
@@ -1330,7 +1549,6 @@ static int event_make_inotify_data(
 
         _cleanup_close_ int fd = -1;
         struct inotify_data *d;
-        struct epoll_event ev;
         int r;
 
         assert(e);
@@ -1369,7 +1587,7 @@ static int event_make_inotify_data(
                 return r;
         }
 
-        ev = (struct epoll_event) {
+        struct epoll_event ev = {
                 .events = EPOLLIN,
                 .data.ptr = d,
         };
@@ -1769,7 +1987,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) {
                         return r;
                 }
 
-                epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL);
+                (void) epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL);
         }
 
         return 0;
@@ -2030,7 +2248,11 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
                         assert(s->event->n_enabled_child_sources > 0);
                         s->event->n_enabled_child_sources--;
 
-                        event_gc_signal_data(s->event, &s->priority, SIGCHLD);
+                        if (EVENT_SOURCE_WATCH_PIDFD(s))
+                                source_child_pidfd_unregister(s);
+                        else
+                                event_gc_signal_data(s->event, &s->priority, SIGCHLD);
+
                         break;
 
                 case SOURCE_EXIT:
@@ -2104,12 +2326,25 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
 
                         s->enabled = m;
 
-                        r = event_make_signal_data(s->event, SIGCHLD, NULL);
-                        if (r < 0) {
-                                s->enabled = SD_EVENT_OFF;
-                                s->event->n_enabled_child_sources--;
-                                event_gc_signal_data(s->event, &s->priority, SIGCHLD);
-                                return r;
+                        if (EVENT_SOURCE_WATCH_PIDFD(s)) {
+                                /* yes, we have pidfd */
+
+                                r = source_child_pidfd_register(s, s->enabled);
+                                if (r < 0) {
+                                        s->enabled = SD_EVENT_OFF;
+                                        s->event->n_enabled_child_sources--;
+                                        return r;
+                                }
+                        } else {
+                                /* no pidfd, or something other to watch for than WEXITED */
+
+                                r = event_make_signal_data(s->event, SIGCHLD, NULL);
+                                if (r < 0) {
+                                        s->enabled = SD_EVENT_OFF;
+                                        s->event->n_enabled_child_sources--;
+                                        event_gc_signal_data(s->event, &s->priority, SIGCHLD);
+                                        return r;
+                                }
                         }
 
                         break;
@@ -2232,6 +2467,98 @@ _public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) {
         return 0;
 }
 
+_public_ int sd_event_source_get_child_pidfd(sd_event_source *s) {
+        assert_return(s, -EINVAL);
+        assert_return(s->type == SOURCE_CHILD, -EDOM);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+
+        if (s->child.pidfd < 0)
+                return -EOPNOTSUPP;
+
+        return s->child.pidfd;
+}
+
+_public_ int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo_t *si, unsigned flags) {
+        assert_return(s, -EINVAL);
+        assert_return(s->type == SOURCE_CHILD, -EDOM);
+        assert_return(!event_pid_changed(s->event), -ECHILD);
+        assert_return(SIGNAL_VALID(sig), -EINVAL);
+
+        /* If we already have seen indication the process exited refuse sending a signal early. This way we
+         * can be sure we don't accidentally kill the wrong process on PID reuse when pidfds are not
+         * available. */
+        if (s->child.exited)
+                return -ESRCH;
+
+        if (s->child.pidfd >= 0) {
+                siginfo_t copy;
+
+                /* pidfd_send_signal() changes the siginfo_t argument. This is weird, let's hence copy the
+                 * structure here */
+                if (si)
+                        copy = *si;
+
+                if (pidfd_send_signal(s->child.pidfd, sig, si ? &copy : NULL, 0) < 0) {
+                        /* Let's propagate the error only if the system call is not implemented or prohibited */
+                        if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
+                                return -errno;
+                } else
+                        return 0;
+        }
+
+        /* Flags are only supported for pidfd_send_signal(), not for rt_sigqueueinfo(), hence let's refuse
+         * this here. */
+        if (flags != 0)
+                return -EOPNOTSUPP;
+
+        if (si) {
+                /* We use rt_sigqueueinfo() only if siginfo_t is specified. */
+                siginfo_t copy = *si;
+
+                if (rt_sigqueueinfo(s->child.pid, sig, &copy) < 0)
+                        return -errno;
+        } else if (kill(s->child.pid, sig) < 0)
+                return -errno;
+
+        return 0;
+}
+
+_public_ int sd_event_source_get_child_pidfd_own(sd_event_source *s) {
+        assert_return(s, -EINVAL);
+        assert_return(s->type == SOURCE_CHILD, -EDOM);
+
+        if (s->child.pidfd < 0)
+                return -EOPNOTSUPP;
+
+        return s->child.pidfd_owned;
+}
+
+_public_ int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own) {
+        assert_return(s, -EINVAL);
+        assert_return(s->type == SOURCE_CHILD, -EDOM);
+
+        if (s->child.pidfd < 0)
+                return -EOPNOTSUPP;
+
+        s->child.pidfd_owned = own;
+        return 0;
+}
+
+_public_ int sd_event_source_get_child_process_own(sd_event_source *s) {
+        assert_return(s, -EINVAL);
+        assert_return(s->type == SOURCE_CHILD, -EDOM);
+
+        return s->child.process_owned;
+}
+
+_public_ int sd_event_source_set_child_process_own(sd_event_source *s, int own) {
+        assert_return(s, -EINVAL);
+        assert_return(s->type == SOURCE_CHILD, -EDOM);
+
+        s->child.process_owned = own;
+        return 0;
+}
+
 _public_ int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *mask) {
         assert_return(s, -EINVAL);
         assert_return(mask, -EINVAL);
@@ -2542,6 +2869,12 @@ static int process_child(sd_event *e) {
                 if (s->enabled == SD_EVENT_OFF)
                         continue;
 
+                if (s->child.exited)
+                        continue;
+
+                if (EVENT_SOURCE_WATCH_PIDFD(s)) /* There's a usable pidfd known for this event source? then don't waitid() for it here */
+                        continue;
+
                 zero(s->child.siginfo);
                 r = waitid(P_PID, s->child.pid, &s->child.siginfo,
                            WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options);
@@ -2551,6 +2884,9 @@ static int process_child(sd_event *e) {
                 if (s->child.siginfo.si_pid != 0) {
                         bool zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED);
 
+                        if (zombie)
+                                s->child.exited = true;
+
                         if (!zombie && (s->child.options & WEXITED)) {
                                 /* If the child isn't dead then let's
                                  * immediately remove the state change
@@ -2570,6 +2906,33 @@ static int process_child(sd_event *e) {
         return 0;
 }
 
+static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) {
+        assert(e);
+        assert(s);
+        assert(s->type == SOURCE_CHILD);
+
+        if (s->pending)
+                return 0;
+
+        if (s->enabled == SD_EVENT_OFF)
+                return 0;
+
+        if (!EVENT_SOURCE_WATCH_PIDFD(s))
+                return 0;
+
+        zero(s->child.siginfo);
+        if (waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0)
+                return -errno;
+
+        if (s->child.siginfo.si_pid == 0)
+                return 0;
+
+        if (IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED))
+                s->child.exited = true;
+
+        return source_set_pending(s, true);
+}
+
 static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
         bool read_one = false;
         int r;
@@ -2854,8 +3217,10 @@ static int source_dispatch(sd_event_source *s) {
                 r = s->child.callback(s, &s->child.siginfo, s->userdata);
 
                 /* Now, reap the PID for good. */
-                if (zombie)
+                if (zombie) {
                         (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|WEXITED);
+                        s->child.waited = true;
+                }
 
                 break;
         }
@@ -3056,6 +3421,11 @@ _public_ int sd_event_prepare(sd_event *e) {
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(e->state == SD_EVENT_INITIAL, -EBUSY);
 
+        /* Let's check that if we are a default event loop we are executed in the correct thread. We only do
+         * this check here once, since gettid() is typically not cached, and thus want to minimize
+         * syscalls */
+        assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO);
+
         if (e->exit_requested)
                 goto pending;
 
@@ -3106,8 +3476,7 @@ pending:
 }
 
 _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
-        struct epoll_event *ev_queue;
-        unsigned ev_queue_max;
+        size_t event_queue_max;
         int r, m, i;
 
         assert_return(e, -EINVAL);
@@ -3121,14 +3490,15 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
                 return 1;
         }
 
-        ev_queue_max = MAX(e->n_sources, 1u);
-        ev_queue = newa(struct epoll_event, ev_queue_max);
+        event_queue_max = MAX(e->n_sources, 1u);
+        if (!GREEDY_REALLOC(e->event_queue, e->event_queue_allocated, event_queue_max))
+                return -ENOMEM;
 
         /* If we still have inotify data buffered, then query the other fds, but don't wait on it */
         if (e->inotify_data_buffered)
                 timeout = 0;
 
-        m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max,
+        m = epoll_wait(e->epoll_fd, e->event_queue, event_queue_max,
                        timeout == (uint64_t) -1 ? -1 : (int) DIV_ROUND_UP(timeout, USEC_PER_MSEC));
         if (m < 0) {
                 if (errno == EINTR) {
@@ -3144,29 +3514,50 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
 
         for (i = 0; i < m; i++) {
 
-                if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG))
-                        r = flush_timer(e, e->watchdog_fd, ev_queue[i].events, NULL);
+                if (e->event_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG))
+                        r = flush_timer(e, e->watchdog_fd, e->event_queue[i].events, NULL);
                 else {
-                        WakeupType *t = ev_queue[i].data.ptr;
+                        WakeupType *t = e->event_queue[i].data.ptr;
 
                         switch (*t) {
 
-                        case WAKEUP_EVENT_SOURCE:
-                                r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events);
+                        case WAKEUP_EVENT_SOURCE: {
+                                sd_event_source *s = e->event_queue[i].data.ptr;
+
+                                assert(s);
+
+                                switch (s->type) {
+
+                                case SOURCE_IO:
+                                        r = process_io(e, s, e->event_queue[i].events);
+                                        break;
+
+                                case SOURCE_CHILD:
+                                        r = process_pidfd(e, s, e->event_queue[i].events);
+                                        break;
+
+                                default:
+                                        assert_not_reached("Unexpected event source type");
+                                }
+
                                 break;
+                        }
 
                         case WAKEUP_CLOCK_DATA: {
-                                struct clock_data *d = ev_queue[i].data.ptr;
-                                r = flush_timer(e, d->fd, ev_queue[i].events, &d->next);
+                                struct clock_data *d = e->event_queue[i].data.ptr;
+
+                                assert(d);
+
+                                r = flush_timer(e, d->fd, e->event_queue[i].events, &d->next);
                                 break;
                         }
 
                         case WAKEUP_SIGNAL_DATA:
-                                r = process_signal(e, ev_queue[i].data.ptr, ev_queue[i].events);
+                                r = process_signal(e, e->event_queue[i].data.ptr, e->event_queue[i].events);
                                 break;
 
                         case WAKEUP_INOTIFY_DATA:
-                                r = event_inotify_data_read(e, ev_queue[i].data.ptr, ev_queue[i].events);
+                                r = event_inotify_data_read(e, e->event_queue[i].data.ptr, e->event_queue[i].events);
                                 break;
 
                         default:
@@ -3450,8 +3841,6 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
                 return e->watchdog;
 
         if (b) {
-                struct epoll_event ev;
-
                 r = sd_watchdog_enabled(false, &e->watchdog_period);
                 if (r <= 0)
                         return r;
@@ -3468,7 +3857,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
                 if (r < 0)
                         goto fail;
 
-                ev = (struct epoll_event) {
+                struct epoll_event ev = {
                         .events = EPOLLIN,
                         .data.ptr = INT_TO_PTR(SOURCE_WATCHDOG),
                 };
@@ -3481,7 +3870,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
 
         } else {
                 if (e->watchdog_fd >= 0) {
-                        epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL);
+                        (void) epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL);
                         e->watchdog_fd = safe_close(e->watchdog_fd);
                 }
         }
diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c
index f8f0883c..3cb96378 100644
--- a/src/systemd/src/libsystemd/sd-id128/id128-util.c
+++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c
@@ -14,7 +14,7 @@
 #include "stdio-util.h"
 
 #if 0 /* NM_IGNORED */
-char *id128_to_uuid_string(sd_id128_t id, char s[37]) {
+char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]) {
         unsigned n, k = 0;
 
         assert(s);
@@ -195,5 +195,18 @@ int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) {
         return memcmp(a, b, 16);
 }
 
+sd_id128_t id128_make_v4_uuid(sd_id128_t id) {
+        /* Stolen from generate_random_uuid() of drivers/char/random.c
+         * in the kernel sources */
+
+        /* Set UUID version to 4 --- truly random generation */
+        id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
+
+        /* Set the UUID variant to DCE */
+        id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
+
+        return id;
+}
+
 DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func);
 #endif /* NM_IGNORED */
diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.h b/src/systemd/src/libsystemd/sd-id128/id128-util.h
index 82a69a77..1901bf11 100644
--- a/src/systemd/src/libsystemd/sd-id128/id128-util.h
+++ b/src/systemd/src/libsystemd/sd-id128/id128-util.h
@@ -8,7 +8,9 @@
 #include "hash-funcs.h"
 #include "macro.h"
 
-char *id128_to_uuid_string(sd_id128_t id, char s[37]);
+#define ID128_UUID_STRING_MAX 37
+
+char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]);
 
 bool id128_is_valid(const char *s) _pure_;
 
@@ -28,3 +30,5 @@ int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);
 void id128_hash_func(const sd_id128_t *p, struct siphash *state);
 int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_;
 extern const struct hash_ops id128_hash_ops;
+
+sd_id128_t id128_make_v4_uuid(sd_id128_t id);
diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
index c0d0fe81..d585ff25 100644
--- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
@@ -255,19 +255,6 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) {
         return 0;
 }
 
-static sd_id128_t make_v4_uuid(sd_id128_t id) {
-        /* Stolen from generate_random_uuid() of drivers/char/random.c
-         * in the kernel sources */
-
-        /* Set UUID version to 4 --- truly random generation */
-        id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40;
-
-        /* Set the UUID variant to DCE */
-        id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80;
-
-        return id;
-}
-
 _public_ int sd_id128_randomize(sd_id128_t *ret) {
         sd_id128_t t;
         int r;
@@ -284,7 +271,7 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) {
          * only guarantee this for newly generated UUIDs, not for
          * pre-existing ones. */
 
-        *ret = make_v4_uuid(t);
+        *ret = id128_make_v4_uuid(t);
         return 0;
 }
 
@@ -311,7 +298,7 @@ static int get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret)
         /* We chop off the trailing 16 bytes */
         memcpy(&result, p, MIN(khash_get_size(h), sizeof(result)));
 
-        *ret = make_v4_uuid(result);
+        *ret = id128_make_v4_uuid(result);
         return 0;
 }
 
diff --git a/src/systemd/src/systemd/_sd-common.h b/src/systemd/src/systemd/_sd-common.h
index b3ee7bbc..8158ee73 100644
--- a/src/systemd/src/systemd/_sd-common.h
+++ b/src/systemd/src/systemd/_sd-common.h
@@ -45,6 +45,18 @@ typedef void (*_sd_destroy_t)(void *userdata);
 #  define _sd_pure_ __attribute__((__pure__))
 #endif
 
+/* Note that strictly speaking __deprecated__ has been available before GCC 6. However, starting with GCC 6
+ * it also works on enum values, which we are interested in. Since this is a developer-facing feature anyway
+ * (as opposed to build engineer-facing), let's hence conditionalize this to gcc 6, given that the developers
+ * are probably going to use something newer anyway. */
+#ifndef _sd_deprecated_
+#  if __GNUC__ >= 6
+#    define _sd_deprecated_ __attribute__((__deprecated__))
+#  else
+#    define _sd_deprecated_
+#  endif
+#endif
+
 #ifndef _SD_STRINGIFY
 #  define _SD_XSTRINGIFY(x) #x
 #  define _SD_STRINGIFY(x) _SD_XSTRINGIFY(x)
diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h
index f97e35b6..da2aa6c7 100644
--- a/src/systemd/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/src/systemd/sd-dhcp-client.h
@@ -83,6 +83,8 @@ enum {
         SD_DHCP_OPTION_REBINDING_T2_TIME           = 59,
         SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER     = 60,
         SD_DHCP_OPTION_CLIENT_IDENTIFIER           = 61,
+        SD_DHCP_OPTION_SMTP_SERVER                 = 69,
+        SD_DHCP_OPTION_POP3_SERVER                 = 70,
         SD_DHCP_OPTION_USER_CLASS                  = 77,
         SD_DHCP_OPTION_FQDN                        = 81,
         SD_DHCP_OPTION_NEW_POSIX_TIMEZONE          = 100,
@@ -90,6 +92,7 @@ enum {
         SD_DHCP_OPTION_DOMAIN_SEARCH_LIST          = 119,
         SD_DHCP_OPTION_SIP_SERVER                  = 120,
         SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE      = 121,
+        SD_DHCP_OPTION_MUD_URL                     = 161,
         SD_DHCP_OPTION_PRIVATE_BASE                = 224,
        /* Windows 10 option to send when Anonymize=true */
         SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE = 249,
@@ -169,6 +172,9 @@ int sd_dhcp_client_set_hostname(
 int sd_dhcp_client_set_vendor_class_identifier(
                 sd_dhcp_client *client,
                 const char *vci);
+int sd_dhcp_client_set_mud_url(
+                sd_dhcp_client *client,
+                const char *mudurl);
 int sd_dhcp_client_set_user_class(
                 sd_dhcp_client *client,
                 const char* const *user_class);
@@ -179,11 +185,13 @@ int sd_dhcp_client_set_service_type(
                 sd_dhcp_client *client,
                 int type);
 
-int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v);
+int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v);
+int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v);
 
 int sd_dhcp_client_stop(sd_dhcp_client *client);
 int sd_dhcp_client_start(sd_dhcp_client *client);
 int sd_dhcp_client_send_release(sd_dhcp_client *client);
+int sd_dhcp_client_send_decline(sd_dhcp_client *client);
 int sd_dhcp_client_send_renew(sd_dhcp_client *client);
 
 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client);
diff --git a/src/systemd/src/systemd/sd-dhcp-lease.h b/src/systemd/src/systemd/sd-dhcp-lease.h
index b80d607f..1ed5bf27 100644
--- a/src/systemd/src/systemd/sd-dhcp-lease.h
+++ b/src/systemd/src/systemd/sd-dhcp-lease.h
@@ -45,6 +45,8 @@ int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *ad
 int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr);
 int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr);
 int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr);
+int sd_dhcp_lease_get_pop3_server(sd_dhcp_lease *lease, const struct in_addr **addr);
+int sd_dhcp_lease_get_smtp_server(sd_dhcp_lease *lease, const struct in_addr **addr);
 int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu);
 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
 int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains);
diff --git a/src/systemd/src/systemd/sd-dhcp6-client.h b/src/systemd/src/systemd/sd-dhcp6-client.h
index be34d43e..42d4ec75 100644
--- a/src/systemd/src/systemd/sd-dhcp6-client.h
+++ b/src/systemd/src/systemd/sd-dhcp6-client.h
@@ -73,6 +73,7 @@ enum {
         SD_DHCP6_OPTION_FQDN                       = 39,  /* RFC 4704 */
 
         SD_DHCP6_OPTION_NTP_SERVER                 = 56,  /* RFC 5908 */
+        SD_DHCP6_OPTION_MUD_URL                    = 112, /* RFC 8250 */
 
         /* option codes 89-142 are unassigned */
         /* option codes 144-65535 are unassigned */
@@ -120,6 +121,9 @@ int sd_dhcp6_client_get_information_request(
 int sd_dhcp6_client_set_request_option(
                 sd_dhcp6_client *client,
                 uint16_t option);
+int sd_dhcp6_client_set_request_mud_url(
+                sd_dhcp6_client *client,
+                char *mudurl);
 int sd_dhcp6_client_set_prefix_delegation_hint(
                 sd_dhcp6_client *client,
                 uint8_t prefixlen,
diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h
index b14c9269..2ec726a8 100644
--- a/src/systemd/src/systemd/sd-event.h
+++ b/src/systemd/src/systemd/sd-event.h
@@ -23,6 +23,7 @@
 #include <sys/inotify.h>
 #include <sys/signalfd.h>
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <time.h>
 
 #include "_sd-common.h"
@@ -89,6 +90,7 @@ int sd_event_add_io(sd_event *e, sd_event_source **s, int fd, uint32_t events, s
 int sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata);
 int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_signal_handler_t callback, void *userdata);
 int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata);
+int sd_event_add_child_pidfd(sd_event *e, sd_event_source **s, int pidfd, int options, sd_event_child_handler_t callback, void *userdata);
 int sd_event_add_inotify(sd_event *e, sd_event_source **s, const char *path, uint32_t mask, sd_event_inotify_handler_t callback, void *userdata);
 int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
 int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
@@ -141,6 +143,16 @@ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec);
 int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock);
 int sd_event_source_get_signal(sd_event_source *s);
 int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid);
+int sd_event_source_get_child_pidfd(sd_event_source *s);
+int sd_event_source_get_child_pidfd_own(sd_event_source *s);
+int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own);
+int sd_event_source_get_child_process_own(sd_event_source *s);
+int sd_event_source_set_child_process_own(sd_event_source *s, int own);
+#if defined _GNU_SOURCE || (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L)
+int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo_t *si, unsigned flags);
+#else
+int sd_event_source_send_child_signal(sd_event_source *s, int sig, const void *si, unsigned flags);
+#endif
 int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret);
 int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback);
 int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret);
diff --git a/src/systemd/src/systemd/sd-ipv4acd.h b/src/systemd/src/systemd/sd-ipv4acd.h
index 039ed3c7..ebf723fc 100644
--- a/src/systemd/src/systemd/sd-ipv4acd.h
+++ b/src/systemd/src/systemd/sd-ipv4acd.h
@@ -20,6 +20,7 @@
 
 #include <net/ethernet.h>
 #include <netinet/in.h>
+#include <stdbool.h>
 
 #include "sd-event.h"
 
@@ -44,7 +45,7 @@ int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr);
 int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index);
 int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address);
 int sd_ipv4acd_is_running(sd_ipv4acd *acd);
-int sd_ipv4acd_start(sd_ipv4acd *acd);
+int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts);
 int sd_ipv4acd_stop(sd_ipv4acd *acd);
 sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd);
 sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd);