about summary refs log tree commit diff
path: root/src/systemd
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2019-12-18 18:29:24 +0100
committerMichael Biebl <biebl@debian.org>2019-12-18 18:29:24 +0100
commit28028b26b3371756811e95d894f709f4b1207c00 (patch)
tree6fe7316fd743b51042db47601a8ef8814b3134ac /src/systemd
parente22609983008e1a669196ad64ba3a59ae8c76e0d (diff)
New upstream version 1.22.0 upstream/1.22.0
Diffstat (limited to 'src/systemd')
-rw-r--r--src/systemd/meson.build87
-rw-r--r--src/systemd/nm-sd-utils-core.c17
-rw-r--r--src/systemd/nm-sd-utils-core.h17
-rw-r--r--src/systemd/nm-sd-utils-dhcp.c18
-rw-r--r--src/systemd/nm-sd-utils-dhcp.h18
-rw-r--r--src/systemd/nm-sd.c79
-rw-r--r--src/systemd/nm-sd.h16
-rw-r--r--src/systemd/sd-adapt-core/nm-sd-adapt-core.c16
-rw-r--r--src/systemd/sd-adapt-core/nm-sd-adapt-core.h17
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-internal.h14
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-lease-internal.h3
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-network.c9
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-option.c139
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-packet.c7
-rw-r--r--src/systemd/src/libsystemd-network/dhcp6-internal.h2
-rw-r--r--src/systemd/src/libsystemd-network/dhcp6-network.c1
-rw-r--r--src/systemd/src/libsystemd-network/dhcp6-option.c21
-rw-r--r--src/systemd/src/libsystemd-network/lldp-neighbor.c2
-rw-r--r--src/systemd/src/libsystemd-network/lldp-network.c2
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.c37
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.h9
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-client.c175
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-lease.c67
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp6-client.c66
-rw-r--r--src/systemd/src/libsystemd-network/sd-ipv4acd.c1
-rw-r--r--src/systemd/src/libsystemd-network/sd-ipv4ll.c1
-rw-r--r--src/systemd/src/libsystemd/sd-event/sd-event.c8
-rw-r--r--src/systemd/src/libsystemd/sd-id128/sd-id128.c2
-rw-r--r--src/systemd/src/systemd/sd-dhcp-client.h8
-rw-r--r--src/systemd/src/systemd/sd-dhcp-lease.h1
-rw-r--r--src/systemd/src/systemd/sd-dhcp-option.h38
-rw-r--r--src/systemd/src/systemd/sd-dhcp6-client.h5
32 files changed, 572 insertions, 331 deletions
diff --git a/src/systemd/meson.build b/src/systemd/meson.build
index af1d0c8b..5c4fa3e2 100644
--- a/src/systemd/meson.build
+++ b/src/systemd/meson.build
@@ -1,45 +1,48 @@
+sources = files(
+  'src/libsystemd-network/arp-util.c',
+  'src/libsystemd-network/dhcp-identifier.c',
+  'src/libsystemd-network/dhcp-network.c',
+  'src/libsystemd-network/dhcp-option.c',
+  'src/libsystemd-network/dhcp-packet.c',
+  'src/libsystemd-network/dhcp6-network.c',
+  'src/libsystemd-network/dhcp6-option.c',
+  'src/libsystemd-network/lldp-neighbor.c',
+  'src/libsystemd-network/lldp-network.c',
+  'src/libsystemd-network/network-internal.c',
+  'src/libsystemd-network/sd-dhcp-client.c',
+  'src/libsystemd-network/sd-dhcp-lease.c',
+  'src/libsystemd-network/sd-dhcp6-client.c',
+  'src/libsystemd-network/sd-dhcp6-lease.c',
+  'src/libsystemd-network/sd-ipv4acd.c',
+  'src/libsystemd-network/sd-ipv4ll.c',
+  'src/libsystemd-network/sd-lldp.c',
+  'src/libsystemd/sd-event/event-util.c',
+  'src/libsystemd/sd-event/sd-event.c',
+  'src/libsystemd/sd-id128/id128-util.c',
+  'src/libsystemd/sd-id128/sd-id128.c',
+  'nm-sd.c',
+  'nm-sd-utils-core.c',
+  'nm-sd-utils-dhcp.c',
+  'sd-adapt-core/nm-sd-adapt-core.c',
+)
+
+incs = include_directories(
+  'sd-adapt-core',
+  'src/libsystemd-network',
+  'src/libsystemd/sd-event',
+  'src/systemd',
+)
+
+deps = [
+  daemon_nm_default_dep,
+  libnm_systemd_shared_dep,
+]
+
 libnm_systemd_core = static_library(
   'nm-systemd-core',
-  sources: files(
-    'sd-adapt-core/nm-sd-adapt-core.c',
-    'src/libsystemd-network/arp-util.c',
-    'src/libsystemd-network/dhcp-identifier.c',
-    'src/libsystemd-network/dhcp-network.c',
-    'src/libsystemd-network/dhcp-option.c',
-    'src/libsystemd-network/dhcp-packet.c',
-    'src/libsystemd-network/dhcp6-network.c',
-    'src/libsystemd-network/dhcp6-option.c',
-    'src/libsystemd-network/lldp-neighbor.c',
-    'src/libsystemd-network/lldp-network.c',
-    'src/libsystemd-network/network-internal.c',
-    'src/libsystemd-network/sd-dhcp-client.c',
-    'src/libsystemd-network/sd-dhcp-lease.c',
-    'src/libsystemd-network/sd-dhcp6-client.c',
-    'src/libsystemd-network/sd-dhcp6-lease.c',
-    'src/libsystemd-network/sd-ipv4acd.c',
-    'src/libsystemd-network/sd-ipv4ll.c',
-    'src/libsystemd-network/sd-lldp.c',
-    'src/libsystemd/sd-event/event-util.c',
-    'src/libsystemd/sd-event/sd-event.c',
-    'src/libsystemd/sd-id128/id128-util.c',
-    'src/libsystemd/sd-id128/sd-id128.c',
-    'nm-sd.c',
-    'nm-sd-utils-core.c',
-    'nm-sd-utils-dhcp.c',
-  ),
-  include_directories: [
-    src_inc,
-    include_directories(
-      'sd-adapt-core',
-      'src/libsystemd-network',
-      'src/libsystemd/sd-event',
-      'src/systemd',
-    )
-  ],
-  dependencies: [
-    libnm_core_dep,
-  ],
-  c_args: [
-    '-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_SYSTEMD',
-  ],
+  sources: sources,
+  include_directories: incs,
+  dependencies: deps,
+  c_args: '-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_SYSTEMD',
+  link_with: libc_siphash,
 )
diff --git a/src/systemd/nm-sd-utils-core.c b/src/systemd/nm-sd-utils-core.c
index 42560789..4057c70a 100644
--- a/src/systemd/nm-sd-utils-core.c
+++ b/src/systemd/nm-sd-utils-core.c
@@ -1,18 +1,5 @@
-/* This library 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 of the License, or (at your option) any later version.
- *
- * This library 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 this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: LGPL-2.1+
+/*
  * Copyright (C) 2018 Red Hat, Inc.
  */
 
diff --git a/src/systemd/nm-sd-utils-core.h b/src/systemd/nm-sd-utils-core.h
index a7b092b3..3b0bc23b 100644
--- a/src/systemd/nm-sd-utils-core.h
+++ b/src/systemd/nm-sd-utils-core.h
@@ -1,18 +1,5 @@
-/* This library 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 of the License, or (at your option) any later version.
- *
- * This library 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 this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: LGPL-2.1+
+/*
  * Copyright (C) 2018 Red Hat, Inc.
  */
 
diff --git a/src/systemd/nm-sd-utils-dhcp.c b/src/systemd/nm-sd-utils-dhcp.c
index 49a924b6..4cfe054c 100644
--- a/src/systemd/nm-sd-utils-dhcp.c
+++ b/src/systemd/nm-sd-utils-dhcp.c
@@ -1,20 +1,6 @@
+// SPDX-License-Identifier: LGPL-2.1+
 /*
- * This library 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 of the License, or (at your option) any later version.
- *
- * This library 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 this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2019 Red Hat, Inc.
+ * Copyright (C) 2019 Red Hat, Inc.
  */
 
 #include "nm-default.h"
diff --git a/src/systemd/nm-sd-utils-dhcp.h b/src/systemd/nm-sd-utils-dhcp.h
index 496bf374..5228eb25 100644
--- a/src/systemd/nm-sd-utils-dhcp.h
+++ b/src/systemd/nm-sd-utils-dhcp.h
@@ -1,20 +1,6 @@
+// SPDX-License-Identifier: LGPL-2.1+
 /*
- * This library 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 of the License, or (at your option) any later version.
- *
- * This library 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 this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
- * (C) Copyright 2019 Red Hat, Inc.
+ * Copyright (C) 2019 Red Hat, Inc.
  */
 
 #ifndef __NETWORKMANAGER_DHCP_SYSTEMD_UTILS_H__
diff --git a/src/systemd/nm-sd.c b/src/systemd/nm-sd.c
index bcab328f..a277f430 100644
--- a/src/systemd/nm-sd.c
+++ b/src/systemd/nm-sd.c
@@ -1,17 +1,5 @@
-/* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2014 - 2016 Red Hat, Inc.
  */
 
@@ -30,7 +18,6 @@ typedef struct SDEventSource {
 	GSource source;
 	GPollFD pollfd;
 	sd_event *event;
-	guint *default_source_id;
 } SDEventSource;
 
 static gboolean
@@ -48,41 +35,49 @@ event_check (GSource *source)
 static gboolean
 event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
 {
-	return sd_event_dispatch (((SDEventSource *)source)->event) > 0;
+	return sd_event_dispatch (((SDEventSource *) source)->event) > 0;
 }
 
 static void
 event_finalize (GSource *source)
 {
-	SDEventSource *s;
+	SDEventSource *s = (SDEventSource *) source;
 
-	s = (SDEventSource *) source;
 	sd_event_unref (s->event);
-	if (s->default_source_id)
-		*s->default_source_id = 0;
 }
 
 static SDEventSource *
-event_create_source (sd_event *event, guint *default_source_id)
+event_create_source (sd_event *event)
 {
-	static GSourceFuncs event_funcs = {
+	static const GSourceFuncs event_funcs = {
 		.prepare = event_prepare,
 		.check = event_check,
 		.dispatch = event_dispatch,
 		.finalize = event_finalize,
 	};
 	SDEventSource *source;
+	gboolean is_default_event = FALSE;
+	int r;
 
-	g_return_val_if_fail (event, NULL);
+	if (!event) {
+		is_default_event = TRUE;
+		r = sd_event_default (&event);
+		if (r < 0)
+			g_return_val_if_reached (NULL);
+	}
 
-	source = (SDEventSource *) g_source_new (&event_funcs, sizeof (SDEventSource));
+	source = (SDEventSource *) g_source_new ((GSourceFuncs *) &event_funcs, sizeof (SDEventSource));
 
-	source->event = sd_event_ref (event);
-	source->pollfd.fd = sd_event_get_fd (event);
-	source->pollfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
-	source->default_source_id = default_source_id;
+	source->event =   is_default_event
+	                ? g_steal_pointer (&event)
+	                : sd_event_ref (event);
 
-	g_source_add_poll ((GSource *) source, &source->pollfd);
+	source->pollfd = (GPollFD) {
+	    .fd     = sd_event_get_fd (source->event),
+	    .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
+	};
+
+	g_source_add_poll (&source->source, &source->pollfd);
 
 	return source;
 }
@@ -92,35 +87,15 @@ event_attach (sd_event *event, GMainContext *context)
 {
 	SDEventSource *source;
 	guint id;
-	int r;
-	sd_event *e = event;
-	guint *p_default_source_id = NULL;
 
-	if (!e) {
-		static guint default_source_id = 0;
+	source = event_create_source (event);
 
-		if (default_source_id) {
-			/* The default event cannot be registered multiple times. */
-			g_return_val_if_reached (0);
-		}
+	g_return_val_if_fail (source, 0);
 
-		r = sd_event_default (&e);
-		if (r < 0)
-			g_return_val_if_reached (0);
-
-		p_default_source_id = &default_source_id;
-	}
-
-	source = event_create_source (e, p_default_source_id);
 	id = g_source_attach ((GSource *) source, context);
 	g_source_unref ((GSource *) source);
 
-	if (!event) {
-		*p_default_source_id = id;
-		sd_event_unref (e);
-	}
-
-	g_return_val_if_fail (id, 0);
+	nm_assert (id != 0);
 	return id;
 }
 
diff --git a/src/systemd/nm-sd.h b/src/systemd/nm-sd.h
index 07fc2ad4..99904243 100644
--- a/src/systemd/nm-sd.h
+++ b/src/systemd/nm-sd.h
@@ -1,17 +1,5 @@
-/* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2014 - 2016 Red Hat, Inc.
  */
 
diff --git a/src/systemd/sd-adapt-core/nm-sd-adapt-core.c b/src/systemd/sd-adapt-core/nm-sd-adapt-core.c
index c461752e..a9f8bd1c 100644
--- a/src/systemd/sd-adapt-core/nm-sd-adapt-core.c
+++ b/src/systemd/sd-adapt-core/nm-sd-adapt-core.c
@@ -1,17 +1,5 @@
-/* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: GPL-2.0+
+/*
  * Copyright (C) 2014 - 2016 Red Hat, Inc.
  */
 
diff --git a/src/systemd/sd-adapt-core/nm-sd-adapt-core.h b/src/systemd/sd-adapt-core/nm-sd-adapt-core.h
index bd71dd18..81bc7320 100644
--- a/src/systemd/sd-adapt-core/nm-sd-adapt-core.h
+++ b/src/systemd/sd-adapt-core/nm-sd-adapt-core.h
@@ -1,18 +1,5 @@
-/* This program 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 of the License, or (at your option) any later version.
- *
- * This library 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 this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
+// SPDX-License-Identifier: LGPL-2.1+
+/*
  * Copyright (C) 2014 - 2018 Red Hat, Inc.
  */
 
diff --git a/src/systemd/src/libsystemd-network/dhcp-internal.h b/src/systemd/src/libsystemd-network/dhcp-internal.h
index e0269b54..6a803d7b 100644
--- a/src/systemd/src/libsystemd-network/dhcp-internal.h
+++ b/src/systemd/src/libsystemd-network/dhcp-internal.h
@@ -15,11 +15,21 @@
 #include "dhcp-protocol.h"
 #include "socket-util.h"
 
+typedef struct sd_dhcp_option {
+        unsigned n_ref;
+
+        uint8_t option;
+        void *data;
+        size_t length;
+} sd_dhcp_option;
+
+extern const struct hash_ops dhcp_option_hash_ops;
+
 int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
                                  uint32_t xid, const uint8_t *mac_addr,
                                  size_t mac_addr_len, uint16_t arp_type,
                                  uint16_t port);
-int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port);
+int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type);
 int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
                                  const void *packet, size_t len);
 int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
@@ -41,7 +51,7 @@ uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len);
 
 void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
                                    uint16_t source, be32_t destination_addr,
-                                   uint16_t destination, uint16_t len);
+                                   uint16_t destination, uint16_t len, int ip_service_type);
 
 int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port);
 
diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
index 122042ab..a2d0f8bd 100644
--- a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
+++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h
@@ -58,6 +58,9 @@ struct sd_dhcp_lease {
         struct in_addr *ntp;
         size_t ntp_size;
 
+        struct in_addr *sip;
+        size_t sip_size;
+
         struct sd_dhcp_route *static_route;
         size_t static_route_size, static_route_allocated;
 
diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c
index 858fe57c..1f01ece1 100644
--- a/src/systemd/src/libsystemd-network/dhcp-network.c
+++ b/src/systemd/src/libsystemd-network/dhcp-network.c
@@ -11,7 +11,6 @@
 #include <net/if_arp.h>
 #include <stdio.h>
 #include <string.h>
-#include <sys/socket.h>
 #include <linux/filter.h>
 #include <linux/if_infiniband.h>
 #include <linux/if_packet.h>
@@ -148,7 +147,7 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
                                 bcast_addr, &eth_mac, arp_type, dhcp_hlen, port);
 }
 
-int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
+int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
         union sockaddr_union src = {
                 .in.sin_family = AF_INET,
                 .in.sin_port = htobe16(port),
@@ -161,7 +160,11 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
         if (s < 0)
                 return -errno;
 
-        r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6);
+        if (ip_service_type >= 0)
+                r = setsockopt_int(s, IPPROTO_IP, IP_TOS, ip_service_type);
+        else
+                r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6);
+
         if (r < 0)
                 return r;
 
diff --git a/src/systemd/src/libsystemd-network/dhcp-option.c b/src/systemd/src/libsystemd-network/dhcp-option.c
index 50238b0a..49193879 100644
--- a/src/systemd/src/libsystemd-network/dhcp-option.c
+++ b/src/systemd/src/libsystemd-network/dhcp-option.c
@@ -8,10 +8,10 @@
 #include <errno.h>
 #include <stdint.h>
 #include <stdio.h>
-#include <string.h>
 
 #include "alloc-util.h"
 #include "dhcp-internal.h"
+#include "dhcp-server-internal.h"
 #include "memory-util.h"
 #include "strv.h"
 #include "utf8.h"
@@ -29,7 +29,7 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
 
         case SD_DHCP_OPTION_PAD:
         case SD_DHCP_OPTION_END:
-                if (size < *offset + 1)
+                if (*offset + 1 > size)
                         return -ENOBUFS;
 
                 options[*offset] = code;
@@ -37,42 +37,83 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
                 break;
 
         case SD_DHCP_OPTION_USER_CLASS: {
-                size_t len = 0;
+                size_t total = 0;
                 char **s;
 
-                STRV_FOREACH(s, (char **) optval)
-                        len += strlen(*s) + 1;
+                STRV_FOREACH(s, (char **) optval) {
+                        size_t len = strlen(*s);
+
+                        if (len > 255)
+                                return -ENAMETOOLONG;
+
+                        total += 1 + len;
+                }
 
-                if (size < *offset + len + 2)
+                if (*offset + 2 + total > size)
                         return -ENOBUFS;
 
                 options[*offset] = code;
-                options[*offset + 1] =  len;
+                options[*offset + 1] =  total;
                 *offset += 2;
 
                 STRV_FOREACH(s, (char **) optval) {
-                        len = strlen(*s);
-
-                        if (len > 255)
-                                return -ENAMETOOLONG;
+                        size_t len = strlen(*s);
 
                         options[*offset] = len;
 
-                        memcpy_safe(&options[*offset + 1], *s, len);
-                        *offset += len + 1;
+                        memcpy(&options[*offset + 1], *s, len);
+                        *offset += 1 + len;
+                }
+
+                break;
+        }
+        case SD_DHCP_OPTION_SIP_SERVER:
+                if (*offset + 3 + optlen > size)
+                        return -ENOBUFS;
+
+                options[*offset] = code;
+                options[*offset + 1] = optlen + 1;
+                options[*offset + 2] = 1;
+
+                memcpy_safe(&options[*offset + 3], optval, optlen);
+                *offset += 3 + optlen;
+
+                break;
+        case SD_DHCP_OPTION_VENDOR_SPECIFIC: {
+                OrderedHashmap *s = (OrderedHashmap *) optval;
+                struct sd_dhcp_option *p;
+                size_t l = 0;
+                Iterator i;
+
+                ORDERED_HASHMAP_FOREACH(p, s, i)
+                        l += p->length + 2;
+
+                if (*offset + l + 2 > size)
+                        return -ENOBUFS;
+
+                options[*offset] = code;
+                options[*offset + 1] = l;
+
+                *offset += 2;
+
+                ORDERED_HASHMAP_FOREACH(p, s, i) {
+                        options[*offset] = p->option;
+                        options[*offset + 1] = p->length;
+                        memcpy(&options[*offset + 2], p->data, p->length);
+                        *offset += 2 + p->length;
                 }
 
                 break;
         }
         default:
-                if (size < *offset + optlen + 2)
+                if (*offset + 2 + optlen > size)
                         return -ENOBUFS;
 
                 options[*offset] = code;
                 options[*offset + 1] = optlen;
 
                 memcpy_safe(&options[*offset + 2], optval, optlen);
-                *offset += optlen + 2;
+                *offset += 2 + optlen;
 
                 break;
         }
@@ -83,22 +124,25 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
 int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
                        uint8_t overload,
                        uint8_t code, size_t optlen, const void *optval) {
-        size_t file_offset = 0, sname_offset =0;
-        bool file, sname;
+        const bool use_file = overload & DHCP_OVERLOAD_FILE;
+        const bool use_sname = overload & DHCP_OVERLOAD_SNAME;
         int r;
 
         assert(message);
         assert(offset);
 
-        file = overload & DHCP_OVERLOAD_FILE;
-        sname = overload & DHCP_OVERLOAD_SNAME;
+        /* If *offset is in range [0, size), we are writing to ->options,
+         * if *offset is in range [size, size + sizeof(message->file)) and use_file, we are writing to ->file,
+         * if *offset is in range [size + use_file*sizeof(message->file), size + use_file*sizeof(message->file) + sizeof(message->sname))
+         * and use_sname, we are writing to ->sname.
+         */
 
         if (*offset < size) {
                 /* still space in the options array */
                 r = option_append(message->options, size, offset, code, optlen, optval);
                 if (r >= 0)
                         return 0;
-                else if (r == -ENOBUFS && (file || sname)) {
+                else if (r == -ENOBUFS && (use_file || use_sname)) {
                         /* did not fit, but we have more buffers to try
                            close the options array and move the offset to its end */
                         r = option_append(message->options, size, offset, SD_DHCP_OPTION_END, 0, NULL);
@@ -110,8 +154,8 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
                         return r;
         }
 
-        if (overload & DHCP_OVERLOAD_FILE) {
-                file_offset = *offset - size;
+        if (use_file) {
+                size_t file_offset = *offset - size;
 
                 if (file_offset < sizeof(message->file)) {
                         /* still space in the 'file' array */
@@ -119,7 +163,7 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
                         if (r >= 0) {
                                 *offset = size + file_offset;
                                 return 0;
-                        } else if (r == -ENOBUFS && sname) {
+                        } else if (r == -ENOBUFS && use_sname) {
                                 /* did not fit, but we have more buffers to try
                                    close the file array and move the offset to its end */
                                 r = option_append(message->options, size, offset, SD_DHCP_OPTION_END, 0, NULL);
@@ -132,19 +176,18 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
                 }
         }
 
-        if (overload & DHCP_OVERLOAD_SNAME) {
-                sname_offset = *offset - size - (file ? sizeof(message->file) : 0);
+        if (use_sname) {
+                size_t sname_offset = *offset - size - use_file*sizeof(message->file);
 
                 if (sname_offset < sizeof(message->sname)) {
                         /* still space in the 'sname' array */
                         r = option_append(message->sname, sizeof(message->sname), &sname_offset, code, optlen, optval);
                         if (r >= 0) {
-                                *offset = size + (file ? sizeof(message->file) : 0) + sname_offset;
+                                *offset = size + use_file*sizeof(message->file) + sname_offset;
                                 return 0;
-                        } else {
+                        } else
                                 /* no space, or other error, give up */
                                 return r;
-                        }
                 }
         }
 
@@ -274,3 +317,43 @@ int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t c
 
         return message_type;
 }
+
+static sd_dhcp_option* dhcp_option_free(sd_dhcp_option *i) {
+        if (!i)
+                return NULL;
+
+        free(i->data);
+        return mfree(i);
+}
+
+int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret) {
+        assert_return(ret, -EINVAL);
+        assert_return(length == 0 || data, -EINVAL);
+
+        _cleanup_free_ void *q = memdup(data, length);
+        if (!q)
+                return -ENOMEM;
+
+        sd_dhcp_option *p = new(sd_dhcp_option, 1);
+        if (!p)
+                return -ENOMEM;
+
+        *p = (sd_dhcp_option) {
+                .n_ref = 1,
+                .option = option,
+                .length = length,
+                .data = TAKE_PTR(q),
+        };
+
+        *ret = TAKE_PTR(p);
+        return 0;
+}
+
+DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_option, sd_dhcp_option, dhcp_option_free);
+DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
+                dhcp_option_hash_ops,
+                void,
+                trivial_hash_func,
+                trivial_compare_func,
+                sd_dhcp_option,
+                sd_dhcp_option_unref);
diff --git a/src/systemd/src/libsystemd-network/dhcp-packet.c b/src/systemd/src/libsystemd-network/dhcp-packet.c
index 9e565e28..2062be91 100644
--- a/src/systemd/src/libsystemd-network/dhcp-packet.c
+++ b/src/systemd/src/libsystemd-network/dhcp-packet.c
@@ -77,12 +77,15 @@ uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) {
 
 void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
                                    uint16_t source_port, be32_t destination_addr,
-                                   uint16_t destination_port, uint16_t len) {
+                                   uint16_t destination_port, uint16_t len, int ip_service_type) {
         packet->ip.version = IPVERSION;
         packet->ip.ihl = DHCP_IP_SIZE / 4;
         packet->ip.tot_len = htobe16(len);
 
-        packet->ip.tos = IPTOS_CLASS_CS6;
+        if (ip_service_type >= 0)
+                packet->ip.tos = ip_service_type;
+        else
+                packet->ip.tos = IPTOS_CLASS_CS6;
 
         packet->ip.protocol = IPPROTO_UDP;
         packet->ip.saddr = source_addr;
diff --git a/src/systemd/src/libsystemd-network/dhcp6-internal.h b/src/systemd/src/libsystemd-network/dhcp6-internal.h
index f28ba68d..517e357d 100644
--- a/src/systemd/src/libsystemd-network/dhcp6-internal.h
+++ b/src/systemd/src/libsystemd-network/dhcp6-internal.h
@@ -85,7 +85,7 @@ typedef struct DHCP6IA DHCP6IA;
 int dhcp6_option_append(uint8_t **buf, size_t *buflen, 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_pd(uint8_t *buf, size_t len, const DHCP6IA *pd);
+int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix);
 int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn);
 int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
                        size_t *optlen, uint8_t **optvalue);
diff --git a/src/systemd/src/libsystemd-network/dhcp6-network.c b/src/systemd/src/libsystemd-network/dhcp6-network.c
index 73c195a7..d43680a5 100644
--- a/src/systemd/src/libsystemd-network/dhcp6-network.c
+++ b/src/systemd/src/libsystemd-network/dhcp6-network.c
@@ -10,7 +10,6 @@
 #include <netinet/ip6.h>
 #include <stdio.h>
 #include <string.h>
-#include <sys/socket.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <linux/if_packet.h>
diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c
index 562a34b5..bb4c4d91 100644
--- a/src/systemd/src/libsystemd-network/dhcp6-option.c
+++ b/src/systemd/src/libsystemd-network/dhcp6-option.c
@@ -7,7 +7,6 @@
 
 #include <errno.h>
 #include <netinet/in.h>
-#include <string.h>
 
 #include "sd-dhcp6-client.h"
 
@@ -170,9 +169,10 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
         return r;
 }
 
-int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd) {
+int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix) {
         DHCP6Option *option = (DHCP6Option *)buf;
         size_t i = sizeof(*option) + sizeof(pd->ia_pd);
+        DHCP6PDPrefixOption *prefix_opt;
         DHCP6Address *prefix;
 
         assert_return(buf, -EINVAL);
@@ -185,10 +185,7 @@ int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd) {
         option->code = htobe16(SD_DHCP6_OPTION_IA_PD);
 
         memcpy(&option->data, &pd->ia_pd, sizeof(pd->ia_pd));
-
         LIST_FOREACH(addresses, prefix, pd->addresses) {
-                DHCP6PDPrefixOption *prefix_opt;
-
                 if (len < i + sizeof(*prefix_opt))
                         return -ENOBUFS;
 
@@ -196,9 +193,19 @@ int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd) {
                 prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX);
                 prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix));
 
-                memcpy(&prefix_opt->iapdprefix, &prefix->iapdprefix,
-                       sizeof(struct iapdprefix));
+                memcpy(&prefix_opt->iapdprefix, &prefix->iapdprefix, sizeof(struct iapdprefix));
+                i += sizeof(*prefix_opt);
+        }
+
+        if (hint_pd_prefix && hint_pd_prefix->iapdprefix.prefixlen > 0) {
+                if (len < i + sizeof(*prefix_opt))
+                        return -ENOBUFS;
+
+                prefix_opt = (DHCP6PDPrefixOption *)&buf[i];
+                prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX);
+                prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix));
 
+                memcpy(&prefix_opt->iapdprefix, &hint_pd_prefix->iapdprefix, sizeof(struct iapdprefix));
                 i += sizeof(*prefix_opt);
         }
 
diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.c b/src/systemd/src/libsystemd-network/lldp-neighbor.c
index 530af034..238d718b 100644
--- a/src/systemd/src/libsystemd-network/lldp-neighbor.c
+++ b/src/systemd/src/libsystemd-network/lldp-neighbor.c
@@ -10,7 +10,7 @@
 #include "lldp-internal.h"
 #include "lldp-neighbor.h"
 #include "memory-util.h"
-#include "missing.h"
+#include "missing_network.h"
 #include "unaligned.h"
 
 static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash *state) {
diff --git a/src/systemd/src/libsystemd-network/lldp-network.c b/src/systemd/src/libsystemd-network/lldp-network.c
index 5ba9f081..f4764dd1 100644
--- a/src/systemd/src/libsystemd-network/lldp-network.c
+++ b/src/systemd/src/libsystemd-network/lldp-network.c
@@ -7,7 +7,7 @@
 
 #include "fd-util.h"
 #include "lldp-network.h"
-#include "missing.h"
+#include "missing_network.h"
 #include "socket-util.h"
 
 int lldp_network_bind_raw_socket(int ifindex) {
diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c
index 209ce884..7d22e754 100644
--- a/src/systemd/src/libsystemd-network/network-internal.c
+++ b/src/systemd/src/libsystemd-network/network-internal.c
@@ -22,6 +22,7 @@
 #include "parse-util.h"
 #include "siphash24.h"
 #include "socket-util.h"
+#include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
 #include "utf8.h"
@@ -139,15 +140,38 @@ static int net_condition_test_property(char * const *match_property, sd_device *
         return true;
 }
 
+static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = {
+        [NL80211_IFTYPE_ADHOC] = "ad-hoc",
+        [NL80211_IFTYPE_STATION] = "station",
+        [NL80211_IFTYPE_AP] = "ap",
+        [NL80211_IFTYPE_AP_VLAN] = "ap-vlan",
+        [NL80211_IFTYPE_WDS] = "wds",
+        [NL80211_IFTYPE_MONITOR] = "monitor",
+        [NL80211_IFTYPE_MESH_POINT] = "mesh-point",
+        [NL80211_IFTYPE_P2P_CLIENT] = "p2p-client",
+        [NL80211_IFTYPE_P2P_GO] = "p2p-go",
+        [NL80211_IFTYPE_P2P_DEVICE] = "p2p-device",
+        [NL80211_IFTYPE_OCB] = "ocb",
+        [NL80211_IFTYPE_NAN] = "nan",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype);
+
 bool net_match_config(Set *match_mac,
                       char * const *match_paths,
                       char * const *match_drivers,
                       char * const *match_types,
                       char * const *match_names,
                       char * const *match_property,
+                      char * const *match_wifi_iftype,
+                      char * const *match_ssid,
+                      Set *match_bssid,
                       sd_device *device,
                       const struct ether_addr *dev_mac,
-                      const char *dev_name) {
+                      const char *dev_name,
+                      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;
 
@@ -181,6 +205,15 @@ bool net_match_config(Set *match_mac,
         if (!net_condition_test_property(match_property, device))
                 return false;
 
+        if (!net_condition_test_strv(match_wifi_iftype, wifi_iftype_to_string(wifi_iftype)))
+                return false;
+
+        if (!net_condition_test_strv(match_ssid, ssid))
+                return false;
+
+        if (match_bssid && (!bssid || !set_contains(match_bssid, bssid)))
+                return false;
+
         return true;
 }
 
@@ -257,7 +290,7 @@ int config_parse_match_strv(
         for (;;) {
                 _cleanup_free_ char *word = NULL, *k = NULL;
 
-                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
+                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
                 if (r == 0)
                         return 0;
                 if (r == -ENOMEM)
diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h
index 487421fb..2eb0cba5 100644
--- a/src/systemd/src/libsystemd-network/network-internal.h
+++ b/src/systemd/src/libsystemd-network/network-internal.h
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <linux/nl80211.h>
 #include <stdbool.h>
 
 #include "sd-device.h"
@@ -21,9 +22,15 @@ bool net_match_config(Set *match_mac,
                       char * const *match_type,
                       char * const *match_name,
                       char * const *match_property,
+                      char * const *match_wifi_iftype,
+                      char * const *match_ssid,
+                      Set *match_bssid,
                       sd_device *device,
                       const struct ether_addr *dev_mac,
-                      const char *dev_name);
+                      const char *dev_name,
+                      enum nl80211_iftype wifi_iftype,
+                      const char *ssid,
+                      const struct ether_addr *bssid);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_net_condition);
 CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr);
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
index 2f531bc7..0266161d 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
@@ -10,7 +10,6 @@
 #include <net/if_arp.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 #include <sys/ioctl.h>
 #include <linux/if_infiniband.h>
 
@@ -92,6 +91,7 @@ struct sd_dhcp_client {
         usec_t start_time;
         uint64_t attempt;
         uint64_t max_attempts;
+        OrderedHashmap *options;
         usec_t request_sent;
         sd_event_source *timeout_t1;
         sd_event_source *timeout_t2;
@@ -100,6 +100,7 @@ struct sd_dhcp_client {
         void *userdata;
         sd_dhcp_lease *lease;
         usec_t start_delay;
+        int ip_service_type;
 };
 
 static const uint8_t default_req_opts[] = {
@@ -234,6 +235,7 @@ int sd_dhcp_client_set_mac(
 
         DHCP_CLIENT_DONT_DESTROY(client);
         bool need_restart = false;
+        int r;
 
         assert_return(client, -EINVAL);
         assert_return(addr, -EINVAL);
@@ -261,8 +263,11 @@ int sd_dhcp_client_set_mac(
         client->mac_addr_len = addr_len;
         client->arp_type = arp_type;
 
-        if (need_restart && client->state != DHCP_STATE_STOPPED)
-                sd_dhcp_client_start(client);
+        if (need_restart && client->state != DHCP_STATE_STOPPED) {
+                r = sd_dhcp_client_start(client);
+                if (r < 0)
+                        return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m");
+        }
 
         return 0;
 }
@@ -298,6 +303,7 @@ int sd_dhcp_client_set_client_id(
 
         DHCP_CLIENT_DONT_DESTROY(client);
         bool need_restart = false;
+        int r;
 
         assert_return(client, -EINVAL);
         assert_return(data, -EINVAL);
@@ -331,8 +337,11 @@ int sd_dhcp_client_set_client_id(
         memcpy(&client->client_id.raw.data, data, data_len);
         client->client_id_len = data_len + sizeof (client->client_id.type);
 
-        if (need_restart && client->state != DHCP_STATE_STOPPED)
-                sd_dhcp_client_start(client);
+        if (need_restart && client->state != DHCP_STATE_STOPPED) {
+                r = sd_dhcp_client_start(client);
+                if (r < 0)
+                        return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m");
+        }
 
         return 0;
 }
@@ -363,7 +372,7 @@ static int dhcp_client_set_iaid_duid_internal(
         if (duid) {
                 r = dhcp_validate_duid_len(duid_type, duid_len, true);
                 if (r < 0)
-                        return r;
+                        return log_dhcp_client_errno(client, r, "Failed to validate length of DUID: %m");
         }
 
         zero(client->client_id);
@@ -378,7 +387,7 @@ static int dhcp_client_set_iaid_duid_internal(
                                                      true,
                                                      &client->client_id.ns.iaid);
                         if (r < 0)
-                                return r;
+                                return log_dhcp_client_errno(client, r, "Failed to set IAID: %m");
                 }
         }
 
@@ -390,32 +399,32 @@ static int dhcp_client_set_iaid_duid_internal(
                 switch (duid_type) {
                 case DUID_TYPE_LLT:
                         if (client->mac_addr_len == 0)
-                                return -EOPNOTSUPP;
+                                return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set DUID-LLT, MAC address is not set.");
 
                         r = dhcp_identifier_set_duid_llt(&client->client_id.ns.duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &len);
                         if (r < 0)
-                                return r;
+                                return log_dhcp_client_errno(client, r, "Failed to set DUID-LLT: %m");
                         break;
                 case DUID_TYPE_EN:
                         r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len);
                         if (r < 0)
-                                return r;
+                                return log_dhcp_client_errno(client, r, "Failed to set DUID-EN: %m");
                         break;
                 case DUID_TYPE_LL:
                         if (client->mac_addr_len == 0)
-                                return -EOPNOTSUPP;
+                                return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set DUID-LL, MAC address is not set.");
 
                         r = dhcp_identifier_set_duid_ll(&client->client_id.ns.duid, client->mac_addr, client->mac_addr_len, client->arp_type, &len);
                         if (r < 0)
-                                return r;
+                                return log_dhcp_client_errno(client, r, "Failed to set DUID-LL: %m");
                         break;
                 case DUID_TYPE_UUID:
                         r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len);
                         if (r < 0)
-                                return r;
+                                return log_dhcp_client_errno(client, r, "Failed to set DUID-UUID: %m");
                         break;
                 default:
-                        return -EINVAL;
+                        return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "Invalid DUID type");
                 }
 
         client->client_id_len = sizeof(client->client_id.type) + len +
@@ -424,7 +433,9 @@ static int dhcp_client_set_iaid_duid_internal(
         if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
                 log_dhcp_client(client, "Configured %sDUID, restarting.", iaid_append ? "IAID+" : "");
                 client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
-                sd_dhcp_client_start(client);
+                r = sd_dhcp_client_start(client);
+                if (r < 0)
+                        return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m");
         }
 
         return 0;
@@ -534,6 +545,24 @@ 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 r;
+
+        assert_return(client, -EINVAL);
+        assert_return(v, -EINVAL);
+
+        r = ordered_hashmap_ensure_allocated(&client->options, &dhcp_option_hash_ops);
+        if (r < 0)
+                return r;
+
+        r = ordered_hashmap_put(client->options, UINT_TO_PTR(v->option), v);
+        if (r < 0)
+                return r;
+
+        sd_dhcp_option_ref(v);
+        return 0;
+}
+
 int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
         assert_return(client, -EINVAL);
 
@@ -546,6 +575,14 @@ int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
         return 0;
 }
 
+int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) {
+        assert_return(client, -EINVAL);
+
+        client->ip_service_type = type;
+
+        return 0;
+}
+
 static int client_notify(sd_dhcp_client *client, int event) {
         assert(client);
 
@@ -778,7 +815,7 @@ static int dhcp_client_send_raw(
                 size_t len) {
 
         dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port,
-                                      INADDR_BROADCAST, DHCP_PORT_SERVER, len);
+                                      INADDR_BROADCAST, DHCP_PORT_SERVER, len, client->ip_service_type);
 
         return dhcp_network_send_raw_socket(client->fd, &client->link,
                                             packet, len);
@@ -787,6 +824,8 @@ static int dhcp_client_send_raw(
 static int client_send_discover(sd_dhcp_client *client) {
         _cleanup_free_ DHCPPacket *discover = NULL;
         size_t optoffset, optlen;
+        sd_dhcp_option *j;
+        Iterator i;
         int r;
 
         assert(client);
@@ -803,7 +842,9 @@ static int client_send_discover(sd_dhcp_client *client) {
            address be assigned, and may include the ’IP address lease time’
            option to suggest the lease time it would like.
          */
-        if (client->last_addr != INADDR_ANY) {
+        /* RFC7844 section 3:
+           SHOULD NOT contain any other option. */
+        if (!client->anonymize && client->last_addr != INADDR_ANY) {
                 r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
                                        SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
                                        4, &client->last_addr);
@@ -848,6 +889,13 @@ static int client_send_discover(sd_dhcp_client *client) {
                         return r;
         }
 
+        ORDERED_HASHMAP_FOREACH(j, client->options, i) {
+                r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+                                       j->option, j->length, j->data);
+                if (r < 0)
+                        return r;
+        }
+
         r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
                                SD_DHCP_OPTION_END, 0, NULL);
         if (r < 0)
@@ -866,41 +914,6 @@ static int client_send_discover(sd_dhcp_client *client) {
         return 0;
 }
 
-static int client_send_release(sd_dhcp_client *client) {
-        _cleanup_free_ DHCPPacket *release = NULL;
-        size_t optoffset, optlen;
-        int r;
-
-        assert(client);
-        assert(!IN_SET(client->state, DHCP_STATE_STOPPED));
-
-        r = client_message_init(client, &release, DHCP_RELEASE,
-                                &optlen, &optoffset);
-        if (r < 0)
-                return r;
-
-        /* Fill up release IP and MAC */
-        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, "RELEASE");
-
-        return 0;
-}
-
 static int client_send_request(sd_dhcp_client *client) {
         _cleanup_free_ DHCPPacket *request = NULL;
         size_t optoffset, optlen;
@@ -1000,15 +1013,14 @@ static int client_send_request(sd_dhcp_client *client) {
         if (r < 0)
                 return r;
 
-        if (client->state == DHCP_STATE_RENEWING) {
+        if (client->state == DHCP_STATE_RENEWING)
                 r = dhcp_network_send_udp_socket(client->fd,
                                                  client->lease->server_address,
                                                  DHCP_PORT_SERVER,
                                                  &request->dhcp,
                                                  sizeof(DHCPMessage) + optoffset);
-        } else {
+        else
                 r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
-        }
         if (r < 0)
                 return r;
 
@@ -1216,7 +1228,7 @@ static int client_initialize_time_events(sd_dhcp_client *client) {
         assert(client);
         assert(client->event);
 
-        if (client->start_delay) {
+        if (client->start_delay > 0) {
                 assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0);
                 usec += client->start_delay;
         }
@@ -1667,7 +1679,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
                                 goto error;
                         }
 
-                        r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port);
+                        r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port, client->ip_service_type);
                         if (r < 0) {
                                 log_dhcp_client(client, "could not bind UDP socket");
                                 goto error;
@@ -1887,6 +1899,17 @@ static int client_receive_message_raw(
         return client_handle_message(client, &packet->dhcp, len);
 }
 
+int sd_dhcp_client_send_renew(sd_dhcp_client *client) {
+        assert_return(client, -EINVAL);
+        assert_return(client->fd >= 0, -EINVAL);
+
+        client->start_delay = 0;
+        client->attempt = 1;
+        client->state = DHCP_STATE_RENEWING;
+
+        return client_initialize_time_events(client);
+}
+
 int sd_dhcp_client_start(sd_dhcp_client *client) {
         int r;
 
@@ -1915,8 +1938,35 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
 
 int sd_dhcp_client_send_release(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_RELEASE, &optlen, &optoffset);
+        if (r < 0)
+                return r;
+
+        /* Fill up release IP and MAC */
+        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;
 
-        client_send_release(client);
+        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, "RELEASE");
 
         return 0;
 }
@@ -1966,7 +2016,8 @@ sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
 }
 
 static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
-        assert(client);
+        if (!client)
+                return NULL;
 
         log_dhcp_client(client, "FREE");
 
@@ -1985,17 +2036,16 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
         free(client->hostname);
         free(client->vendor_class_identifier);
         client->user_class = strv_free(client->user_class);
+        ordered_hashmap_free(client->options);
         return mfree(client);
 }
 
 DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free);
 
 int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
-        _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL;
-
         assert_return(ret, -EINVAL);
 
-        client = new(sd_dhcp_client, 1);
+        _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = new(sd_dhcp_client, 1);
         if (!client)
                 return -ENOMEM;
 
@@ -2008,6 +2058,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
                 .port = DHCP_PORT_CLIENT,
                 .anonymize = !!anonymize,
                 .max_attempts = (uint64_t) -1,
+                .ip_service_type = -1,
         };
         /* NOTE: this could be moved to a function. */
         if (anonymize) {
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
index 7559d066..ac6fe3f4 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
@@ -7,9 +7,7 @@
 
 #include <arpa/inet.h>
 #include <errno.h>
-#include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -122,6 +120,17 @@ int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
         return (int) lease->ntp_size;
 }
 
+int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr) {
+        assert_return(lease, -EINVAL);
+        assert_return(addr, -EINVAL);
+
+        if (lease->sip_size <= 0)
+                return -ENODATA;
+
+        *addr = lease->sip;
+        return (int) lease->sip_size;
+}
+
 int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
         assert_return(lease, -EINVAL);
         assert_return(domainname, -EINVAL);
@@ -271,6 +280,7 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
         free(lease->domainname);
         free(lease->dns);
         free(lease->ntp);
+        free(lease->sip);
         free(lease->static_route);
         free(lease->client_id);
         free(lease->vendor_specific);
@@ -404,6 +414,36 @@ static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_add
         return 0;
 }
 
+static int lease_parse_sip_server(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
+        assert(option);
+        assert(ret);
+        assert(n_ret);
+
+        if (len <= 0) {
+                *ret = mfree(*ret);
+                *n_ret = 0;
+        } else {
+                size_t n_addresses;
+                struct in_addr *addresses;
+                int l = len - 1;
+
+                if (l % 4 != 0)
+                        return -EINVAL;
+
+                n_addresses = l / 4;
+
+                addresses = newdup(struct in_addr, option + 1, n_addresses);
+                if (!addresses)
+                        return -ENOMEM;
+
+                free(*ret);
+                *ret = addresses;
+                *n_ret = n_addresses;
+        }
+
+        return 0;
+}
+
 static int lease_parse_routes(
                 const uint8_t *option, size_t len,
                 struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) {
@@ -557,6 +597,12 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
                         log_debug_errno(r, "Failed to parse NTP server, ignoring: %m");
                 break;
 
+        case SD_DHCP_OPTION_SIP_SERVER:
+                r = lease_parse_sip_server(option, len, &lease->sip, &lease->sip_size);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to parse SIP 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)
@@ -895,6 +941,13 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
                 fputc('\n', f);
         }
 
+        r = sd_dhcp_lease_get_sip(lease, &addresses);
+        if (r > 0) {
+                fputs("SIP=", f);
+                serialize_in_addrs(f, addresses, r, false, NULL);
+                fputc('\n', f);
+        }
+
         r = sd_dhcp_lease_get_domainname(lease, &string);
         if (r >= 0)
                 fprintf(f, "DOMAINNAME=%s\n", string);
@@ -985,6 +1038,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
                 *broadcast = NULL,
                 *dns = NULL,
                 *ntp = NULL,
+                *sip = NULL,
                 *mtu = NULL,
                 *routes = NULL,
                 *domains = NULL,
@@ -1013,6 +1067,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
                            "BROADCAST", &broadcast,
                            "DNS", &dns,
                            "NTP", &ntp,
+                           "SIP", &sip,
                            "MTU", &mtu,
                            "DOMAINNAME", &lease->domainname,
                            "HOSTNAME", &lease->hostname,
@@ -1117,6 +1172,14 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
                         lease->ntp_size = r;
         }
 
+        if (sip) {
+                r = deserialize_in_addrs(&lease->sip, sip);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to deserialize SIP servers %s, ignoring: %m", sip);
+                else
+                        lease->ntp_size = r;
+        }
+
         if (mtu) {
                 r = safe_atou16(mtu, &lease->mtu);
                 if (r < 0)
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
index f67a45bd..e1150f98 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
@@ -6,7 +6,6 @@
 #include "nm-sd-adapt-core.h"
 
 #include <errno.h>
-#include <string.h>
 #include <sys/ioctl.h>
 #include <linux/if_arp.h>
 #include <linux/if_infiniband.h>
@@ -31,6 +30,9 @@
 
 #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
 
+#define IRT_DEFAULT (1 * USEC_PER_DAY)
+#define IRT_MINIMUM (600 * USEC_PER_SEC)
+
 /* what to request from the server, addresses (IA_NA) and/or prefixes (IA_PD) */
 enum {
         DHCP6_REQUEST_IA_NA                     = 1,
@@ -45,6 +47,7 @@ struct sd_dhcp6_client {
         sd_event *event;
         int event_priority;
         int ifindex;
+        DHCP6Address hint_pd_prefix;
         struct in6_addr local_address;
         uint8_t mac_addr[MAX_MAC_ADDR_LEN];
         size_t mac_addr_len;
@@ -73,6 +76,8 @@ struct sd_dhcp6_client {
         void *userdata;
         struct duid duid;
         size_t duid_len;
+        usec_t information_request_time_usec;
+        usec_t information_refresh_time_usec;
 };
 
 static const uint16_t default_req_opts[] = {
@@ -184,6 +189,22 @@ int sd_dhcp6_client_set_mac(
         return 0;
 }
 
+int sd_dhcp6_client_set_prefix_delegation_hint(
+                sd_dhcp6_client *client,
+                uint8_t prefixlen,
+                const struct in6_addr *pd_address) {
+
+        assert_return(client, -EINVAL);
+        assert_return(pd_address, -EINVAL);
+
+        assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+
+        client->hint_pd_prefix.iapdprefix.address = *pd_address;
+        client->hint_pd_prefix.iapdprefix.prefixlen = prefixlen;
+
+        return 0;
+}
+
 static int client_ensure_duid(sd_dhcp6_client *client) {
         if (client->duid_len != 0)
                 return 0;
@@ -213,7 +234,7 @@ static int dhcp6_client_set_duid_internal(
                 if (r < 0) {
                         r = dhcp_validate_duid_len(duid_type, duid_len, false);
                         if (r < 0)
-                                return r;
+                                return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m");
                         log_dhcp6_client(client, "Setting DUID of type %u with unexpected content", duid_type);
                 }
 
@@ -225,32 +246,32 @@ static int dhcp6_client_set_duid_internal(
                 switch (duid_type) {
                 case DUID_TYPE_LLT:
                         if (client->mac_addr_len == 0)
-                                return -EOPNOTSUPP;
+                                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set DUID-LLT, MAC address is not set.");
 
                         r = dhcp_identifier_set_duid_llt(&client->duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len);
                         if (r < 0)
-                                return r;
+                                return log_dhcp6_client_errno(client, r, "Failed to set DUID-LLT: %m");
                         break;
                 case DUID_TYPE_EN:
                         r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
                         if (r < 0)
-                                return r;
+                                return log_dhcp6_client_errno(client, r, "Failed to set DUID-EN: %m");
                         break;
                 case DUID_TYPE_LL:
                         if (client->mac_addr_len == 0)
-                                return -EOPNOTSUPP;
+                                return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set DUID-LL, MAC address is not set.");
 
                         r = dhcp_identifier_set_duid_ll(&client->duid, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len);
                         if (r < 0)
-                                return r;
+                                return log_dhcp6_client_errno(client, r, "Failed to set DUID-LL: %m");
                         break;
                 case DUID_TYPE_UUID:
                         r = dhcp_identifier_set_duid_uuid(&client->duid, &client->duid_len);
                         if (r < 0)
-                                return r;
+                                return log_dhcp6_client_errno(client, r, "Failed to set DUID-UUID: %m");
                         break;
                 default:
-                        return -EINVAL;
+                        return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "Invalid DUID type");
                 }
 #else /* NM_IGNORED */
                 g_return_val_if_reached (-EINVAL);
@@ -493,7 +514,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                 }
 
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
-                        r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd);
+                        r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix);
                         if (r < 0)
                                 return r;
 
@@ -531,7 +552,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                 }
 
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
-                        r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
+                        r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
                         if (r < 0)
                                 return r;
 
@@ -557,7 +578,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
                 }
 
                 if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
-                        r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd);
+                        r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL);
                         if (r < 0)
                                 return r;
 
@@ -826,6 +847,7 @@ static int client_parse_message(
         uint32_t lt_t1 = ~0, lt_t2 = ~0;
         bool clientid = false;
         size_t pos = 0;
+        usec_t irt = IRT_DEFAULT;
         int r;
 
         assert(client);
@@ -1000,6 +1022,13 @@ static int client_parse_message(
                                 return r;
 
                         break;
+
+                case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME:
+                        if (optlen != 4)
+                                return -EINVAL;
+
+                        irt = unaligned_read_be32((be32_t *) optval) * USEC_PER_SEC;
+                        break;
                 }
 
                 pos += offsetof(DHCP6Option, data) + optlen;
@@ -1031,6 +1060,8 @@ static int client_parse_message(
                 }
         }
 
+        client->information_refresh_time_usec = MAX(irt, IRT_MINIMUM);
+
         return 0;
 }
 
@@ -1431,8 +1462,15 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
                 client->fd = r;
         }
 
-        if (client->information_request)
+        if (client->information_request) {
+                usec_t t = now(CLOCK_MONOTONIC);
+
+                if (t < usec_add(client->information_request_time_usec, client->information_refresh_time_usec))
+                        return 0;
+
+                client->information_request_time_usec = t;
                 state = DHCP6_STATE_INFORMATION_REQUEST;
+        }
 
         log_dhcp6_client(client, "Started in %s mode",
                          client->information_request? "Information request":
@@ -1521,6 +1559,8 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
                 .request = DHCP6_REQUEST_IA_NA,
                 .fd = -1,
                 .req_opts_len = ELEMENTSOF(default_req_opts),
+                .hint_pd_prefix.iapdprefix.lifetime_preferred = (be32_t) -1,
+                .hint_pd_prefix.iapdprefix.lifetime_valid = (be32_t) -1,
                 .req_opts = TAKE_PTR(req_opts),
         };
 
diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c
index e7561480..3efa8170 100644
--- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c
+++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c
@@ -10,7 +10,6 @@
 #include <netinet/if_ether.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 
 #include "sd-ipv4acd.h"
 
diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c
index daac8839..2d17b4fe 100644
--- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c
@@ -9,7 +9,6 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 
 #include "sd-id128.h"
 #include "sd-ipv4acd.h"
diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c
index c3781706..7c4566e3 100644
--- a/src/systemd/src/libsystemd/sd-event/sd-event.c
+++ b/src/systemd/src/libsystemd/sd-event/sd-event.c
@@ -18,7 +18,7 @@
 #include "list.h"
 #include "macro.h"
 #include "memory-util.h"
-#include "missing.h"
+#include "missing_syscall.h"
 #include "prioq.h"
 #include "process-util.h"
 #include "set.h"
@@ -773,11 +773,13 @@ static void source_disconnect(sd_event_source *s) {
 
         event = s->event;
 
-        s->type = _SOURCE_EVENT_SOURCE_TYPE_INVALID;
         s->event = NULL;
         LIST_REMOVE(sources, event->sources, s);
         event->n_sources--;
 
+        /* Note that we don't invalidate the type here, since we still need it in order to close the fd or
+         * pidfd associated with this event source, which we'll do only on source_free(). */
+
         if (!s->floating)
                 sd_event_unref(event);
 }
@@ -2556,7 +2558,7 @@ static int process_child(sd_event *e) {
                                  * benefit in leaving it queued */
 
                                 assert(s->child.options & (WSTOPPED|WCONTINUED));
-                                waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED)));
+                                (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED)));
                         }
 
                         r = source_set_pending(s, true);
diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
index eeb29e97..c0d0fe81 100644
--- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
@@ -15,7 +15,7 @@
 #include "io-util.h"
 #include "khash.h"
 #include "macro.h"
-#include "missing.h"
+#include "missing_syscall.h"
 #include "random-util.h"
 #include "user-util.h"
 #include "util.h"
diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h
index ab62368e..f97e35b6 100644
--- a/src/systemd/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/src/systemd/sd-dhcp-client.h
@@ -26,6 +26,7 @@
 #include <stdbool.h>
 
 #include "sd-dhcp-lease.h"
+#include "sd-dhcp-option.h"
 #include "sd-event.h"
 
 #include "_sd-common.h"
@@ -87,6 +88,7 @@ enum {
         SD_DHCP_OPTION_NEW_POSIX_TIMEZONE          = 100,
         SD_DHCP_OPTION_NEW_TZDB_TIMEZONE           = 101,
         SD_DHCP_OPTION_DOMAIN_SEARCH_LIST          = 119,
+        SD_DHCP_OPTION_SIP_SERVER                  = 120,
         SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE      = 121,
         SD_DHCP_OPTION_PRIVATE_BASE                = 224,
        /* Windows 10 option to send when Anonymize=true */
@@ -173,10 +175,16 @@ int sd_dhcp_client_set_user_class(
 int sd_dhcp_client_get_lease(
                 sd_dhcp_client *client,
                 sd_dhcp_lease **ret);
+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_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_renew(sd_dhcp_client *client);
 
 sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client);
 sd_dhcp_client *sd_dhcp_client_unref(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 d299c791..b80d607f 100644
--- a/src/systemd/src/systemd/sd-dhcp-lease.h
+++ b/src/systemd/src/systemd/sd-dhcp-lease.h
@@ -44,6 +44,7 @@ int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr);
 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr);
 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_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-dhcp-option.h b/src/systemd/src/systemd/sd-dhcp-option.h
new file mode 100644
index 00000000..45dbd279
--- /dev/null
+++ b/src/systemd/src/systemd/sd-dhcp-option.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#ifndef foosddhcpoptionhfoo
+#define foosddhcpoptionhfoo
+
+/***
+  Copyright © 2013 Intel Corporation. All rights reserved.
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
+typedef struct sd_dhcp_option sd_dhcp_option;
+
+int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret);
+sd_dhcp_option *sd_dhcp_option_ref(sd_dhcp_option *ra);
+sd_dhcp_option *sd_dhcp_option_unref(sd_dhcp_option *ra);
+
+_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_option, sd_dhcp_option_unref);
+
+_SD_END_DECLARATIONS;
+
+#endif
diff --git a/src/systemd/src/systemd/sd-dhcp6-client.h b/src/systemd/src/systemd/sd-dhcp6-client.h
index 43d38f5c..be34d43e 100644
--- a/src/systemd/src/systemd/sd-dhcp6-client.h
+++ b/src/systemd/src/systemd/sd-dhcp6-client.h
@@ -66,6 +66,7 @@ enum {
         SD_DHCP6_OPTION_IA_PD_PREFIX               = 26,  /* RFC 3633, prefix delegation */
 
         SD_DHCP6_OPTION_SNTP_SERVERS               = 31,  /* RFC 4075, deprecated */
+        SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME   = 32,  /* RFC 8415, sec. 21.23 */
 
         /* option code 35 is unassigned */
 
@@ -119,6 +120,10 @@ 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_prefix_delegation_hint(
+                sd_dhcp6_client *client,
+                uint8_t prefixlen,
+                const struct in6_addr *pd_address);
 int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client,
                                           int *delegation);
 int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client,