summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2022-01-24 20:34:37 +0100
committerThomas Haller <thaller@redhat.com>2022-02-03 18:50:26 +0100
commit18cb8205b34b7e4ed6ccf73a5de3c9c6601f9c86 (patch)
treebe970dfbb3ae40840b6d4d3163a897c1c3fcf7e2
parent3399e19df89118cd23270cccad2557844aa16ae5 (diff)
parenta4ff07aaad3de9a0707a0220adf4091b8e2fe678 (diff)
downloadNetworkManager-18cb8205b34b7e4ed6ccf73a5de3c9c6601f9c86.tar.gz
systemd: merge branch systemd into main
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1068
-rw-r--r--Makefile.am5
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/arp-util.c34
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/arp-util.h4
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c6
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h4
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h6
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c66
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c33
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h8
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-lease-internal.h16
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c4
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c189
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h120
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c50
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/lldp-network.c21
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/network-common.h4
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c61
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c96
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c316
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c103
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c29
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h6
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c24
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h26
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c204
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c2
-rw-r--r--src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c43
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-dhcp-client.h117
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h7
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h169
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h4
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-event.h2
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-ndisc.h3
-rw-r--r--src/libnm-systemd-shared/sd-adapt-shared/filesystems.h3
-rw-r--r--src/libnm-systemd-shared/sd-adapt-shared/hmac.h3
-rw-r--r--src/libnm-systemd-shared/sd-adapt-shared/missing_magic.h2
-rw-r--r--src/libnm-systemd-shared/sd-adapt-shared/netif-util.h3
-rw-r--r--src/libnm-systemd-shared/src/basic/alloc-util.h51
-rw-r--r--src/libnm-systemd-shared/src/basic/cgroup-util.h28
-rw-r--r--src/libnm-systemd-shared/src/basic/env-util.c22
-rw-r--r--src/libnm-systemd-shared/src/basic/errno-util.h38
-rw-r--r--src/libnm-systemd-shared/src/basic/escape.c6
-rw-r--r--src/libnm-systemd-shared/src/basic/escape.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/ether-addr-util.c216
-rw-r--r--src/libnm-systemd-shared/src/basic/ether-addr-util.h56
-rw-r--r--src/libnm-systemd-shared/src/basic/fd-util.c261
-rw-r--r--src/libnm-systemd-shared/src/basic/fd-util.h15
-rw-r--r--src/libnm-systemd-shared/src/basic/fileio.c24
-rw-r--r--src/libnm-systemd-shared/src/basic/fileio.h5
-rw-r--r--src/libnm-systemd-shared/src/basic/format-util.h8
-rw-r--r--src/libnm-systemd-shared/src/basic/fs-util.c188
-rw-r--r--src/libnm-systemd-shared/src/basic/fs-util.h6
-rw-r--r--src/libnm-systemd-shared/src/basic/hostname-util.c3
-rw-r--r--src/libnm-systemd-shared/src/basic/hostname-util.h7
-rw-r--r--src/libnm-systemd-shared/src/basic/in-addr-util.c125
-rw-r--r--src/libnm-systemd-shared/src/basic/in-addr-util.h12
-rw-r--r--src/libnm-systemd-shared/src/basic/inotify-util.c18
-rw-r--r--src/libnm-systemd-shared/src/basic/list.h11
-rw-r--r--src/libnm-systemd-shared/src/basic/log.h9
-rw-r--r--src/libnm-systemd-shared/src/basic/macro.h27
-rw-r--r--src/libnm-systemd-shared/src/basic/missing_syscall.h66
-rw-r--r--src/libnm-systemd-shared/src/basic/parse-util.c6
-rw-r--r--src/libnm-systemd-shared/src/basic/path-util.c38
-rw-r--r--src/libnm-systemd-shared/src/basic/process-util.c156
-rw-r--r--src/libnm-systemd-shared/src/basic/process-util.h47
-rw-r--r--src/libnm-systemd-shared/src/basic/random-util.c18
-rw-r--r--src/libnm-systemd-shared/src/basic/signal-util.c20
-rw-r--r--src/libnm-systemd-shared/src/basic/socket-util.c60
-rw-r--r--src/libnm-systemd-shared/src/basic/socket-util.h5
-rw-r--r--src/libnm-systemd-shared/src/basic/sort-util.h22
-rw-r--r--src/libnm-systemd-shared/src/basic/sparse-endian.h12
-rw-r--r--src/libnm-systemd-shared/src/basic/stat-util.c51
-rw-r--r--src/libnm-systemd-shared/src/basic/string-util.h4
-rw-r--r--src/libnm-systemd-shared/src/basic/strv.c88
-rw-r--r--src/libnm-systemd-shared/src/basic/strv.h52
-rw-r--r--src/libnm-systemd-shared/src/basic/strxcpyx.c67
-rw-r--r--src/libnm-systemd-shared/src/basic/strxcpyx.h33
-rw-r--r--src/libnm-systemd-shared/src/basic/time-util.c12
-rw-r--r--src/libnm-systemd-shared/src/basic/tmpfile-util.c25
-rw-r--r--src/libnm-systemd-shared/src/basic/umask-util.h3
-rw-r--r--src/libnm-systemd-shared/src/basic/user-util.h6
-rw-r--r--src/libnm-systemd-shared/src/basic/utf8.c39
-rw-r--r--src/libnm-systemd-shared/src/basic/utf8.h2
-rw-r--r--src/libnm-systemd-shared/src/basic/util.c66
-rw-r--r--src/libnm-systemd-shared/src/basic/util.h36
-rw-r--r--src/libnm-systemd-shared/src/fundamental/macro-fundamental.h72
-rw-r--r--src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c8
-rw-r--r--src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h4
-rw-r--r--src/libnm-systemd-shared/src/fundamental/type.h22
-rw-r--r--src/libnm-systemd-shared/src/fundamental/types-fundamental.h39
-rw-r--r--src/libnm-systemd-shared/src/shared/dns-domain.c4
-rw-r--r--src/libnm-systemd-shared/src/shared/dns-domain.h4
92 files changed, 2709 insertions, 1309 deletions
diff --git a/Makefile.am b/Makefile.am
index 7a1616d50f..ed4ffb0455 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2122,8 +2122,10 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
src/libnm-systemd-shared/sd-adapt-shared/dhcp-server-internal.h \
src/libnm-systemd-shared/sd-adapt-shared/dirent-util.h \
src/libnm-systemd-shared/sd-adapt-shared/errno-list.h \
+ src/libnm-systemd-shared/sd-adapt-shared/filesystems.h \
src/libnm-systemd-shared/sd-adapt-shared/glob-util.h \
src/libnm-systemd-shared/sd-adapt-shared/gunicode.h \
+ src/libnm-systemd-shared/sd-adapt-shared/hmac.h \
src/libnm-systemd-shared/sd-adapt-shared/idn-util.h \
src/libnm-systemd-shared/sd-adapt-shared/ioprio.h \
src/libnm-systemd-shared/sd-adapt-shared/locale-util.h \
@@ -2138,6 +2140,7 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
src/libnm-systemd-shared/sd-adapt-shared/missing_timerfd.h \
src/libnm-systemd-shared/sd-adapt-shared/mkdir.h \
src/libnm-systemd-shared/sd-adapt-shared/namespace-util.h \
+ src/libnm-systemd-shared/sd-adapt-shared/netif-util.h \
src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h \
src/libnm-systemd-shared/sd-adapt-shared/nulstr-util.h \
src/libnm-systemd-shared/sd-adapt-shared/os-util.h \
@@ -2245,7 +2248,7 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
src/libnm-systemd-shared/src/fundamental/macro-fundamental.h \
src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c \
src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h \
- src/libnm-systemd-shared/src/fundamental/type.h \
+ src/libnm-systemd-shared/src/fundamental/types-fundamental.h \
src/libnm-systemd-shared/src/shared/dns-domain.c \
src/libnm-systemd-shared/src/shared/dns-domain.h \
src/libnm-systemd-shared/src/shared/log-link.h \
diff --git a/src/libnm-systemd-core/src/libsystemd-network/arp-util.c b/src/libnm-systemd-core/src/libsystemd-network/arp-util.c
index 46c4a8cb0b..c8a73111b5 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/arp-util.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/arp-util.c
@@ -16,7 +16,7 @@
#include "unaligned.h"
#include "util.h"
-int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *eth_mac) {
+int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *mac) {
struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */
@@ -38,30 +38,21 @@ int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), /* protocol == reply ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
/* Sender Hardware Address must be different from our own */
- BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(&eth_mac->ether_addr_octet[0])),/* A <- 4 bytes of client's MAC */
- BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(&mac->ether_addr_octet[0])), /* X <- 4 bytes of client's MAC */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_sha)), /* A <- 4 bytes of SHA */
- BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 6), /* A == 0 ? */
- BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be16(&eth_mac->ether_addr_octet[4])),/* A <- remainder of client's MAC */
- BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 4), /* A == X ? */
+ BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(&mac->ether_addr_octet[4])), /* X <- remainder of client's MAC */
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, arp_sha) + 4), /* A <- remainder of SHA */
- BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == X ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
/* Sender Protocol Address or Target Protocol Address must be equal to the one we care about */
- BPF_STMT(BPF_LD + BPF_IMM, htobe32(a->s_addr)), /* A <- clients IP */
- BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_LDX + BPF_IMM, htobe32(a->s_addr)), /* X <- clients IP */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_spa)), /* A <- SPA */
- BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
- BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
- BPF_STMT(BPF_LD + BPF_IMM, htobe32(a->s_addr)), /* A <- clients IP */
- BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == X ? */
+ BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_tpa)), /* A <- TPA */
- BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
- BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == 0 ? */
+ BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
};
struct sock_fprog fprog = {
@@ -77,7 +68,7 @@ int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *
return 0;
}
-int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *eth_mac) {
+int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *mac) {
union sockaddr_union link = {
.ll.sll_family = AF_PACKET,
.ll.sll_protocol = htobe16(ETH_P_ARP),
@@ -89,12 +80,13 @@ int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const stru
int r;
assert(ifindex > 0);
+ assert(mac);
s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (s < 0)
return -errno;
- r = arp_update_filter(s, a, eth_mac);
+ r = arp_update_filter(s, a, mac);
if (r < 0)
return r;
diff --git a/src/libnm-systemd-core/src/libsystemd-network/arp-util.h b/src/libnm-systemd-core/src/libsystemd-network/arp-util.h
index e8615a158d..b66a81bf9b 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/arp-util.h
+++ b/src/libnm-systemd-core/src/libsystemd-network/arp-util.h
@@ -11,8 +11,8 @@
#include "socket-util.h"
#include "sparse-endian.h"
-int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *eth_mac);
-int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *eth_mac);
+int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *mac);
+int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *mac);
int arp_send_packet(
int fd,
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c
index bd47ff41ef..74aa19de64 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c
@@ -11,7 +11,7 @@
#include "dhcp-identifier.h"
#include "dhcp6-protocol.h"
-#include "network-util.h"
+#include "netif-util.h"
#include "siphash24.h"
#include "sparse-endian.h"
#include "stat-util.h"
@@ -200,7 +200,7 @@ int dhcp_identifier_set_iaid(
/* device is under renaming */
return -EBUSY;
- name = net_get_name_persistent(device);
+ name = net_get_persistent_name(device);
}
if (name)
@@ -214,7 +214,7 @@ int dhcp_identifier_set_iaid(
if (legacy_unstable_byteorder)
/* for historical reasons (a bug), the bits were swapped and thus
* the result was endianness dependent. Preserve that behavior. */
- id32 = __bswap_32(id32);
+ id32 = bswap_32(id32);
else
/* the fixed behavior returns a stable byte order. Since LE is expected
* to be more common, swap the bytes on LE to give the same as legacy
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h
index 6538f05bdb..466d8e4b3f 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h
@@ -53,8 +53,8 @@ typedef int (*dhcp_option_callback_t)(uint8_t code, uint8_t len,
int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **error_message);
int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
- uint8_t type, uint16_t arp_type, size_t optlen,
- size_t *optoffset);
+ uint8_t type, uint16_t arp_type, uint8_t hlen, const uint8_t *chaddr,
+ size_t optlen, size_t *optoffset);
uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h
index 35a74dd7c2..992ac9f325 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h
@@ -70,6 +70,12 @@ struct sd_dhcp_lease {
char *timezone;
+ uint8_t sixrd_ipv4masklen;
+ uint8_t sixrd_prefixlen;
+ struct in6_addr sixrd_prefix;
+ struct in_addr *sixrd_br_addresses;
+ size_t sixrd_n_br_addresses;
+
LIST_HEAD(struct sd_dhcp_raw_option, private_options);
};
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c
index bbfdeb0f8c..1c5f342754 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c
@@ -60,24 +60,20 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
/* We only support MAC address length to be either 0 or 6 (ETH_ALEN). Optionally
* compare chaddr for ETH_ALEN bytes. */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 12), /* A (the MAC address length) == ETH_ALEN ? */
- BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(&eth_mac->ether_addr_octet[0])), /* A <- 4 bytes of client's MAC */
- BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 8), /* A (the MAC address length) == ETH_ALEN ? */
+ BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(&eth_mac->ether_addr_octet[0])), /* X <- 4 bytes of client's MAC */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */
- BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be16(&eth_mac->ether_addr_octet[4])), /* A <- remainder of client's MAC */
- BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(&eth_mac->ether_addr_octet[4])), /* X <- remainder of client's MAC */
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4), /* A <- remainder of MAC from dhcp.chaddr */
- BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)), /* A <- DHCP magic cookie */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0), /* cookie == DHCP magic cookie ? */
BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
+ BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */
};
struct sock_fprog fprog = {
.len = ELEMENTSOF(filter),
@@ -117,10 +113,17 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
return TAKE_FD(s);
}
-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,
- const uint8_t *bcast_addr, size_t bcast_addr_len,
- uint16_t arp_type, uint16_t port) {
+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,
+ const uint8_t *bcast_addr,
+ size_t bcast_addr_len,
+ uint16_t arp_type,
+ uint16_t port) {
+
static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
/* Default broadcast address for IPoIB */
static const uint8_t ib_bcast[] = {
@@ -174,7 +177,6 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int
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;
@@ -206,43 +208,49 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int
return r;
}
- r = bind(s, &src.sa, sizeof(src.in));
- if (r < 0)
+ if (bind(s, &src.sa, sizeof(src.in)) < 0)
return -errno;
return TAKE_FD(s);
}
-int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
- const void *packet, size_t len) {
- int r;
+int dhcp_network_send_raw_socket(
+ int s,
+ const union sockaddr_union *link,
+ const void *packet,
+ size_t len) {
+
+ /* Do not add assert(s >= 0) here, as this is called in fuzz-dhcp-server, and in that case this
+ * function should fail with negative errno. */
assert(link);
assert(packet);
- assert(len);
+ assert(len > 0);
- r = sendto(s, packet, len, 0, &link->sa, SOCKADDR_LL_LEN(link->ll));
- if (r < 0)
+ if (sendto(s, packet, len, 0, &link->sa, SOCKADDR_LL_LEN(link->ll)) < 0)
return -errno;
return 0;
}
-int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
- const void *packet, size_t len) {
+int dhcp_network_send_udp_socket(
+ int s,
+ be32_t address,
+ uint16_t port,
+ const void *packet,
+ size_t len) {
+
union sockaddr_union dest = {
.in.sin_family = AF_INET,
.in.sin_port = htobe16(port),
.in.sin_addr.s_addr = address,
};
- int r;
assert(s >= 0);
assert(packet);
- assert(len);
+ assert(len > 0);
- r = sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in));
- if (r < 0)
+ if (sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in)) < 0)
return -errno;
return 0;
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c
index eeadd5628b..25a69a616e 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c
@@ -12,21 +12,44 @@
#include "dhcp-internal.h"
#include "dhcp-protocol.h"
+#include "memory-util.h"
#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312
-int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
- uint8_t type, uint16_t arp_type, size_t optlen,
- size_t *optoffset) {
+int dhcp_message_init(
+ DHCPMessage *message,
+ uint8_t op,
+ uint32_t xid,
+ uint8_t type,
+ uint16_t arp_type,
+ uint8_t hlen,
+ const uint8_t *chaddr,
+ size_t optlen,
+ size_t *optoffset) {
+
size_t offset = 0;
int r;
assert(IN_SET(op, BOOTREQUEST, BOOTREPLY));
- assert(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND));
+ assert(chaddr || hlen == 0);
message->op = op;
message->htype = arp_type;
- message->hlen = (arp_type == ARPHRD_ETHER) ? ETHER_ADDR_LEN : 0;
+
+ /* RFC2131 section 4.1.1:
+ The client MUST include its hardware address in the ’chaddr’ field, if
+ necessary for delivery of DHCP reply messages.
+
+ RFC 4390 section 2.1:
+ A DHCP client, when working over an IPoIB interface, MUST follow the
+ following rules:
+ "htype" (hardware address type) MUST be 32 [ARPPARAM].
+ "hlen" (hardware address length) MUST be 0.
+ "chaddr" (client hardware address) field MUST be zeroed.
+ */
+ message->hlen = (arp_type == ARPHRD_INFINIBAND) ? 0 : hlen;
+ memcpy_safe(message->chaddr, chaddr, message->hlen);
+
message->xid = htobe32(xid);
message->magic = htobe32(DHCP_MAGIC_COOKIE);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h
index 4eb56aa8c9..f943409856 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h
@@ -11,6 +11,7 @@
#include "sd-event.h"
#include "sd-dhcp6-client.h"
+#include "dhcp6-protocol.h"
#include "hashmap.h"
#include "list.h"
#include "macro.h"
@@ -93,6 +94,7 @@ typedef struct DHCP6IA {
typedef struct sd_dhcp6_client sd_dhcp6_client;
+bool dhcp6_option_can_request(uint16_t option);
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);
@@ -129,6 +131,12 @@ int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *address);
int dhcp6_network_send_udp_socket(int s, struct in6_addr *address,
const void *packet, size_t len);
+int client_parse_message(
+ sd_dhcp6_client *client,
+ DHCP6Message *message,
+ size_t len,
+ sd_dhcp6_lease *lease);
+
const char *dhcp6_message_type_to_string(int s) _const_;
int dhcp6_message_type_from_string(const char *s) _pure_;
const char *dhcp6_message_status_to_string(int s) _const_;
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-lease-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-lease-internal.h
index 8801497b72..8ae2ecd6d9 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-lease-internal.h
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-lease-internal.h
@@ -14,10 +14,14 @@
struct sd_dhcp6_lease {
unsigned n_ref;
+ uint8_t *clientid;
+ size_t clientid_len;
uint8_t *serverid;
size_t serverid_len;
uint8_t preference;
bool rapid_commit;
+ triple_timestamp timestamp;
+ struct in6_addr server_address;
DHCP6IA ia;
DHCP6IA pd;
@@ -39,21 +43,19 @@ struct sd_dhcp6_lease {
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire);
DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia);
-int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id,
- size_t len);
-int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len);
+int dhcp6_lease_set_clientid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len);
+int dhcp6_lease_get_clientid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len);
+int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len);
+int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len);
int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference);
int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference);
int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease);
int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit);
-int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
-int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
-
int dhcp6_lease_add_dns(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
int dhcp6_lease_add_domains(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
int dhcp6_lease_add_ntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
-int dhcp6_lease_add_sntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) ;
+int dhcp6_lease_add_sntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
int dhcp6_lease_new(sd_dhcp6_lease **ret);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c
index b6816de404..beace4c7ec 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c
@@ -49,6 +49,10 @@ int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *local_address) {
if (r < 0)
return r;
+ r = setsockopt_int(s, SOL_SOCKET, SO_TIMESTAMP, true);
+ if (r < 0)
+ return r;
+
r = bind(s, &src.sa, sizeof(src.in6));
if (r < 0)
return -errno;
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c
index 4249f90de0..237771e613 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c
@@ -26,6 +26,193 @@
#define DHCP6_OPTION_IA_PD_LEN (sizeof(struct ia_pd))
#define DHCP6_OPTION_IA_TA_LEN (sizeof(struct ia_ta))
+bool dhcp6_option_can_request(uint16_t option) {
+ /* See Client ORO field in
+ * https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-2 */
+
+ switch (option) {
+ case SD_DHCP6_OPTION_CLIENTID:
+ case SD_DHCP6_OPTION_SERVERID:
+ case SD_DHCP6_OPTION_IA_NA:
+ case SD_DHCP6_OPTION_IA_TA:
+ case SD_DHCP6_OPTION_IAADDR:
+ case SD_DHCP6_OPTION_ORO:
+ case SD_DHCP6_OPTION_PREFERENCE:
+ case SD_DHCP6_OPTION_ELAPSED_TIME:
+ case SD_DHCP6_OPTION_RELAY_MSG:
+ case SD_DHCP6_OPTION_AUTH:
+ case SD_DHCP6_OPTION_UNICAST:
+ case SD_DHCP6_OPTION_STATUS_CODE:
+ case SD_DHCP6_OPTION_RAPID_COMMIT:
+ case SD_DHCP6_OPTION_USER_CLASS:
+ case SD_DHCP6_OPTION_VENDOR_CLASS:
+ return false;
+ case SD_DHCP6_OPTION_VENDOR_OPTS:
+ return true;
+ case SD_DHCP6_OPTION_INTERFACE_ID:
+ case SD_DHCP6_OPTION_RECONF_MSG:
+ case SD_DHCP6_OPTION_RECONF_ACCEPT:
+ return false;
+ case SD_DHCP6_OPTION_SIP_SERVER_DOMAIN_NAME:
+ case SD_DHCP6_OPTION_SIP_SERVER_ADDRESS:
+ case SD_DHCP6_OPTION_DNS_SERVERS:
+ case SD_DHCP6_OPTION_DOMAIN_LIST:
+ return true;
+ case SD_DHCP6_OPTION_IA_PD:
+ case SD_DHCP6_OPTION_IA_PD_PREFIX:
+ return false;
+ case SD_DHCP6_OPTION_NIS_SERVERS:
+ case SD_DHCP6_OPTION_NISP_SERVERS:
+ case SD_DHCP6_OPTION_NIS_DOMAIN_NAME:
+ case SD_DHCP6_OPTION_NISP_DOMAIN_NAME:
+ case SD_DHCP6_OPTION_SNTP_SERVERS:
+ case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME:
+ case SD_DHCP6_OPTION_BCMCS_SERVER_D:
+ case SD_DHCP6_OPTION_BCMCS_SERVER_A:
+ case SD_DHCP6_OPTION_GEOCONF_CIVIC:
+ return true;
+ case SD_DHCP6_OPTION_REMOTE_ID:
+ case SD_DHCP6_OPTION_SUBSCRIBER_ID:
+ return false;
+ case SD_DHCP6_OPTION_CLIENT_FQDN:
+ case SD_DHCP6_OPTION_PANA_AGENT:
+ case SD_DHCP6_OPTION_NEW_POSIX_TIMEZONE:
+ case SD_DHCP6_OPTION_NEW_TZDB_TIMEZONE:
+ return true;
+ case SD_DHCP6_OPTION_ERO:
+ case SD_DHCP6_OPTION_LQ_QUERY:
+ case SD_DHCP6_OPTION_CLIENT_DATA:
+ case SD_DHCP6_OPTION_CLT_TIME:
+ case SD_DHCP6_OPTION_LQ_RELAY_DATA:
+ case SD_DHCP6_OPTION_LQ_CLIENT_LINK:
+ return false;
+ case SD_DHCP6_OPTION_MIP6_HNIDF:
+ case SD_DHCP6_OPTION_MIP6_VDINF:
+ case SD_DHCP6_OPTION_V6_LOST:
+ case SD_DHCP6_OPTION_CAPWAP_AC_V6:
+ return true;
+ case SD_DHCP6_OPTION_RELAY_ID:
+ return false;
+ case SD_DHCP6_OPTION_IPV6_ADDRESS_MOS:
+ case SD_DHCP6_OPTION_IPV6_FQDN_MOS:
+ case SD_DHCP6_OPTION_NTP_SERVER:
+ case SD_DHCP6_OPTION_V6_ACCESS_DOMAIN:
+ case SD_DHCP6_OPTION_SIP_UA_CS_LIST:
+ case SD_DHCP6_OPTION_BOOTFILE_URL:
+ case SD_DHCP6_OPTION_BOOTFILE_PARAM:
+ return true;
+ case SD_DHCP6_OPTION_CLIENT_ARCH_TYPE:
+ return false;
+ case SD_DHCP6_OPTION_NII:
+ case SD_DHCP6_OPTION_GEOLOCATION:
+ case SD_DHCP6_OPTION_AFTR_NAME:
+ case SD_DHCP6_OPTION_ERP_LOCAL_DOMAIN_NAME:
+ return true;
+ case SD_DHCP6_OPTION_RSOO:
+ return false;
+ case SD_DHCP6_OPTION_PD_EXCLUDE:
+ return true;
+ case SD_DHCP6_OPTION_VSS:
+ return false;
+ case SD_DHCP6_OPTION_MIP6_IDINF:
+ case SD_DHCP6_OPTION_MIP6_UDINF:
+ case SD_DHCP6_OPTION_MIP6_HNP:
+ case SD_DHCP6_OPTION_MIP6_HAA:
+ case SD_DHCP6_OPTION_MIP6_HAF:
+ case SD_DHCP6_OPTION_RDNSS_SELECTION:
+ case SD_DHCP6_OPTION_KRB_PRINCIPAL_NAME:
+ case SD_DHCP6_OPTION_KRB_REALM_NAME:
+ case SD_DHCP6_OPTION_KRB_DEFAULT_REALM_NAME:
+ case SD_DHCP6_OPTION_KRB_KDC:
+ return true;
+ case SD_DHCP6_OPTION_CLIENT_LINKLAYER_ADDR:
+ case SD_DHCP6_OPTION_LINK_ADDRESS:
+ case SD_DHCP6_OPTION_RADIUS:
+ return false;
+ case SD_DHCP6_OPTION_SOL_MAX_RT:
+ case SD_DHCP6_OPTION_INF_MAX_RT:
+ case SD_DHCP6_OPTION_ADDRSEL:
+ case SD_DHCP6_OPTION_ADDRSEL_TABLE:
+ case SD_DHCP6_OPTION_V6_PCP_SERVER:
+ return true;
+ case SD_DHCP6_OPTION_DHCPV4_MSG:
+ return false;
+ case SD_DHCP6_OPTION_DHCP4_O_DHCP6_SERVER:
+ return true;
+ case SD_DHCP6_OPTION_S46_RULE:
+ return false;
+ case SD_DHCP6_OPTION_S46_BR:
+ return true;
+ case SD_DHCP6_OPTION_S46_DMR:
+ case SD_DHCP6_OPTION_S46_V4V6BIND:
+ case SD_DHCP6_OPTION_S46_PORTPARAMS:
+ return false;
+ case SD_DHCP6_OPTION_S46_CONT_MAPE:
+ case SD_DHCP6_OPTION_S46_CONT_MAPT:
+ case SD_DHCP6_OPTION_S46_CONT_LW:
+ case SD_DHCP6_OPTION_4RD:
+ case SD_DHCP6_OPTION_4RD_MAP_RULE:
+ case SD_DHCP6_OPTION_4RD_NON_MAP_RULE:
+ return true;
+ case SD_DHCP6_OPTION_LQ_BASE_TIME:
+ case SD_DHCP6_OPTION_LQ_START_TIME:
+ case SD_DHCP6_OPTION_LQ_END_TIME:
+ return false;
+ case SD_DHCP6_OPTION_CAPTIVE_PORTAL:
+ case SD_DHCP6_OPTION_MPL_PARAMETERS:
+ return true;
+ case SD_DHCP6_OPTION_ANI_ATT:
+ case SD_DHCP6_OPTION_ANI_NETWORK_NAME:
+ case SD_DHCP6_OPTION_ANI_AP_NAME:
+ case SD_DHCP6_OPTION_ANI_AP_BSSID:
+ case SD_DHCP6_OPTION_ANI_OPERATOR_ID:
+ case SD_DHCP6_OPTION_ANI_OPERATOR_REALM:
+ return false;
+ case SD_DHCP6_OPTION_S46_PRIORITY:
+ return true;
+ case SD_DHCP6_OPTION_MUD_URL_V6:
+ return false;
+ case SD_DHCP6_OPTION_V6_PREFIX64:
+ return true;
+ case SD_DHCP6_OPTION_F_BINDING_STATUS:
+ case SD_DHCP6_OPTION_F_CONNECT_FLAGS:
+ case SD_DHCP6_OPTION_F_DNS_REMOVAL_INFO:
+ case SD_DHCP6_OPTION_F_DNS_HOST_NAME:
+ case SD_DHCP6_OPTION_F_DNS_ZONE_NAME:
+ case SD_DHCP6_OPTION_F_DNS_FLAGS:
+ case SD_DHCP6_OPTION_F_EXPIRATION_TIME:
+ case SD_DHCP6_OPTION_F_MAX_UNACKED_BNDUPD:
+ case SD_DHCP6_OPTION_F_MCLT:
+ case SD_DHCP6_OPTION_F_PARTNER_LIFETIME:
+ case SD_DHCP6_OPTION_F_PARTNER_LIFETIME_SENT:
+ case SD_DHCP6_OPTION_F_PARTNER_DOWN_TIME:
+ case SD_DHCP6_OPTION_F_PARTNER_RAW_CLT_TIME:
+ case SD_DHCP6_OPTION_F_PROTOCOL_VERSION:
+ case SD_DHCP6_OPTION_F_KEEPALIVE_TIME:
+ case SD_DHCP6_OPTION_F_RECONFIGURE_DATA:
+ case SD_DHCP6_OPTION_F_RELATIONSHIP_NAME:
+ case SD_DHCP6_OPTION_F_SERVER_FLAGS:
+ case SD_DHCP6_OPTION_F_SERVER_STATE:
+ case SD_DHCP6_OPTION_F_START_TIME_OF_STATE:
+ case SD_DHCP6_OPTION_F_STATE_EXPIRATION_TIME:
+ case SD_DHCP6_OPTION_RELAY_PORT:
+ return false;
+ case SD_DHCP6_OPTION_V6_SZTP_REDIRECT:
+ case SD_DHCP6_OPTION_S46_BIND_IPV6_PREFIX:
+ return true;
+ case SD_DHCP6_OPTION_IA_LL:
+ case SD_DHCP6_OPTION_LLADDR:
+ case SD_DHCP6_OPTION_SLAP_QUAD:
+ return false;
+ case SD_DHCP6_OPTION_V6_DOTS_RI:
+ case SD_DHCP6_OPTION_V6_DOTS_ADDRESS:
+ case SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF:
+ return true;
+ default:
+ return false;
+ }
+}
+
static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode, size_t optlen) {
DHCP6Option *option;
@@ -275,7 +462,7 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) {
if (dns_name_is_single_label(fqdn))
r--;
- r = dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_FQDN, 1 + r, buffer);
+ r = dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_CLIENT_FQDN, 1 + r, buffer);
return r;
}
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h
index c700363803..5d2af439e2 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h
+++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-protocol.h
@@ -5,6 +5,7 @@
Copyright © 2014 Intel Corporation. All rights reserved.
***/
+#include <errno.h>
#include <netinet/ip6.h>
#include <netinet/udp.h>
@@ -36,57 +37,83 @@ enum {
DHCP6_PORT_CLIENT = 546,
};
-#define DHCP6_INF_TIMEOUT 1 * USEC_PER_SEC
-#define DHCP6_INF_MAX_RT 120 * USEC_PER_SEC
-#define DHCP6_SOL_MAX_DELAY 1 * USEC_PER_SEC
-#define DHCP6_SOL_TIMEOUT 1 * USEC_PER_SEC
-#define DHCP6_SOL_MAX_RT 120 * USEC_PER_SEC
-#define DHCP6_REQ_TIMEOUT 1 * USEC_PER_SEC
-#define DHCP6_REQ_MAX_RT 120 * USEC_PER_SEC
+#define DHCP6_INF_TIMEOUT (1 * USEC_PER_SEC)
+#define DHCP6_INF_MAX_RT (120 * USEC_PER_SEC)
+#define DHCP6_SOL_MAX_DELAY (1 * USEC_PER_SEC)
+#define DHCP6_SOL_TIMEOUT (1 * USEC_PER_SEC)
+#define DHCP6_SOL_MAX_RT (120 * USEC_PER_SEC)
+#define DHCP6_REQ_TIMEOUT (1 * USEC_PER_SEC)
+#define DHCP6_REQ_MAX_RT (120 * USEC_PER_SEC)
#define DHCP6_REQ_MAX_RC 10
-#define DHCP6_REN_TIMEOUT 10 * USEC_PER_SEC
-#define DHCP6_REN_MAX_RT 600 * USEC_PER_SEC
-#define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC
-#define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC
+#define DHCP6_REN_TIMEOUT (10 * USEC_PER_SEC)
+#define DHCP6_REN_MAX_RT (600 * USEC_PER_SEC)
+#define DHCP6_REB_TIMEOUT (10 * USEC_PER_SEC)
+#define DHCP6_REB_MAX_RT (600 * USEC_PER_SEC)
-enum DHCP6State {
- DHCP6_STATE_STOPPED = 0,
- DHCP6_STATE_INFORMATION_REQUEST = 1,
- DHCP6_STATE_SOLICITATION = 2,
- DHCP6_STATE_REQUEST = 3,
- DHCP6_STATE_BOUND = 4,
- DHCP6_STATE_RENEW = 5,
- DHCP6_STATE_REBIND = 6,
-};
+typedef enum DHCP6State {
+ DHCP6_STATE_STOPPED,
+ DHCP6_STATE_INFORMATION_REQUEST,
+ DHCP6_STATE_SOLICITATION,
+ DHCP6_STATE_REQUEST,
+ DHCP6_STATE_BOUND,
+ DHCP6_STATE_RENEW,
+ DHCP6_STATE_REBIND,
+ _DHCP6_STATE_MAX,
+ _DHCP6_STATE_INVALID = -EINVAL,
+} DHCP6State;
-enum {
- DHCP6_SOLICIT = 1,
- DHCP6_ADVERTISE = 2,
- DHCP6_REQUEST = 3,
- DHCP6_CONFIRM = 4,
- DHCP6_RENEW = 5,
- DHCP6_REBIND = 6,
- DHCP6_REPLY = 7,
- DHCP6_RELEASE = 8,
- DHCP6_DECLINE = 9,
- DHCP6_RECONFIGURE = 10,
- DHCP6_INFORMATION_REQUEST = 11,
- DHCP6_RELAY_FORW = 12,
- DHCP6_RELAY_REPL = 13,
- _DHCP6_MESSAGE_MAX = 14,
-};
+/* https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-1 */
+typedef enum DHCP6MessageType {
+ DHCP6_MESSAGE_SOLICIT = 1, /* RFC 8415 */
+ DHCP6_MESSAGE_ADVERTISE = 2, /* RFC 8415 */
+ DHCP6_MESSAGE_REQUEST = 3, /* RFC 8415 */
+ DHCP6_MESSAGE_CONFIRM = 4, /* RFC 8415 */
+ DHCP6_MESSAGE_RENEW = 5, /* RFC 8415 */
+ DHCP6_MESSAGE_REBIND = 6, /* RFC 8415 */
+ DHCP6_MESSAGE_REPLY = 7, /* RFC 8415 */
+ DHCP6_MESSAGE_RELEASE = 8, /* RFC 8415 */
+ DHCP6_MESSAGE_DECLINE = 9, /* RFC 8415 */
+ DHCP6_MESSAGE_RECONFIGURE = 10, /* RFC 8415 */
+ DHCP6_MESSAGE_INFORMATION_REQUEST = 11, /* RFC 8415 */
+ DHCP6_MESSAGE_RELAY_FORWARD = 12, /* RFC 8415 */
+ DHCP6_MESSAGE_RELAY_REPLY = 13, /* RFC 8415 */
+ DHCP6_MESSAGE_LEASE_QUERY = 14, /* RFC 5007 */
+ DHCP6_MESSAGE_LEASE_QUERY_REPLY = 15, /* RFC 5007 */
+ DHCP6_MESSAGE_LEASE_QUERY_DONE = 16, /* RFC 5460 */
+ DHCP6_MESSAGE_LEASE_QUERY_DATA = 17, /* RFC 5460 */
+ DHCP6_MESSAGE_RECONFIGURE_REQUEST = 18, /* RFC 6977 */
+ DHCP6_MESSAGE_RECONFIGURE_REPLY = 19, /* RFC 6977 */
+ DHCP6_MESSAGE_DHCPV4_QUERY = 20, /* RFC 7341 */
+ DHCP6_MESSAGE_DHCPV4_RESPONSE = 21, /* RFC 7341 */
+ DHCP6_MESSAGE_ACTIVE_LEASE_QUERY = 22, /* RFC 7653 */
+ DHCP6_MESSAGE_START_TLS = 23, /* RFC 7653 */
+ DHCP6_MESSAGE_BINDING_UPDATE = 24, /* RFC 8156 */
+ DHCP6_MESSAGE_BINDING_REPLY = 25, /* RFC 8156 */
+ DHCP6_MESSAGE_POOL_REQUEST = 26, /* RFC 8156 */
+ DHCP6_MESSAGE_POOL_RESPONSE = 27, /* RFC 8156 */
+ DHCP6_MESSAGE_UPDATE_REQUEST = 28, /* RFC 8156 */
+ DHCP6_MESSAGE_UPDATE_REQUEST_ALL = 29, /* RFC 8156 */
+ DHCP6_MESSAGE_UPDATE_DONE = 30, /* RFC 8156 */
+ DHCP6_MESSAGE_CONNECT = 31, /* RFC 8156 */
+ DHCP6_MESSAGE_CONNECT_REPLY = 32, /* RFC 8156 */
+ DHCP6_MESSAGE_DISCONNECT = 33, /* RFC 8156 */
+ DHCP6_MESSAGE_STATE = 34, /* RFC 8156 */
+ DHCP6_MESSAGE_CONTACT = 35, /* RFC 8156 */
+ _DHCP6_MESSAGE_TYPE_MAX,
+ _DHCP6_MESSAGE_TYPE_INVALID = -EINVAL,
+} DHCP6MessageType;
-enum {
+typedef enum DHCP6NTPSubOption {
DHCP6_NTP_SUBOPTION_SRV_ADDR = 1,
DHCP6_NTP_SUBOPTION_MC_ADDR = 2,
DHCP6_NTP_SUBOPTION_SRV_FQDN = 3,
-};
+} DHCP6NTPSubOption;
/*
* RFC 8415, RFC 5007 and RFC 7653 status codes:
* https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-5
*/
-enum {
+typedef enum DHCP6Status {
DHCP6_STATUS_SUCCESS = 0,
DHCP6_STATUS_UNSPEC_FAIL = 1,
DHCP6_STATUS_NO_ADDRS_AVAIL = 2,
@@ -110,11 +137,12 @@ enum {
DHCP6_STATUS_SERVER_SHUTTING_DOWN = 20,
DHCP6_STATUS_DNS_UPDATE_NOT_SUPPORTED = 21,
DHCP6_STATUS_EXCESSIVE_TIME_SKEW = 22,
- _DHCP6_STATUS_MAX = 23,
-};
+ _DHCP6_STATUS_MAX,
+ _DHCP6_STATUS_INVALID = -EINVAL,
+} DHCP6Status;
-enum {
- DHCP6_FQDN_FLAG_S = (1 << 0),
- DHCP6_FQDN_FLAG_O = (1 << 1),
- DHCP6_FQDN_FLAG_N = (1 << 2),
-};
+typedef enum DHCP6FQDNFlag {
+ DHCP6_FQDN_FLAG_S = 1 << 0,
+ DHCP6_FQDN_FLAG_O = 1 << 1,
+ DHCP6_FQDN_FLAG_N = 1 << 2,
+} DHCP6FQDNFlag;
diff --git a/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c b/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c
index 3d6d7e4206..b4d7c327cc 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c
@@ -47,7 +47,7 @@ int lldp_neighbor_prioq_compare_func(const void *a, const void *b) {
return CMP(x->until, y->until);
}
-_public_ sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) {
+sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) {
if (!n)
return NULL;
@@ -72,7 +72,7 @@ static sd_lldp_neighbor *lldp_neighbor_free(sd_lldp_neighbor *n) {
return mfree(n);
}
-_public_ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n) {
+sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n) {
/* Drops one reference from the neighbor. Note that the object is not freed unless it is already unlinked from
* the sd_lldp object. */
@@ -360,7 +360,7 @@ bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b) {
return memcmp(LLDP_NEIGHBOR_RAW(a), LLDP_NEIGHBOR_RAW(b), a->raw_size) == 0;
}
-_public_ int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address) {
+int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address) {
assert_return(n, -EINVAL);
assert_return(address, -EINVAL);
@@ -368,7 +368,7 @@ _public_ int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct eth
return 0;
}
-_public_ int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address) {
+int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address) {
assert_return(n, -EINVAL);
assert_return(address, -EINVAL);
@@ -376,7 +376,7 @@ _public_ int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struc
return 0;
}
-_public_ int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
+int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
assert_return(size, -EINVAL);
@@ -387,7 +387,7 @@ _public_ int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, siz
return 0;
}
-_public_ int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
+int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
assert_return(n, -EINVAL);
assert_return(type, -EINVAL);
assert_return(ret, -EINVAL);
@@ -440,7 +440,7 @@ static int format_network_address(const void *data, size_t sz, char **ret) {
return 1;
}
-_public_ int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) {
+int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) {
char *k;
int r;
@@ -496,7 +496,7 @@ done:
return 0;
}
-_public_ int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
+int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
assert_return(n, -EINVAL);
assert_return(type, -EINVAL);
assert_return(ret, -EINVAL);
@@ -511,7 +511,7 @@ _public_ int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, co
return 0;
}
-_public_ int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret) {
+int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret) {
char *k;
int r;
@@ -566,7 +566,7 @@ done:
return 0;
}
-_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec) {
+int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec) {
assert_return(n, -EINVAL);
assert_return(ret_sec, -EINVAL);
@@ -574,7 +574,7 @@ _public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec) {
return 0;
}
-_public_ int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret) {
+int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret) {
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
@@ -585,7 +585,7 @@ _public_ int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **
return 0;
}
-_public_ int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret) {
+int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret) {
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
@@ -596,7 +596,7 @@ _public_ int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const
return 0;
}
-_public_ int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret) {
+int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret) {
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
@@ -607,7 +607,7 @@ _public_ int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const ch
return 0;
}
-_public_ int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret) {
+int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret) {
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
@@ -618,7 +618,7 @@ _public_ int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret)
return 0;
}
-_public_ int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
+int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
@@ -629,7 +629,7 @@ _public_ int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint1
return 0;
}
-_public_ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
+int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
@@ -640,7 +640,7 @@ _public_ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint
return 0;
}
-_public_ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) {
+int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) {
_cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
int r;
@@ -661,7 +661,7 @@ _public_ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw,
return r;
}
-_public_ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
+int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
assert_return(n, -EINVAL);
assert(n->raw_size >= sizeof(struct ether_header));
@@ -670,7 +670,7 @@ _public_ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
return n->rindex < n->raw_size;
}
-_public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) {
+int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) {
size_t length;
assert_return(n, -EINVAL);
@@ -689,7 +689,7 @@ _public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) {
return n->rindex < n->raw_size;
}
-_public_ int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) {
+int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) {
assert_return(n, -EINVAL);
assert_return(type, -EINVAL);
@@ -703,7 +703,7 @@ _public_ int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) {
return 0;
}
-_public_ int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) {
+int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) {
uint8_t k;
int r;
@@ -716,7 +716,7 @@ _public_ int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) {
return type == k;
}
-_public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t *subtype) {
+int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t *subtype) {
const uint8_t *d;
size_t length;
int r;
@@ -745,7 +745,7 @@ _public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_A
return 0;
}
-_public_ int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t subtype) {
+int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t subtype) {
uint8_t k[3], st;
int r;
@@ -758,7 +758,7 @@ _public_ int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[
return memcmp(k, oui, 3) == 0 && st == subtype;
}
-_public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
+int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
size_t length;
assert_return(n, -EINVAL);
@@ -780,7 +780,7 @@ _public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret,
return 0;
}
-_public_ int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret) {
+int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret) {
assert_return(n, -EINVAL);
assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
assert_return(clock_supported(clock), -EOPNOTSUPP);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/lldp-network.c b/src/libnm-systemd-core/src/libsystemd-network/lldp-network.c
index 34a4f3f068..00eb97038d 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/lldp-network.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/lldp-network.c
@@ -11,7 +11,6 @@
#include "socket-util.h"
int lldp_network_bind_raw_socket(int ifindex) {
-
static const struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ethhdr, h_dest)), /* A <- 4 bytes of destination MAC */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0180c200, 1, 0), /* A != 01:80:c2:00 */
@@ -26,26 +25,21 @@ int lldp_network_bind_raw_socket(int ifindex) {
BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept packet */
};
-
static const struct sock_fprog fprog = {
.len = ELEMENTSOF(filter),
.filter = (struct sock_filter*) filter,
};
-
struct packet_mreq mreq = {
.mr_ifindex = ifindex,
.mr_type = PACKET_MR_MULTICAST,
.mr_alen = ETH_ALEN,
.mr_address = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00 }
};
-
union sockaddr_union saddrll = {
.ll.sll_family = AF_PACKET,
.ll.sll_ifindex = ifindex,
};
-
_cleanup_close_ int fd = -1;
- int r;
assert(ifindex > 0);
@@ -54,29 +48,24 @@ int lldp_network_bind_raw_socket(int ifindex) {
if (fd < 0)
return -errno;
- r = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
- if (r < 0)
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0)
return -errno;
/* customer bridge */
- r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
- if (r < 0)
+ if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
return -errno;
/* non TPMR bridge */
mreq.mr_address[ETH_ALEN - 1] = 0x03;
- r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
- if (r < 0)
+ if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
return -errno;
/* nearest bridge */
mreq.mr_address[ETH_ALEN - 1] = 0x0E;
- r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
- if (r < 0)
+ if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
return -errno;
- r = bind(fd, &saddrll.sa, sizeof(saddrll.ll));
- if (r < 0)
+ if (bind(fd, &saddrll.sa, sizeof(saddrll.ll)) < 0)
return -errno;
return TAKE_FD(fd);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/network-common.h b/src/libnm-systemd-core/src/libsystemd-network/network-common.h
index d43b76d4b8..2b0e3b5607 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/network-common.h
+++ b/src/libnm-systemd-core/src/libsystemd-network/network-common.h
@@ -8,8 +8,10 @@
int _e = (error); \
if (DEBUG_LOGGING) { \
const char *_n = NULL; \
+ type *_v = (val); \
\
- (void) type##_get_ifname(val, &_n); \
+ if (_v) \
+ (void) type##_get_ifname(_v, &_n); \
log_interface_full_errno_zerook( \
_n, LOG_DEBUG, _e, prefix fmt, \
##__VA_ARGS__); \
diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c
index cb984b6e0a..1600f806ed 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c
@@ -837,7 +837,8 @@ static int client_message_init(
return -ENOMEM;
r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
- client->arp_type, optlen, &optoffset);
+ client->arp_type, client->mac_addr_len, client->mac_addr,
+ optlen, &optoffset);
if (r < 0)
return r;
@@ -853,7 +854,7 @@ static int client_message_init(
secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
packet->dhcp.secs = htobe16(secs);
- /* RFC2132 section 4.1
+ /* RFC2131 section 4.1
A client that cannot receive unicast IP datagrams until its protocol
software has been configured with an IP address SHOULD set the
BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or
@@ -867,15 +868,6 @@ static int client_message_init(
if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
packet->dhcp.flags = htobe16(0x8000);
- /* RFC2132 section 4.1.1:
- The client MUST include its hardware address in the ’chaddr’ field, if
- necessary for delivery of DHCP reply messages. Non-Ethernet
- interfaces will leave 'chaddr' empty and use the client identifier
- instead (eg, RFC 4390 section 2.1).
- */
- if (client->arp_type == ARPHRD_ETHER)
- memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
-
/* If no client identifier exists, construct an RFC 4361-compliant one */
if (client->client_id_len == 0) {
size_t duid_len;
@@ -1935,13 +1927,13 @@ static int client_receive_message_udp(
assert(client);
buflen = next_datagram_size_fd(fd);
- if (buflen == -ENETDOWN)
- /* the link is down. Don't return an error or the I/O event
- source will be disconnected and we won't be able to receive
- packets again when the link comes back. */
+ if (buflen < 0) {
+ if (ERRNO_IS_TRANSIENT(buflen) || ERRNO_IS_DISCONNECT(buflen))
+ return 0;
+
+ log_dhcp_client_errno(client, buflen, "Failed to determine datagram size to read, ignoring: %m");
return 0;
- if (buflen < 0)
- return buflen;
+ }
message = malloc0(buflen);
if (!message)
@@ -1949,12 +1941,11 @@ static int client_receive_message_udp(
len = recv(fd, message, buflen, 0);
if (len < 0) {
- /* see comment above for why we shouldn't error out on ENETDOWN. */
- if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
+ if (ERRNO_IS_TRANSIENT(errno) || ERRNO_IS_DISCONNECT(errno))
return 0;
- return log_dhcp_client_errno(client, errno,
- "Could not receive message from UDP socket: %m");
+ log_dhcp_client_errno(client, errno, "Could not receive message from UDP socket, ignoring: %m");
+ return 0;
}
if ((size_t) len < sizeof(DHCPMessage)) {
log_dhcp_client(client, "Too small to be a DHCP message: ignoring");
@@ -2000,7 +1991,9 @@ static int client_receive_message_udp(
return 0;
}
- return client_handle_message(client, message, len);
+ log_dhcp_client(client, "Received message from UDP socket, processing.");
+ (void) client_handle_message(client, message, len);
+ return 0;
}
static int client_receive_message_raw(
@@ -2028,10 +2021,13 @@ static int client_receive_message_raw(
assert(client);
buflen = next_datagram_size_fd(fd);
- if (buflen == -ENETDOWN)
+ if (buflen < 0) {
+ if (ERRNO_IS_TRANSIENT(buflen) || ERRNO_IS_DISCONNECT(buflen))
+ return 0;
+
+ log_dhcp_client_errno(client, buflen, "Failed to determine datagram size to read, ignoring: %m");
return 0;
- if (buflen < 0)
- return buflen;
+ }
packet = malloc0(buflen);
if (!packet)
@@ -2040,12 +2036,13 @@ static int client_receive_message_raw(
iov = IOVEC_MAKE(packet, buflen);
len = recvmsg_safe(fd, &msg, 0);
- if (IN_SET(len, -EAGAIN, -EINTR, -ENETDOWN))
- return 0;
- if (len < 0)
- return log_dhcp_client_errno(client, len,
- "Could not receive message from raw socket: %m");
+ if (len < 0) {
+ if (ERRNO_IS_TRANSIENT(len) || ERRNO_IS_DISCONNECT(len))
+ return 0;
+ log_dhcp_client_errno(client, len, "Could not receive message from raw socket, ignoring: %m");
+ return 0;
+ }
if ((size_t) len < sizeof(DHCPPacket))
return 0;
@@ -2061,7 +2058,9 @@ static int client_receive_message_raw(
len -= DHCP_IP_UDP_SIZE;
- return client_handle_message(client, &packet->dhcp, len);
+ log_dhcp_client(client, "Received message from RAW socket, processing.");
+ (void) client_handle_message(client, &packet->dhcp, len);
+ return 0;
}
int sd_dhcp_client_send_renew(sd_dhcp_client *client) {
diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c
index 4cd9295c75..7a2505343d 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c
@@ -107,12 +107,13 @@ int sd_dhcp_lease_get_servers(
assert_return(lease, -EINVAL);
assert_return(what >= 0, -EINVAL);
assert_return(what < _SD_DHCP_LEASE_SERVER_TYPE_MAX, -EINVAL);
- assert_return(addr, -EINVAL);
if (lease->servers[what].size <= 0)
return -ENODATA;
- *addr = lease->servers[what].addr;
+ if (addr)
+ *addr = lease->servers[what].addr;
+
return (int) lease->servers[what].size;
}
@@ -252,6 +253,33 @@ int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
return -ENODATA;
}
+int sd_dhcp_lease_get_6rd(
+ sd_dhcp_lease *lease,
+ uint8_t *ret_ipv4masklen,
+ uint8_t *ret_prefixlen,
+ struct in6_addr *ret_prefix,
+ const struct in_addr **ret_br_addresses,
+ size_t *ret_n_br_addresses) {
+
+ assert_return(lease, -EINVAL);
+
+ if (lease->sixrd_n_br_addresses <= 0)
+ return -ENODATA;
+
+ if (ret_ipv4masklen)
+ *ret_ipv4masklen = lease->sixrd_ipv4masklen;
+ if (ret_prefixlen)
+ *ret_prefixlen = lease->sixrd_prefixlen;
+ if (ret_prefix)
+ *ret_prefix = lease->sixrd_prefix;
+ if (ret_br_addresses)
+ *ret_br_addresses = lease->sixrd_br_addresses;
+ if (ret_n_br_addresses)
+ *ret_n_br_addresses = lease->sixrd_n_br_addresses;
+
+ return 0;
+}
+
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) {
assert_return(lease, -EINVAL);
assert_return(data, -EINVAL);
@@ -290,6 +318,7 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
free(lease->client_id);
free(lease->vendor_specific);
strv_free(lease->search_domains);
+ free(lease->sixrd_br_addresses);
return mfree(lease);
}
@@ -535,6 +564,61 @@ static int lease_parse_classless_routes(
return 0;
}
+static int lease_parse_6rd(sd_dhcp_lease *lease, const uint8_t *option, size_t len) {
+ uint8_t ipv4masklen, prefixlen;
+ struct in6_addr prefix;
+ _cleanup_free_ struct in_addr *br_addresses = NULL;
+ size_t n_br_addresses;
+
+ assert(lease);
+ assert(option);
+
+ /* See RFC 5969 Section 7.1.1 */
+
+ if (lease->sixrd_n_br_addresses > 0)
+ /* Multiple 6rd option?? */
+ return -EINVAL;
+
+ /* option-length: The length of the DHCP option in octets (22 octets with one BR IPv4 address). */
+ if (len < 2 + sizeof(struct in6_addr) + sizeof(struct in_addr) ||
+ (len - 2 - sizeof(struct in6_addr)) % sizeof(struct in_addr) != 0)
+ return -EINVAL;
+
+ /* IPv4MaskLen: The number of high-order bits that are identical across all CE IPv4 addresses
+ * within a given 6rd domain. This may be any value between 0 and 32. Any value
+ * greater than 32 is invalid. */
+ ipv4masklen = option[0];
+ if (ipv4masklen > 32)
+ return -EINVAL;
+
+ /* 6rdPrefixLen: The IPv6 prefix length of the SP's 6rd IPv6 prefix in number of bits. For the
+ * purpose of bounds checking by DHCP option processing, the sum of
+ * (32 - IPv4MaskLen) + 6rdPrefixLen MUST be less than or equal to 128. */
+ prefixlen = option[1];
+ if (32 - ipv4masklen + prefixlen > 128)
+ return -EINVAL;
+
+ /* 6rdPrefix: The service provider's 6rd IPv6 prefix represented as a 16-octet IPv6 address.
+ * The bits in the prefix after the 6rdPrefixlen number of bits are reserved and
+ * MUST be initialized to zero by the sender and ignored by the receiver. */
+ memcpy(&prefix, option + 2, sizeof(struct in6_addr));
+ (void) in6_addr_mask(&prefix, prefixlen);
+
+ /* 6rdBRIPv4Address: One or more IPv4 addresses of the 6rd Border Relay(s) for a given 6rd domain. */
+ n_br_addresses = (len - 2 - sizeof(struct in6_addr)) / sizeof(struct in_addr);
+ br_addresses = newdup(struct in_addr, option + 2 + sizeof(struct in6_addr), n_br_addresses);
+ if (!br_addresses)
+ return -ENOMEM;
+
+ lease->sixrd_ipv4masklen = ipv4masklen;
+ lease->sixrd_prefixlen = prefixlen;
+ lease->sixrd_prefix = prefix;
+ lease->sixrd_br_addresses = TAKE_PTR(br_addresses);
+ lease->sixrd_n_br_addresses = n_br_addresses;
+
+ return 0;
+}
+
int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) {
sd_dhcp_lease *lease = userdata;
int r;
@@ -693,7 +777,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
}
if (!timezone_is_valid(tz, LOG_DEBUG)) {
- log_debug_errno(r, "Timezone is not valid, ignoring: %m");
+ log_debug("Timezone is not valid, ignoring.");
return 0;
}
@@ -720,6 +804,12 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
lease->vendor_specific_len = len;
break;
+ case SD_DHCP_OPTION_6RD:
+ r = lease_parse_6rd(lease, option, len);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse 6rd option, ignoring: %m");
+ break;
+
case SD_DHCP_OPTION_PRIVATE_BASE ... SD_DHCP_OPTION_PRIVATE_LAST:
r = dhcp_lease_insert_private_option(lease, code, option, len);
if (r < 0)
diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
index 5398bdff37..0c2206ff71 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c
@@ -27,6 +27,7 @@
#include "hexdecoct.h"
#include "hostname-util.h"
#include "in-addr-util.h"
+#include "io-util.h"
#include "network-common.h"
#include "random-util.h"
#include "socket-util.h"
@@ -41,16 +42,16 @@
#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,
- DHCP6_REQUEST_IA_TA = 2, /* currently not used */
- DHCP6_REQUEST_IA_PD = 4,
-};
+typedef enum DHCP6RequestIA {
+ DHCP6_REQUEST_IA_NA = 1 << 0,
+ DHCP6_REQUEST_IA_TA = 1 << 1, /* currently not used */
+ DHCP6_REQUEST_IA_PD = 1 << 2,
+} DHCP6RequestIA;
struct sd_dhcp6_client {
unsigned n_ref;
- enum DHCP6State state;
+ DHCP6State state;
sd_event *event;
int event_priority;
int ifindex;
@@ -64,7 +65,7 @@ struct sd_dhcp6_client {
DHCP6IA ia_pd;
sd_event_source *timeout_t1;
sd_event_source *timeout_t2;
- unsigned request;
+ DHCP6RequestIA request_ia;
be32_t transaction_id;
usec_t transaction_start;
struct sd_dhcp6_lease *lease;
@@ -102,20 +103,42 @@ static const uint16_t default_req_opts[] = {
SD_DHCP6_OPTION_SNTP_SERVERS,
};
-const char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = {
- [DHCP6_SOLICIT] = "SOLICIT",
- [DHCP6_ADVERTISE] = "ADVERTISE",
- [DHCP6_REQUEST] = "REQUEST",
- [DHCP6_CONFIRM] = "CONFIRM",
- [DHCP6_RENEW] = "RENEW",
- [DHCP6_REBIND] = "REBIND",
- [DHCP6_REPLY] = "REPLY",
- [DHCP6_RELEASE] = "RELEASE",
- [DHCP6_DECLINE] = "DECLINE",
- [DHCP6_RECONFIGURE] = "RECONFIGURE",
- [DHCP6_INFORMATION_REQUEST] = "INFORMATION-REQUEST",
- [DHCP6_RELAY_FORW] = "RELAY-FORW",
- [DHCP6_RELAY_REPL] = "RELAY-REPL",
+const char * dhcp6_message_type_table[_DHCP6_MESSAGE_TYPE_MAX] = {
+ [DHCP6_MESSAGE_SOLICIT] = "Solicit",
+ [DHCP6_MESSAGE_ADVERTISE] = "Advertise",
+ [DHCP6_MESSAGE_REQUEST] = "Request",
+ [DHCP6_MESSAGE_CONFIRM] = "Confirm",
+ [DHCP6_MESSAGE_RENEW] = "Renew",
+ [DHCP6_MESSAGE_REBIND] = "Rebind",
+ [DHCP6_MESSAGE_REPLY] = "Reply",
+ [DHCP6_MESSAGE_RELEASE] = "Release",
+ [DHCP6_MESSAGE_DECLINE] = "Decline",
+ [DHCP6_MESSAGE_RECONFIGURE] = "Reconfigure",
+ [DHCP6_MESSAGE_INFORMATION_REQUEST] = "Information Request",
+ [DHCP6_MESSAGE_RELAY_FORWARD] = "Relay Forward",
+ [DHCP6_MESSAGE_RELAY_REPLY] = "Relay Reply",
+ [DHCP6_MESSAGE_LEASE_QUERY] = "Lease Query",
+ [DHCP6_MESSAGE_LEASE_QUERY_REPLY] = "Lease Query Reply",
+ [DHCP6_MESSAGE_LEASE_QUERY_DONE] = "Lease Query Done",
+ [DHCP6_MESSAGE_LEASE_QUERY_DATA] = "Lease Query Data",
+ [DHCP6_MESSAGE_RECONFIGURE_REQUEST] = "Reconfigure Request",
+ [DHCP6_MESSAGE_RECONFIGURE_REPLY] = "Reconfigure Reply",
+ [DHCP6_MESSAGE_DHCPV4_QUERY] = "DHCPv4 Query",
+ [DHCP6_MESSAGE_DHCPV4_RESPONSE] = "DHCPv4 Response",
+ [DHCP6_MESSAGE_ACTIVE_LEASE_QUERY] = "Active Lease Query",
+ [DHCP6_MESSAGE_START_TLS] = "Start TLS",
+ [DHCP6_MESSAGE_BINDING_UPDATE] = "Binding Update",
+ [DHCP6_MESSAGE_BINDING_REPLY] = "Binding Reply",
+ [DHCP6_MESSAGE_POOL_REQUEST] = "Pool Request",
+ [DHCP6_MESSAGE_POOL_RESPONSE] = "Pool Response",
+ [DHCP6_MESSAGE_UPDATE_REQUEST] = "Update Request",
+ [DHCP6_MESSAGE_UPDATE_REQUEST_ALL] = "Update Request All",
+ [DHCP6_MESSAGE_UPDATE_DONE] = "Update Done",
+ [DHCP6_MESSAGE_CONNECT] = "Connect",
+ [DHCP6_MESSAGE_CONNECT_REPLY] = "Connect Reply",
+ [DHCP6_MESSAGE_DISCONNECT] = "Disconnect",
+ [DHCP6_MESSAGE_STATE] = "State",
+ [DHCP6_MESSAGE_CONTACT] = "Contact",
};
DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type, int);
@@ -151,7 +174,7 @@ DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
#define DHCP6_CLIENT_DONT_DESTROY(client) \
_cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
-static int client_start(sd_dhcp6_client *client, enum DHCP6State state);
+static int client_start(sd_dhcp6_client *client, DHCP6State state);
int sd_dhcp6_client_set_callback(
sd_dhcp6_client *client,
@@ -234,10 +257,6 @@ int sd_dhcp6_client_set_mac(
return 0;
}
- if (client->mac_addr_len == addr_len &&
- memcmp(&client->mac_addr, addr, addr_len) == 0)
- return 0;
-
memcpy(&client->mac_addr, addr, addr_len);
client->mac_addr_len = addr_len;
client->arp_type = arp_type;
@@ -475,7 +494,7 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
assert_return(client, -EINVAL);
assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY);
- if (option <= 0 || option >= UINT8_MAX)
+ if (!dhcp6_option_can_request(option))
return -EINVAL;
for (t = 0; t < client->req_opts_len; t++)
@@ -548,7 +567,7 @@ int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegati
assert_return(client, -EINVAL);
assert_return(delegation, -EINVAL);
- *delegation = FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD);
+ *delegation = FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD);
return 0;
}
@@ -556,7 +575,7 @@ int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegati
int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, int delegation) {
assert_return(client, -EINVAL);
- SET_FLAG(client->request, DHCP6_REQUEST_IA_PD, delegation);
+ SET_FLAG(client->request_ia, DHCP6_REQUEST_IA_PD, delegation);
return 0;
}
@@ -565,7 +584,7 @@ int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client, int *request) {
assert_return(client, -EINVAL);
assert_return(request, -EINVAL);
- *request = FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA);
+ *request = FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA);
return 0;
}
@@ -573,7 +592,7 @@ int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client, int *request) {
int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request) {
assert_return(client, -EINVAL);
- SET_FLAG(client->request, DHCP6_REQUEST_IA_NA, request);
+ SET_FLAG(client->request_ia, DHCP6_REQUEST_IA_NA, request);
return 0;
}
@@ -678,11 +697,11 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
switch(client->state) {
case DHCP6_STATE_INFORMATION_REQUEST:
- message->type = DHCP6_INFORMATION_REQUEST;
+ message->type = DHCP6_MESSAGE_INFORMATION_REQUEST;
if (client->mudurl) {
r = dhcp6_option_append(&opt, &optlen,
- SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
+ SD_DHCP6_OPTION_MUD_URL_V6, strlen(client->mudurl),
client->mudurl);
if (r < 0)
return r;
@@ -691,14 +710,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
break;
case DHCP6_STATE_SOLICITATION:
- message->type = DHCP6_SOLICIT;
+ message->type = DHCP6_MESSAGE_SOLICIT;
r = dhcp6_option_append(&opt, &optlen,
SD_DHCP6_OPTION_RAPID_COMMIT, 0, NULL);
if (r < 0)
return r;
- if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
+ if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA)) {
r = dhcp6_option_append_ia(&opt, &optlen,
&client->ia_na);
if (r < 0)
@@ -713,7 +732,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
if (client->mudurl) {
r = dhcp6_option_append(&opt, &optlen,
- SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
+ SD_DHCP6_OPTION_MUD_URL_V6, strlen(client->mudurl),
client->mudurl);
if (r < 0)
return r;
@@ -738,7 +757,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
return r;
}
- if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
+ if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD)) {
r = dhcp6_option_append_pd(&opt, &optlen, &client->ia_pd, &client->hint_pd_prefix);
if (r < 0)
return r;
@@ -750,9 +769,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
case DHCP6_STATE_RENEW:
if (client->state == DHCP6_STATE_REQUEST)
- message->type = DHCP6_REQUEST;
+ message->type = DHCP6_MESSAGE_REQUEST;
else
- message->type = DHCP6_RENEW;
+ message->type = DHCP6_MESSAGE_RENEW;
r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_SERVERID,
client->lease->serverid_len,
@@ -760,7 +779,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
if (r < 0)
return r;
- if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
+ if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
r = dhcp6_option_append_ia(&opt, &optlen,
&client->lease->ia);
if (r < 0)
@@ -775,7 +794,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
if (client->mudurl) {
r = dhcp6_option_append(&opt, &optlen,
- SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
+ SD_DHCP6_OPTION_MUD_URL_V6, strlen(client->mudurl),
client->mudurl);
if (r < 0)
return r;
@@ -799,7 +818,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
return r;
}
- if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
+ if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
r = dhcp6_option_append_pd(&opt, &optlen, &client->lease->pd, NULL);
if (r < 0)
return r;
@@ -808,9 +827,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
break;
case DHCP6_STATE_REBIND:
- message->type = DHCP6_REBIND;
+ message->type = DHCP6_MESSAGE_REBIND;
- if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) {
+ if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA)) {
r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia);
if (r < 0)
return r;
@@ -824,7 +843,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
if (client->mudurl) {
r = dhcp6_option_append(&opt, &optlen,
- SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl),
+ SD_DHCP6_OPTION_MUD_URL_V6, strlen(client->mudurl),
client->mudurl);
if (r < 0)
return r;
@@ -848,7 +867,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
return r;
}
- if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) {
+ if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
r = dhcp6_option_append_pd(&opt, &optlen, &client->lease->pd, NULL);
if (r < 0)
return r;
@@ -859,6 +878,8 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
case DHCP6_STATE_STOPPED:
case DHCP6_STATE_BOUND:
return -EINVAL;
+ default:
+ assert_not_reached();
}
r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ORO,
@@ -873,14 +894,12 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
if (r < 0)
return r;
- elapsed_usec = time_now - client->transaction_start;
- if (elapsed_usec < 0xffff * USEC_PER_MSEC * 10)
- elapsed_time = htobe16(elapsed_usec / USEC_PER_MSEC / 10);
- else
- elapsed_time = 0xffff;
-
- r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ELAPSED_TIME,
- sizeof(elapsed_time), &elapsed_time);
+ /* RFC 8415 Section 21.9.
+ * A client MUST include an Elapsed Time option in messages to indicate how long the client has
+ * been trying to complete a DHCP message exchange. */
+ elapsed_usec = MIN(usec_sub_unsigned(time_now, client->transaction_start) / USEC_PER_MSEC / 10, (usec_t) UINT16_MAX);
+ elapsed_time = htobe16(elapsed_usec);
+ r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ELAPSED_TIME, sizeof(elapsed_time), &elapsed_time);
if (r < 0)
return r;
@@ -936,7 +955,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void *userdata) {
sd_dhcp6_client *client = userdata;
DHCP6_CLIENT_DONT_DESTROY(client);
- enum DHCP6State state;
+ DHCP6State state;
assert(s);
assert(client);
@@ -980,7 +999,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
case DHCP6_STATE_SOLICITATION:
- if (client->retransmit_count && client->lease) {
+ if (client->retransmit_count > 0 && client->lease) {
client_start(client, DHCP6_STATE_REQUEST);
return 0;
}
@@ -1027,6 +1046,8 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda
case DHCP6_STATE_STOPPED:
case DHCP6_STATE_BOUND:
return 0;
+ default:
+ assert_not_reached();
}
if (max_retransmit_count > 0 &&
@@ -1051,8 +1072,8 @@ 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 > 0 &&
- client->retransmit_time > max_retransmit_time / 2)
+ assert(max_retransmit_time > 0);
+ if (client->retransmit_time > max_retransmit_time / 2)
client->retransmit_time = client_timeout_compute_random(max_retransmit_time);
else
client->retransmit_time += client_timeout_compute_random(client->retransmit_time);
@@ -1113,7 +1134,7 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
return 0;
}
-static int client_parse_message(
+int client_parse_message(
sd_dhcp6_client *client,
DHCP6Message *message,
size_t len,
@@ -1121,7 +1142,6 @@ static int client_parse_message(
uint32_t lt_t1 = UINT32_MAX, lt_t2 = UINT32_MAX;
usec_t irt = IRT_DEFAULT;
- bool clientid = false;
int r;
assert(client);
@@ -1141,23 +1161,19 @@ static int client_parse_message(
switch (optcode) {
case SD_DHCP6_OPTION_CLIENTID:
- if (clientid)
- return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s contains multiple clientids",
+ if (dhcp6_lease_get_clientid(lease, NULL, NULL) >= 0)
+ return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s contains multiple client IDs",
dhcp6_message_type_to_string(message->type));
- if (optlen != client->duid_len ||
- memcmp(&client->duid, optval, optlen) != 0)
- return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s DUID does not match",
- dhcp6_message_type_to_string(message->type));
-
- clientid = true;
+ r = dhcp6_lease_set_clientid(lease, optval, optlen);
+ if (r < 0)
+ return r;
break;
case SD_DHCP6_OPTION_SERVERID:
- r = dhcp6_lease_get_serverid(lease, NULL, NULL);
- if (r >= 0)
- return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s contains multiple serverids",
+ if (dhcp6_lease_get_serverid(lease, NULL, NULL) >= 0)
+ return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s contains multiple server IDs",
dhcp6_message_type_to_string(message->type));
r = dhcp6_lease_set_serverid(lease, optval, optlen);
@@ -1255,35 +1271,35 @@ static int client_parse_message(
case SD_DHCP6_OPTION_DNS_SERVERS:
r = dhcp6_lease_add_dns(lease, optval, optlen);
if (r < 0)
- return r;
+ log_dhcp6_client_errno(client, r, "Failed to parse DNS server option, ignoring: %m");
break;
case SD_DHCP6_OPTION_DOMAIN_LIST:
r = dhcp6_lease_add_domains(lease, optval, optlen);
if (r < 0)
- return r;
+ log_dhcp6_client_errno(client, r, "Failed to parse domain list option, ignoring: %m");
break;
case SD_DHCP6_OPTION_NTP_SERVER:
r = dhcp6_lease_add_ntp(lease, optval, optlen);
if (r < 0)
- return r;
+ log_dhcp6_client_errno(client, r, "Failed to parse NTP server option, ignoring: %m");
break;
case SD_DHCP6_OPTION_SNTP_SERVERS:
r = dhcp6_lease_add_sntp(lease, optval, optlen);
if (r < 0)
- return r;
+ log_dhcp6_client_errno(client, r, "Failed to parse SNTP server option, ignoring: %m");
break;
- case SD_DHCP6_OPTION_FQDN:
+ case SD_DHCP6_OPTION_CLIENT_FQDN:
r = dhcp6_lease_set_fqdn(lease, optval, optlen);
if (r < 0)
- return r;
+ log_dhcp6_client_errno(client, r, "Failed to parse FQDN option, ignoring: %m");
break;
@@ -1296,8 +1312,15 @@ static int client_parse_message(
}
}
- if (!clientid)
- return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s has incomplete options",
+ uint8_t *clientid;
+ size_t clientid_len;
+ if (dhcp6_lease_get_clientid(lease, &clientid, &clientid_len) < 0)
+ return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s message does not contain client ID. Ignoring.",
+ dhcp6_message_type_to_string(message->type));
+
+ if (clientid_len != client->duid_len ||
+ memcmp(clientid, &client->duid, clientid_len) != 0)
+ return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "The client ID in %s message does not match. Ignoring.",
dhcp6_message_type_to_string(message->type));
if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
@@ -1325,21 +1348,32 @@ static int client_parse_message(
return 0;
}
-static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) {
+static int client_receive_reply(
+ sd_dhcp6_client *client,
+ DHCP6Message *reply,
+ size_t len,
+ const triple_timestamp *t,
+ const struct in6_addr *server_address) {
+
_cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
bool rapid_commit;
int r;
assert(client);
assert(reply);
+ assert(t);
- if (reply->type != DHCP6_REPLY)
+ if (reply->type != DHCP6_MESSAGE_REPLY)
return 0;
r = dhcp6_lease_new(&lease);
if (r < 0)
return -ENOMEM;
+ lease->timestamp = *t;
+ if (server_address)
+ lease->server_address = *server_address;
+
r = client_parse_message(client, reply, len, lease);
if (r < 0)
return r;
@@ -1359,18 +1393,32 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si
return DHCP6_STATE_BOUND;
}
-static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) {
+static int client_receive_advertise(
+ sd_dhcp6_client *client,
+ DHCP6Message *advertise,
+ size_t len,
+ const triple_timestamp *t,
+ const struct in6_addr *server_address) {
+
_cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
uint8_t pref_advertise = 0, pref_lease = 0;
int r;
- if (advertise->type != DHCP6_ADVERTISE)
+ assert(client);
+ assert(advertise);
+ assert(t);
+
+ if (advertise->type != DHCP6_MESSAGE_ADVERTISE)
return 0;
r = dhcp6_lease_new(&lease);
if (r < 0)
return r;
+ lease->timestamp = *t;
+ if (server_address)
+ lease->server_address = *server_address;
+
r = client_parse_message(client, advertise, len, lease);
if (r < 0)
return r;
@@ -1401,7 +1449,22 @@ static int client_receive_message(
sd_dhcp6_client *client = userdata;
DHCP6_CLIENT_DONT_DESTROY(client);
+ /* This needs to be initialized with zero. See #20741. */
+ CMSG_BUFFER_TYPE(CMSG_SPACE_TIMEVAL) control = {};
+ struct iovec iov;
+ union sockaddr_union sa = {};
+ struct msghdr msg = {
+ .msg_name = &sa.sa,
+ .msg_namelen = sizeof(sa),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+ struct cmsghdr *cmsg;
+ triple_timestamp t = {};
_cleanup_free_ DHCP6Message *message = NULL;
+ struct in6_addr *server_address = NULL;
ssize_t buflen, len;
int r = 0;
@@ -1410,52 +1473,59 @@ static int client_receive_message(
assert(client->event);
buflen = next_datagram_size_fd(fd);
- if (buflen == -ENETDOWN)
- /* the link is down. Don't return an error or the I/O event
- source will be disconnected and we won't be able to receive
- packets again when the link comes back. */
+ if (buflen < 0) {
+ if (ERRNO_IS_TRANSIENT(buflen) || ERRNO_IS_DISCONNECT(buflen))
+ return 0;
+
+ log_dhcp6_client_errno(client, buflen, "Failed to determine datagram size to read, ignoring: %m");
return 0;
- if (buflen < 0)
- return buflen;
+ }
message = malloc(buflen);
if (!message)
return -ENOMEM;
- len = recv(fd, message, buflen, 0);
+ iov = IOVEC_MAKE(message, buflen);
+
+ len = recvmsg_safe(fd, &msg, MSG_DONTWAIT);
if (len < 0) {
- /* see comment above for why we shouldn't error out on ENETDOWN. */
- if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
+ if (ERRNO_IS_TRANSIENT(len) || ERRNO_IS_DISCONNECT(len))
return 0;
- return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m");
-
+ log_dhcp6_client_errno(client, len, "Could not receive message from UDP socket, ignoring: %m");
+ return 0;
}
if ((size_t) len < sizeof(DHCP6Message)) {
log_dhcp6_client(client, "Too small to be DHCP6 message: ignoring");
return 0;
}
- switch(message->type) {
- case DHCP6_SOLICIT:
- case DHCP6_REQUEST:
- case DHCP6_CONFIRM:
- case DHCP6_RENEW:
- case DHCP6_REBIND:
- case DHCP6_RELEASE:
- case DHCP6_DECLINE:
- case DHCP6_INFORMATION_REQUEST:
- case DHCP6_RELAY_FORW:
- case DHCP6_RELAY_REPL:
- return 0;
+ /* msg_namelen == 0 happens when running the test-suite over a socketpair */
+ if (msg.msg_namelen > 0) {
+ if (msg.msg_namelen != sizeof(struct sockaddr_in6) || sa.in6.sin6_family != AF_INET6) {
+ log_dhcp6_client(client, "Received message from invalid source, ignoring.");
+ return 0;
+ }
- case DHCP6_ADVERTISE:
- case DHCP6_REPLY:
- case DHCP6_RECONFIGURE:
- break;
+ server_address = &sa.in6.sin6_addr;
+ }
- default:
- log_dhcp6_client(client, "Unknown message type %d", message->type);
+ CMSG_FOREACH(cmsg, &msg) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SO_TIMESTAMP &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
+ triple_timestamp_from_realtime(&t, timeval_load((struct timeval*) CMSG_DATA(cmsg)));
+ }
+
+ if (!triple_timestamp_is_set(&t))
+ triple_timestamp_get(&t);
+
+ if (!IN_SET(message->type, DHCP6_MESSAGE_ADVERTISE, DHCP6_MESSAGE_REPLY, DHCP6_MESSAGE_RECONFIGURE)) {
+ const char *type_str = dhcp6_message_type_to_string(message->type);
+ if (type_str)
+ log_dhcp6_client(client, "Received unexpected %s message, ignoring.", type_str);
+ else
+ log_dhcp6_client(client, "Received unsupported message type %u, ignoring.", message->type);
return 0;
}
@@ -1464,7 +1534,7 @@ static int client_receive_message(
switch (client->state) {
case DHCP6_STATE_INFORMATION_REQUEST:
- r = client_receive_reply(client, message, len);
+ r = client_receive_reply(client, message, len, &t, server_address);
if (r < 0) {
log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
return 0;
@@ -1477,7 +1547,7 @@ static int client_receive_message(
break;
case DHCP6_STATE_SOLICITATION:
- r = client_receive_advertise(client, message, len);
+ r = client_receive_advertise(client, message, len, &t, server_address);
if (r < 0) {
log_dhcp6_client_errno(client, r, "Failed to process received advertise message, ignoring: %m");
return 0;
@@ -1493,7 +1563,7 @@ static int client_receive_message(
case DHCP6_STATE_RENEW:
case DHCP6_STATE_REBIND:
- r = client_receive_reply(client, message, len);
+ r = client_receive_reply(client, message, len, &t, server_address);
if (r < 0) {
log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m");
return 0;
@@ -1517,6 +1587,8 @@ static int client_receive_message(
case DHCP6_STATE_STOPPED:
return 0;
+ default:
+ assert_not_reached();
}
log_dhcp6_client(client, "Recv %s",
@@ -1530,14 +1602,14 @@ static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1,
assert_return(client, -EINVAL);
assert_return(client->lease, -EINVAL);
- if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
+ if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) {
*lifetime_t1 = be32toh(client->lease->ia.ia_na.lifetime_t1);
*lifetime_t2 = be32toh(client->lease->ia.ia_na.lifetime_t2);
return 0;
}
- if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
+ if (FLAGS_SET(client->request_ia, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) {
*lifetime_t1 = be32toh(client->lease->pd.ia_pd.lifetime_t1);
*lifetime_t2 = be32toh(client->lease->pd.ia_pd.lifetime_t2);
@@ -1547,7 +1619,7 @@ static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1,
return -ENOMSG;
}
-static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
+static int client_start(sd_dhcp6_client *client, DHCP6State state) {
int r;
usec_t timeout, time_now;
uint32_t lifetime_t1, lifetime_t2;
@@ -1647,6 +1719,8 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
client->state = state;
return 0;
+ default:
+ assert_not_reached();
}
client->transaction_id = random_u32() & htobe32(0x00ffffff);
@@ -1685,7 +1759,7 @@ int sd_dhcp6_client_is_running(sd_dhcp6_client *client) {
}
int sd_dhcp6_client_start(sd_dhcp6_client *client) {
- enum DHCP6State state = DHCP6_STATE_SOLICITATION;
+ DHCP6State state = DHCP6_STATE_SOLICITATION;
int r;
assert_return(client, -EINVAL);
@@ -1696,7 +1770,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
if (client->state != DHCP6_STATE_STOPPED)
return -EBUSY;
- if (!client->information_request && !client->request)
+ if (!client->information_request && client->request_ia == 0)
return -EINVAL;
r = client_reset(client);
@@ -1824,7 +1898,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
.ia_na.type = SD_DHCP6_OPTION_IA_NA,
.ia_pd.type = SD_DHCP6_OPTION_IA_PD,
.ifindex = -1,
- .request = DHCP6_REQUEST_IA_NA,
+ .request_ia = DHCP6_REQUEST_IA_NA | DHCP6_REQUEST_IA_PD,
.fd = -1,
.req_opts_len = ELEMENTSOF(default_req_opts),
.hint_pd_prefix.iapdprefix.lifetime_preferred = (be32_t) -1,
diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c
index 85649d92ee..b46a2e3341 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c
@@ -13,6 +13,27 @@
#include "strv.h"
#include "util.h"
+int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret) {
+ assert_return(lease, -EINVAL);
+ assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
+ assert_return(clock_supported(clock), -EOPNOTSUPP);
+ assert_return(ret, -EINVAL);
+
+ if (!triple_timestamp_is_set(&lease->timestamp))
+ return -ENODATA;
+
+ *ret = triple_timestamp_by_clock(&lease->timestamp, clock);
+ return 0;
+}
+
+int sd_dhcp6_lease_get_server_address(sd_dhcp6_lease *lease, struct in6_addr *ret) {
+ assert_return(lease, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ *ret = lease->server_address;
+ return 0;
+}
+
int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) {
DHCP6Address *addr;
uint32_t valid = 0, t;
@@ -52,12 +73,43 @@ DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) {
return NULL;
}
-int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id,
- size_t len) {
+int dhcp6_lease_set_clientid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len) {
+ uint8_t *clientid;
+
+ assert_return(lease, -EINVAL);
+ assert_return(id, -EINVAL);
+ assert_return(len > 0, -EINVAL);
+
+ clientid = memdup(id, len);
+ if (!clientid)
+ return -ENOMEM;
+
+ free_and_replace(lease->clientid, clientid);
+ lease->clientid_len = len;
+
+ return 0;
+}
+
+int dhcp6_lease_get_clientid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len) {
+ assert_return(lease, -EINVAL);
+
+ if (!lease->clientid)
+ return -ENODATA;
+
+ if (ret_id)
+ *ret_id = lease->clientid;
+ if (ret_len)
+ *ret_len = lease->clientid_len;
+
+ return 0;
+}
+
+int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len) {
uint8_t *serverid;
assert_return(lease, -EINVAL);
assert_return(id, -EINVAL);
+ assert_return(len > 0, -EINVAL);
serverid = memdup(id, len);
if (!serverid)
@@ -69,16 +121,16 @@ int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id,
return 0;
}
-int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len) {
+int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len) {
assert_return(lease, -EINVAL);
if (!lease->serverid)
- return -ENOMSG;
+ return -ENODATA;
- if (id)
- *id = lease->serverid;
- if (len)
- *len = lease->serverid_len;
+ if (ret_id)
+ *ret_id = lease->serverid;
+ if (ret_len)
+ *ret_len = lease->serverid_len;
return 0;
}
@@ -119,24 +171,6 @@ int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit) {
return 0;
}
-int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
- assert_return(lease, -EINVAL);
- assert_return(iaid, -EINVAL);
-
- *iaid = lease->ia.ia_na.id;
-
- return 0;
-}
-
-int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid) {
- assert_return(lease, -EINVAL);
- assert_return(iaid, -EINVAL);
-
- *iaid = lease->pd.ia_pd.id;
-
- return 0;
-}
-
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,
uint32_t *lifetime_preferred,
uint32_t *lifetime_valid) {
@@ -207,12 +241,13 @@ int dhcp6_lease_add_dns(sd_dhcp6_lease *lease, const uint8_t *optval, size_t opt
int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **ret) {
assert_return(lease, -EINVAL);
- assert_return(ret, -EINVAL);
if (!lease->dns)
return -ENOENT;
- *ret = lease->dns;
+ if (ret)
+ *ret = lease->dns;
+
return lease->dns_count;
}
@@ -305,16 +340,17 @@ int dhcp6_lease_add_sntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t op
int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, const struct in6_addr **ret) {
assert_return(lease, -EINVAL);
- assert_return(ret, -EINVAL);
if (lease->ntp) {
- *ret = lease->ntp;
+ if (ret)
+ *ret = lease->ntp;
return lease->ntp_count;
}
if (lease->sntp && !lease->ntp_fqdn) {
/* Fallback to the deprecated SNTP option. */
- *ret = lease->sntp;
+ if (ret)
+ *ret = lease->sntp;
return lease->sntp_count;
}
@@ -323,12 +359,12 @@ int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, const struct in6_addr **
int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ret) {
assert_return(lease, -EINVAL);
- assert_return(ret, -EINVAL);
if (!lease->ntp_fqdn)
return -ENOENT;
- *ret = lease->ntp_fqdn;
+ if (ret)
+ *ret = lease->ntp_fqdn;
return strv_length(lease->ntp_fqdn);
}
@@ -366,6 +402,7 @@ static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
if (!lease)
return NULL;
+ free(lease->clientid);
free(lease->serverid);
dhcp6_lease_free_ia(&lease->ia);
dhcp6_lease_free_ia(&lease->pd);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c b/src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c
index 9da2b14946..f50e9c8db0 100644
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c
+++ b/src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c
@@ -202,6 +202,9 @@ static int lldp_rx_receive_datagram(sd_event_source *s, int fd, uint32_t revents
space = next_datagram_size_fd(fd);
if (space < 0) {
+ if (ERRNO_IS_TRANSIENT(space) || ERRNO_IS_DISCONNECT(space))
+ return 0;
+
log_lldp_rx_errno(lldp_rx, space, "Failed to determine datagram size to read, ignoring: %m");
return 0;
}
@@ -214,7 +217,7 @@ static int lldp_rx_receive_datagram(sd_event_source *s, int fd, uint32_t revents
length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT);
if (length < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno) || ERRNO_IS_DISCONNECT(errno))
return 0;
log_lldp_rx_errno(lldp_rx, errno, "Failed to read LLDP datagram, ignoring: %m");
@@ -251,7 +254,7 @@ int sd_lldp_rx_is_running(sd_lldp_rx *lldp_rx) {
return lldp_rx->fd >= 0;
}
-_public_ int sd_lldp_rx_start(sd_lldp_rx *lldp_rx) {
+int sd_lldp_rx_start(sd_lldp_rx *lldp_rx) {
int r;
assert_return(lldp_rx, -EINVAL);
@@ -285,7 +288,7 @@ fail:
return r;
}
-_public_ int sd_lldp_rx_stop(sd_lldp_rx *lldp_rx) {
+int sd_lldp_rx_stop(sd_lldp_rx *lldp_rx) {
if (!sd_lldp_rx_is_running(lldp_rx))
return 0;
@@ -297,7 +300,7 @@ _public_ int sd_lldp_rx_stop(sd_lldp_rx *lldp_rx) {
return 1;
}
-_public_ int sd_lldp_rx_attach_event(sd_lldp_rx *lldp_rx, sd_event *event, int64_t priority) {
+int sd_lldp_rx_attach_event(sd_lldp_rx *lldp_rx, sd_event *event, int64_t priority) {
int r;
assert_return(lldp_rx, -EINVAL);
@@ -317,7 +320,7 @@ _public_ int sd_lldp_rx_attach_event(sd_lldp_rx *lldp_rx, sd_event *event, int64
return 0;
}
-_public_ int sd_lldp_rx_detach_event(sd_lldp_rx *lldp_rx) {
+int sd_lldp_rx_detach_event(sd_lldp_rx *lldp_rx) {
assert_return(lldp_rx, -EINVAL);
assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
@@ -327,13 +330,13 @@ _public_ int sd_lldp_rx_detach_event(sd_lldp_rx *lldp_rx) {
return 0;
}
-_public_ sd_event* sd_lldp_rx_get_event(sd_lldp_rx *lldp_rx) {
+sd_event* sd_lldp_rx_get_event(sd_lldp_rx *lldp_rx) {
assert_return(lldp_rx, NULL);
return lldp_rx->event;
}
-_public_ int sd_lldp_rx_set_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_callback_t cb, void *userdata) {
+int sd_lldp_rx_set_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_callback_t cb, void *userdata) {
assert_return(lldp_rx, -EINVAL);
lldp_rx->callback = cb;
@@ -342,7 +345,7 @@ _public_ int sd_lldp_rx_set_callback(sd_lldp_rx *lldp_rx, sd_lldp_rx_callback_t
return 0;
}
-_public_ int sd_lldp_rx_set_ifindex(sd_lldp_rx *lldp_rx, int ifindex) {
+int sd_lldp_rx_set_ifindex(sd_lldp_rx *lldp_rx, int ifindex) {
assert_return(lldp_rx, -EINVAL);
assert_return(ifindex > 0, -EINVAL);
assert_return(!sd_lldp_rx_is_running(lldp_rx), -EBUSY);
@@ -394,7 +397,7 @@ static sd_lldp_rx *lldp_rx_free(sd_lldp_rx *lldp_rx) {
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_lldp_rx, sd_lldp_rx, lldp_rx_free);
-_public_ int sd_lldp_rx_new(sd_lldp_rx **ret) {
+int sd_lldp_rx_new(sd_lldp_rx **ret) {
_cleanup_(sd_lldp_rx_unrefp) sd_lldp_rx *lldp_rx = NULL;
assert_return(ret, -EINVAL);
@@ -462,7 +465,7 @@ static inline int neighbor_compare_func(sd_lldp_neighbor * const *a, sd_lldp_nei
return lldp_neighbor_id_compare_func(&(*a)->id, &(*b)->id);
}
-_public_ int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***ret) {
+int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***ret) {
_cleanup_free_ sd_lldp_neighbor **l = NULL;
sd_lldp_neighbor *n;
int k = 0;
@@ -491,7 +494,7 @@ _public_ int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***r
return k;
}
-_public_ int sd_lldp_rx_set_neighbors_max(sd_lldp_rx *lldp_rx, uint64_t m) {
+int sd_lldp_rx_set_neighbors_max(sd_lldp_rx *lldp_rx, uint64_t m) {
assert_return(lldp_rx, -EINVAL);
assert_return(m > 0, -EINVAL);
@@ -501,7 +504,7 @@ _public_ int sd_lldp_rx_set_neighbors_max(sd_lldp_rx *lldp_rx, uint64_t m) {
return 0;
}
-_public_ int sd_lldp_rx_match_capabilities(sd_lldp_rx *lldp_rx, uint16_t mask) {
+int sd_lldp_rx_match_capabilities(sd_lldp_rx *lldp_rx, uint16_t mask) {
assert_return(lldp_rx, -EINVAL);
assert_return(mask != 0, -EINVAL);
@@ -510,7 +513,7 @@ _public_ int sd_lldp_rx_match_capabilities(sd_lldp_rx *lldp_rx, uint16_t mask) {
return 0;
}
-_public_ int sd_lldp_rx_set_filter_address(sd_lldp_rx *lldp_rx, const struct ether_addr *addr) {
+int sd_lldp_rx_set_filter_address(sd_lldp_rx *lldp_rx, const struct ether_addr *addr) {
assert_return(lldp_rx, -EINVAL);
/* In order to deal nicely with bridges that send back our own packets, allow one address to be filtered, so
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h b/src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h
index 08b409fef1..74cbc26962 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h
+++ b/src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h
@@ -71,6 +71,7 @@ struct sd_event_source {
uint64_t prepare_iteration;
sd_event_destroy_t destroy_callback;
+ sd_event_handler_t ratelimit_expire_callback;
LIST_FIELDS(sd_event_source, sources);
@@ -214,6 +215,11 @@ struct inotify_data {
* the events locally if they can't be coalesced). */
unsigned n_pending;
+ /* If this counter is non-zero, don't GC the inotify data object even if not used to watch any inode
+ * anymore. This is useful to pin the object for a bit longer, after the last event source needing it
+ * is gone. */
+ unsigned n_busy;
+
/* A linked list of all inotify objects with data already read, that still need processing. We keep this list
* to make it efficient to figure out what inotify objects to process data on next. */
LIST_FIELDS(struct inotify_data, buffered);
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c
index 7cc55be101..13e16f9b31 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c
@@ -86,6 +86,30 @@ int event_reset_time(
return created;
}
+int event_reset_time_relative(
+ sd_event *e,
+ sd_event_source **s,
+ clockid_t clock,
+ uint64_t usec,
+ uint64_t accuracy,
+ sd_event_time_handler_t callback,
+ void *userdata,
+ int64_t priority,
+ const char *description,
+ bool force_reset) {
+
+ usec_t usec_now;
+ int r;
+
+ assert(e);
+
+ r = sd_event_now(e, clock, &usec_now);
+ if (r < 0)
+ return log_debug_errno(r, "sd-event: Failed to get the current time: %m");
+
+ return event_reset_time(e, s, clock, usec_add(usec_now, usec), accuracy, callback, userdata, priority, description, force_reset);
+}
+
int event_source_disable(sd_event_source *s) {
if (!s)
return 0;
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h
index c8f97bc8d6..64a4199244 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h
+++ b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h
@@ -5,9 +5,27 @@
#include "sd-event.h"
-int event_reset_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,
- int64_t priority, const char *description, bool force_reset);
+int event_reset_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,
+ int64_t priority,
+ const char *description,
+ bool force_reset);
+int event_reset_time_relative(
+ sd_event *e,
+ sd_event_source **s,
+ clockid_t clock,
+ uint64_t usec,
+ uint64_t accuracy,
+ sd_event_time_handler_t callback,
+ void *userdata,
+ int64_t priority,
+ const char *description,
+ bool force_reset);
int event_source_disable(sd_event_source *s);
int event_source_is_enabled(sd_event_source *s);
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
index 0acbdd540e..e87d900c4a 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c
@@ -1824,6 +1824,29 @@ static void event_free_inode_data(
free(d);
}
+static void event_gc_inotify_data(
+ sd_event *e,
+ struct inotify_data *d) {
+
+ assert(e);
+
+ /* GCs the inotify data object if we don't need it anymore. That's the case if we don't want to watch
+ * any inode with it anymore, which in turn happens if no event source of this priority is interested
+ * in any inode any longer. That said, we maintain an extra busy counter: if non-zero we'll delay GC
+ * (under the expectation that the GC is called again once the counter is decremented). */
+
+ if (!d)
+ return;
+
+ if (!hashmap_isempty(d->inodes))
+ return;
+
+ if (d->n_busy > 0)
+ return;
+
+ event_free_inotify_data(e, d);
+}
+
static void event_gc_inode_data(
sd_event *e,
struct inode_data *d) {
@@ -1841,8 +1864,7 @@ static void event_gc_inode_data(
inotify_data = d->inotify_data;
event_free_inode_data(e, d);
- if (inotify_data && hashmap_isempty(inotify_data->inodes))
- event_free_inotify_data(e, inotify_data);
+ event_gc_inotify_data(e, inotify_data);
}
static int event_make_inode_data(
@@ -1971,24 +1993,25 @@ static int inotify_exit_callback(sd_event_source *s, const struct inotify_event
return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
}
-_public_ int sd_event_add_inotify(
+static int event_add_inotify_fd_internal(
sd_event *e,
sd_event_source **ret,
- const char *path,
+ int fd,
+ bool donate,
uint32_t mask,
sd_event_inotify_handler_t callback,
void *userdata) {
+ _cleanup_close_ int donated_fd = donate ? fd : -1;
+ _cleanup_(source_freep) sd_event_source *s = NULL;
struct inotify_data *inotify_data = NULL;
struct inode_data *inode_data = NULL;
- _cleanup_close_ int fd = -1;
- _cleanup_(source_freep) sd_event_source *s = NULL;
struct stat st;
int r;
assert_return(e, -EINVAL);
assert_return(e = event_resolve(e), -ENOPKG);
- assert_return(path, -EINVAL);
+ assert_return(fd >= 0, -EBADF);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
@@ -2001,12 +2024,6 @@ _public_ int sd_event_add_inotify(
if (mask & IN_MASK_ADD)
return -EINVAL;
- fd = open(path, O_PATH|O_CLOEXEC|
- (mask & IN_ONLYDIR ? O_DIRECTORY : 0)|
- (mask & IN_DONT_FOLLOW ? O_NOFOLLOW : 0));
- if (fd < 0)
- return -errno;
-
if (fstat(fd, &st) < 0)
return -errno;
@@ -2026,14 +2043,24 @@ _public_ int sd_event_add_inotify(
r = event_make_inode_data(e, inotify_data, st.st_dev, st.st_ino, &inode_data);
if (r < 0) {
- event_free_inotify_data(e, inotify_data);
+ event_gc_inotify_data(e, inotify_data);
return r;
}
/* Keep the O_PATH fd around until the first iteration of the loop, so that we can still change the priority of
* the event source, until then, for which we need the original inode. */
if (inode_data->fd < 0) {
- inode_data->fd = TAKE_FD(fd);
+ if (donated_fd >= 0)
+ inode_data->fd = TAKE_FD(donated_fd);
+ else {
+ inode_data->fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (inode_data->fd < 0) {
+ r = -errno;
+ event_gc_inode_data(e, inode_data);
+ return r;
+ }
+ }
+
LIST_PREPEND(to_close, e->inode_data_to_close, inode_data);
}
@@ -2046,8 +2073,6 @@ _public_ int sd_event_add_inotify(
if (r < 0)
return r;
- (void) sd_event_source_set_description(s, path);
-
if (ret)
*ret = s;
TAKE_PTR(s);
@@ -2055,6 +2080,48 @@ _public_ int sd_event_add_inotify(
return 0;
}
+_public_ int sd_event_add_inotify_fd(
+ sd_event *e,
+ sd_event_source **ret,
+ int fd,
+ uint32_t mask,
+ sd_event_inotify_handler_t callback,
+ void *userdata) {
+
+ return event_add_inotify_fd_internal(e, ret, fd, /* donate= */ false, mask, callback, userdata);
+}
+
+_public_ int sd_event_add_inotify(
+ sd_event *e,
+ sd_event_source **ret,
+ const char *path,
+ uint32_t mask,
+ sd_event_inotify_handler_t callback,
+ void *userdata) {
+
+ sd_event_source *s = NULL; /* avoid false maybe-uninitialized warning */
+ int fd, r;
+
+ assert_return(path, -EINVAL);
+
+ fd = open(path, O_PATH|O_CLOEXEC|
+ (mask & IN_ONLYDIR ? O_DIRECTORY : 0)|
+ (mask & IN_DONT_FOLLOW ? O_NOFOLLOW : 0));
+ if (fd < 0)
+ return -errno;
+
+ r = event_add_inotify_fd_internal(e, &s, fd, /* donate= */ true, mask, callback, userdata);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(s, path);
+
+ if (ret)
+ *ret = s;
+
+ return r;
+}
+
static sd_event_source* event_source_free(sd_event_source *s) {
if (!s)
return NULL;
@@ -2845,7 +2912,7 @@ fail:
return r;
}
-static int event_source_leave_ratelimit(sd_event_source *s) {
+static int event_source_leave_ratelimit(sd_event_source *s, bool run_callback) {
int r;
assert(s);
@@ -2877,6 +2944,30 @@ static int event_source_leave_ratelimit(sd_event_source *s) {
ratelimit_reset(&s->rate_limit);
log_debug("Event source %p (%s) left rate limit state.", s, strna(s->description));
+
+ if (run_callback && s->ratelimit_expire_callback) {
+ s->dispatching = true;
+ r = s->ratelimit_expire_callback(s, s->userdata);
+ s->dispatching = false;
+
+ if (r < 0) {
+ log_debug_errno(r, "Ratelimit expiry callback of event source %s (type %s) returned error, %s: %m",
+ strna(s->description),
+ event_source_type_to_string(s->type),
+ s->exit_on_failure ? "exiting" : "disabling");
+
+ if (s->exit_on_failure)
+ (void) sd_event_exit(s->event, r);
+ }
+
+ if (s->n_ref == 0)
+ source_free(s);
+ else if (r < 0)
+ assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
+
+ return 1;
+ }
+
return 0;
fail:
@@ -3055,7 +3146,7 @@ static int flush_timer(sd_event *e, int fd, uint32_t events, usec_t *next) {
ss = read(fd, &x, sizeof(x));
if (ss < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return -errno;
@@ -3076,6 +3167,7 @@ static int process_timer(
struct clock_data *d) {
sd_event_source *s;
+ bool callback_invoked = false;
int r;
assert(e);
@@ -3093,9 +3185,11 @@ static int process_timer(
* again. */
assert(s->ratelimited);
- r = event_source_leave_ratelimit(s);
+ r = event_source_leave_ratelimit(s, /* run_callback */ true);
if (r < 0)
return r;
+ else if (r == 1)
+ callback_invoked = true;
continue;
}
@@ -3110,7 +3204,7 @@ static int process_timer(
event_source_time_prioq_reshuffle(s);
}
- return 0;
+ return callback_invoked;
}
static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priority) {
@@ -3258,7 +3352,7 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events, i
n = read(d->fd, &si, sizeof(si));
if (n < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return -errno;
@@ -3312,7 +3406,7 @@ static int event_inotify_data_read(sd_event *e, struct inotify_data *d, uint32_t
n = read(d->fd, &d->buffer, sizeof(d->buffer));
if (n < 0) {
- if (IN_SET(errno, EAGAIN, EINTR))
+ if (ERRNO_IS_TRANSIENT(errno))
return 0;
return -errno;
@@ -3560,13 +3654,23 @@ static int source_dispatch(sd_event_source *s) {
sz = offsetof(struct inotify_event, name) + d->buffer.ev.len;
assert(d->buffer_filled >= sz);
+ /* If the inotify callback destroys the event source then this likely means we don't need to
+ * watch the inode anymore, and thus also won't need the inotify object anymore. But if we'd
+ * free it immediately, then we couldn't drop the event from the inotify event queue without
+ * memory corruption anymore, as below. Hence, let's not free it immediately, but mark it
+ * "busy" with a counter (which will ensure it's not GC'ed away prematurely). Let's then
+ * explicitly GC it after we are done dropping the inotify event from the buffer. */
+ d->n_busy++;
r = s->inotify.callback(s, &d->buffer.ev, s->userdata);
+ d->n_busy--;
- /* When no event is pending anymore on this inotify object, then let's drop the event from the
- * buffer. */
+ /* When no event is pending anymore on this inotify object, then let's drop the event from
+ * the inotify event queue buffer. */
if (d->n_pending == 0)
event_inotify_data_drop(e, d, sz);
+ /* Now we don't want to access 'd' anymore, it's OK to GC now. */
+ event_gc_inotify_data(e, d);
break;
}
@@ -3591,7 +3695,7 @@ static int source_dispatch(sd_event_source *s) {
if (s->n_ref == 0)
source_free(s);
else if (r < 0)
- sd_event_source_set_enabled(s, SD_EVENT_OFF);
+ assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
return 1;
}
@@ -3632,7 +3736,7 @@ static int event_prepare(sd_event *e) {
if (s->n_ref == 0)
source_free(s);
else if (r < 0)
- sd_event_source_set_enabled(s, SD_EVENT_OFF);
+ assert_se(sd_event_source_set_enabled(s, SD_EVENT_OFF) >= 0);
}
return 0;
@@ -3693,10 +3797,7 @@ static int arm_watchdog(sd_event *e) {
if (its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0)
its.it_value.tv_nsec = 1;
- if (timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL));
}
static int process_watchdog(sd_event *e) {
@@ -3806,7 +3907,7 @@ static int epoll_wait_usec(
int maxevents,
usec_t timeout) {
- int r, msec;
+ int msec;
#if 0
static bool epoll_pwait2_absent = false;
@@ -3846,14 +3947,7 @@ static int epoll_wait_usec(
msec = (int) k;
}
- r = epoll_wait(fd,
- events,
- maxevents,
- msec);
- if (r < 0)
- return -errno;
-
- return r;
+ return RET_NERRNO(epoll_wait(fd, events, maxevents, msec));
}
static int process_epoll(sd_event *e, usec_t timeout, int64_t threshold, int64_t *ret_min_priority) {
@@ -4024,15 +4118,15 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
if (r < 0)
goto finish;
- r = process_timer(e, e->timestamp.realtime, &e->realtime);
+ r = process_inotify(e);
if (r < 0)
goto finish;
- r = process_timer(e, e->timestamp.boottime, &e->boottime);
+ r = process_timer(e, e->timestamp.realtime, &e->realtime);
if (r < 0)
goto finish;
- r = process_timer(e, e->timestamp.monotonic, &e->monotonic);
+ r = process_timer(e, e->timestamp.boottime, &e->boottime);
if (r < 0)
goto finish;
@@ -4044,9 +4138,20 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
if (r < 0)
goto finish;
- r = process_inotify(e);
+ r = process_timer(e, e->timestamp.monotonic, &e->monotonic);
if (r < 0)
goto finish;
+ else if (r == 1) {
+ /* Ratelimit expiry callback was called. Let's postpone processing pending sources and
+ * put loop in the initial state in order to evaluate (in the next iteration) also sources
+ * there were potentially re-enabled by the callback.
+ *
+ * Wondering why we treat only this invocation of process_timer() differently? Once event
+ * source is ratelimited we essentially transform it into CLOCK_MONOTONIC timer hence
+ * ratelimit expiry callback is never called for any other timer type. */
+ r = 0;
+ goto finish;
+ }
if (event_next_pending(e)) {
e->state = SD_EVENT_PENDING;
@@ -4117,7 +4222,7 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) {
this_run = now(CLOCK_MONOTONIC);
- l = u64log2(this_run - e->last_run_usec);
+ l = log2u64(this_run - e->last_run_usec);
assert(l < ELEMENTSOF(e->delays));
e->delays[l]++;
@@ -4416,7 +4521,7 @@ _public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval
/* When ratelimiting is configured we'll always reset the rate limit state first and start fresh,
* non-ratelimited. */
- r = event_source_leave_ratelimit(s);
+ r = event_source_leave_ratelimit(s, /* run_callback */ false);
if (r < 0)
return r;
@@ -4424,6 +4529,13 @@ _public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval
return 0;
}
+_public_ int sd_event_source_set_ratelimit_expire_callback(sd_event_source *s, sd_event_handler_t callback) {
+ assert_return(s, -EINVAL);
+
+ s->ratelimit_expire_callback = callback;
+ return 0;
+}
+
_public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) {
assert_return(s, -EINVAL);
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c
index d80145a819..9ec2abc884 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c
@@ -224,7 +224,7 @@ int id128_get_product(sd_id128_t *ret) {
r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid);
if (r == -ENOENT)
- r = id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, &uuid);
+ r = id128_read("/proc/device-tree/vm,uuid", ID128_UUID, &uuid);
if (r < 0)
return r;
diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c b/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c
index 0860f49342..c3ed3bbb5b 100644
--- a/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c
@@ -6,21 +6,14 @@
#include <fcntl.h>
#include <unistd.h>
-#if HAVE_OPENSSL
-#include <openssl/hmac.h>
-#include <openssl/sha.h>
-#endif
-
#include "sd-id128.h"
#include "alloc-util.h"
#include "fd-util.h"
#include "hexdecoct.h"
+#include "hmac.h"
#include "id128-util.h"
#include "io-util.h"
-#if !HAVE_OPENSSL
-#include "khash.h"
-#endif
#include "macro.h"
#include "missing_syscall.h"
#include "random-util.h"
@@ -283,43 +276,15 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) {
}
static int get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret) {
+ uint8_t hmac[SHA256_DIGEST_SIZE];
sd_id128_t result;
assert(ret);
-#if HAVE_OPENSSL
- /* We prefer doing this in-process, since we this means we are not dependent on kernel configuration,
- * and this also works in locked down container environments. But some distros don't like OpenSSL's
- * license and its (in-) compatibility with GPL2, hence also support khash */
- uint8_t md[256/8];
- if (!HMAC(EVP_sha256(),
- &base, sizeof(base),
- (const unsigned char*) &app_id, sizeof(app_id),
- md, NULL))
- return -ENOTRECOVERABLE;
+ hmac_sha256(&base, sizeof(base), &app_id, sizeof(app_id), hmac);
/* Take only the first half. */
- memcpy(&result, md, MIN(sizeof(md), sizeof(result)));
-#else
- _cleanup_(khash_unrefp) khash *h = NULL;
- const void *p;
- int r;
-
- r = khash_new_with_key(&h, "hmac(sha256)", &base, sizeof(base));
- if (r < 0)
- return r;
-
- r = khash_put(h, &app_id, sizeof(app_id));
- if (r < 0)
- return r;
-
- r = khash_digest_data(h, &p);
- if (r < 0)
- return r;
-
- /* We chop off the trailing 16 bytes */
- memcpy(&result, p, MIN(khash_get_size(h), sizeof(result)));
-#endif
+ memcpy(&result, hmac, MIN(sizeof(hmac), sizeof(result)));
*ret = id128_make_v4_uuid(result);
return 0;
diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp-client.h b/src/libnm-systemd-core/src/systemd/sd-dhcp-client.h
index 23979b1232..4af4b45f2d 100644
--- a/src/libnm-systemd-core/src/systemd/sd-dhcp-client.h
+++ b/src/libnm-systemd-core/src/systemd/sd-dhcp-client.h
@@ -45,65 +45,66 @@ enum {
};
enum {
- SD_DHCP_OPTION_PAD = 0,
- SD_DHCP_OPTION_SUBNET_MASK = 1,
- SD_DHCP_OPTION_TIME_OFFSET = 2,
- SD_DHCP_OPTION_ROUTER = 3,
- SD_DHCP_OPTION_DOMAIN_NAME_SERVER = 6,
- SD_DHCP_OPTION_LPR_SERVER = 9,
- SD_DHCP_OPTION_HOST_NAME = 12,
- SD_DHCP_OPTION_BOOT_FILE_SIZE = 13,
- SD_DHCP_OPTION_DOMAIN_NAME = 15,
- SD_DHCP_OPTION_ROOT_PATH = 17,
- SD_DHCP_OPTION_ENABLE_IP_FORWARDING = 19,
- SD_DHCP_OPTION_ENABLE_IP_FORWARDING_NL = 20,
- SD_DHCP_OPTION_POLICY_FILTER = 21,
- SD_DHCP_OPTION_INTERFACE_MDR = 22,
- SD_DHCP_OPTION_INTERFACE_TTL = 23,
- SD_DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT = 24,
- SD_DHCP_OPTION_INTERFACE_MTU = 26,
- SD_DHCP_OPTION_BROADCAST = 28,
- /* Windows 10 option to send when Anonymize=true */
- SD_DHCP_OPTION_ROUTER_DISCOVER = 31,
- SD_DHCP_OPTION_STATIC_ROUTE = 33,
- SD_DHCP_OPTION_NTP_SERVER = 42,
- SD_DHCP_OPTION_VENDOR_SPECIFIC = 43,
- /* Windows 10 option to send when Anonymize=true */
- SD_DHCP_OPTION_NETBIOS_NAMESERVER = 44,
- /* Windows 10 option to send when Anonymize=true */
- SD_DHCP_OPTION_NETBIOS_NODETYPE = 46,
- /* Windows 10 option to send when Anonymize=true */
- SD_DHCP_OPTION_NETBIOS_SCOPE = 47,
- SD_DHCP_OPTION_REQUESTED_IP_ADDRESS = 50,
- SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51,
- SD_DHCP_OPTION_OVERLOAD = 52,
- SD_DHCP_OPTION_MESSAGE_TYPE = 53,
- SD_DHCP_OPTION_SERVER_IDENTIFIER = 54,
- SD_DHCP_OPTION_PARAMETER_REQUEST_LIST = 55,
- SD_DHCP_OPTION_ERROR_MESSAGE = 56,
- SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57,
- SD_DHCP_OPTION_RENEWAL_T1_TIME = 58,
- 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_RELAY_AGENT_INFORMATION = 82,
- 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_MUD_URL = 161,
- SD_DHCP_OPTION_PRIVATE_BASE = 224,
- /* Windows 10 option to send when Anonymize=true */
+ SD_DHCP_OPTION_PAD = 0,
+ SD_DHCP_OPTION_SUBNET_MASK = 1,
+ SD_DHCP_OPTION_TIME_OFFSET = 2,
+ SD_DHCP_OPTION_ROUTER = 3,
+ SD_DHCP_OPTION_DOMAIN_NAME_SERVER = 6,
+ SD_DHCP_OPTION_LPR_SERVER = 9,
+ SD_DHCP_OPTION_HOST_NAME = 12,
+ SD_DHCP_OPTION_BOOT_FILE_SIZE = 13,
+ SD_DHCP_OPTION_DOMAIN_NAME = 15,
+ SD_DHCP_OPTION_ROOT_PATH = 17,
+ SD_DHCP_OPTION_ENABLE_IP_FORWARDING = 19,
+ SD_DHCP_OPTION_ENABLE_IP_FORWARDING_NL = 20,
+ SD_DHCP_OPTION_POLICY_FILTER = 21,
+ SD_DHCP_OPTION_INTERFACE_MDR = 22,
+ SD_DHCP_OPTION_INTERFACE_TTL = 23,
+ SD_DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT = 24,
+ SD_DHCP_OPTION_INTERFACE_MTU = 26,
+ SD_DHCP_OPTION_BROADCAST = 28,
+ /* Windows 10 option to send when Anonymize=true */
+ SD_DHCP_OPTION_ROUTER_DISCOVER = 31,
+ SD_DHCP_OPTION_STATIC_ROUTE = 33,
+ SD_DHCP_OPTION_NTP_SERVER = 42,
+ SD_DHCP_OPTION_VENDOR_SPECIFIC = 43,
+ /* Windows 10 option to send when Anonymize=true */
+ SD_DHCP_OPTION_NETBIOS_NAMESERVER = 44,
+ /* Windows 10 option to send when Anonymize=true */
+ SD_DHCP_OPTION_NETBIOS_NODETYPE = 46,
+ /* Windows 10 option to send when Anonymize=true */
+ SD_DHCP_OPTION_NETBIOS_SCOPE = 47,
+ SD_DHCP_OPTION_REQUESTED_IP_ADDRESS = 50,
+ SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51,
+ SD_DHCP_OPTION_OVERLOAD = 52,
+ SD_DHCP_OPTION_MESSAGE_TYPE = 53,
+ SD_DHCP_OPTION_SERVER_IDENTIFIER = 54,
+ SD_DHCP_OPTION_PARAMETER_REQUEST_LIST = 55,
+ SD_DHCP_OPTION_ERROR_MESSAGE = 56,
+ SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57,
+ SD_DHCP_OPTION_RENEWAL_T1_TIME = 58,
+ 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_RELAY_AGENT_INFORMATION = 82,
+ 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_MUD_URL = 161,
+ SD_DHCP_OPTION_6RD = 212,
+ SD_DHCP_OPTION_PRIVATE_BASE = 224,
+ /* Windows 10 option to send when Anonymize=true */
SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE = 249,
- /* Windows 10 option to send when Anonymize=true */
- SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY = 252,
- SD_DHCP_OPTION_PRIVATE_LAST = 254,
- SD_DHCP_OPTION_END = 255,
+ /* Windows 10 option to send when Anonymize=true */
+ SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY = 252,
+ SD_DHCP_OPTION_PRIVATE_LAST = 254,
+ SD_DHCP_OPTION_END = 255,
};
/* Suboptions for SD_DHCP_OPTION_RELAY_AGENT_INFORMATION option */
diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h b/src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h
index 5abf9a406c..478bbfd7a6 100644
--- a/src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h
+++ b/src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h
@@ -71,6 +71,13 @@ int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes);
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len);
int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len);
int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone);
+int sd_dhcp_lease_get_6rd(
+ sd_dhcp_lease *lease,
+ uint8_t *ret_ipv4masklen,
+ uint8_t *ret_prefixlen,
+ struct in6_addr *ret_prefix,
+ const struct in_addr **ret_br_addresses,
+ size_t *ret_n_br_addresses);
int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination);
int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length);
diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h
index f3889782bc..0e23c84e64 100644
--- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h
+++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h
@@ -39,44 +39,151 @@ enum {
SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13,
};
+/* https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-2 */
enum {
- SD_DHCP6_OPTION_CLIENTID = 1,
- SD_DHCP6_OPTION_SERVERID = 2,
- SD_DHCP6_OPTION_IA_NA = 3,
- SD_DHCP6_OPTION_IA_TA = 4,
- SD_DHCP6_OPTION_IAADDR = 5,
- SD_DHCP6_OPTION_ORO = 6,
- SD_DHCP6_OPTION_PREFERENCE = 7,
- SD_DHCP6_OPTION_ELAPSED_TIME = 8,
- SD_DHCP6_OPTION_RELAY_MSG = 9,
+ SD_DHCP6_OPTION_CLIENTID = 1, /* RFC 8415 */
+ SD_DHCP6_OPTION_SERVERID = 2, /* RFC 8415 */
+ SD_DHCP6_OPTION_IA_NA = 3, /* RFC 8415 */
+ SD_DHCP6_OPTION_IA_TA = 4, /* RFC 8415 */
+ SD_DHCP6_OPTION_IAADDR = 5, /* RFC 8415 */
+ SD_DHCP6_OPTION_ORO = 6, /* RFC 8415 */
+ SD_DHCP6_OPTION_PREFERENCE = 7, /* RFC 8415 */
+ SD_DHCP6_OPTION_ELAPSED_TIME = 8, /* RFC 8415 */
+ SD_DHCP6_OPTION_RELAY_MSG = 9, /* RFC 8415 */
/* option code 10 is unassigned */
- SD_DHCP6_OPTION_AUTH = 11,
- SD_DHCP6_OPTION_UNICAST = 12,
- SD_DHCP6_OPTION_STATUS_CODE = 13,
- SD_DHCP6_OPTION_RAPID_COMMIT = 14,
- SD_DHCP6_OPTION_USER_CLASS = 15,
- SD_DHCP6_OPTION_VENDOR_CLASS = 16,
- SD_DHCP6_OPTION_VENDOR_OPTS = 17,
- SD_DHCP6_OPTION_INTERFACE_ID = 18,
- SD_DHCP6_OPTION_RECONF_MSG = 19,
- SD_DHCP6_OPTION_RECONF_ACCEPT = 20,
-
+ SD_DHCP6_OPTION_AUTH = 11, /* RFC 8415 */
+ SD_DHCP6_OPTION_UNICAST = 12, /* RFC 8415 */
+ SD_DHCP6_OPTION_STATUS_CODE = 13, /* RFC 8415 */
+ SD_DHCP6_OPTION_RAPID_COMMIT = 14, /* RFC 8415 */
+ SD_DHCP6_OPTION_USER_CLASS = 15, /* RFC 8415 */
+ SD_DHCP6_OPTION_VENDOR_CLASS = 16, /* RFC 8415 */
+ SD_DHCP6_OPTION_VENDOR_OPTS = 17, /* RFC 8415 */
+ SD_DHCP6_OPTION_INTERFACE_ID = 18, /* RFC 8415 */
+ SD_DHCP6_OPTION_RECONF_MSG = 19, /* RFC 8415 */
+ SD_DHCP6_OPTION_RECONF_ACCEPT = 20, /* RFC 8415 */
+ SD_DHCP6_OPTION_SIP_SERVER_DOMAIN_NAME = 21, /* RFC 3319 */
+ SD_DHCP6_OPTION_SIP_SERVER_ADDRESS = 22, /* RFC 3319 */
SD_DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */
SD_DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */
- SD_DHCP6_OPTION_IA_PD = 25, /* RFC 3633, prefix delegation */
- SD_DHCP6_OPTION_IA_PD_PREFIX = 26, /* RFC 3633, prefix delegation */
-
+ SD_DHCP6_OPTION_IA_PD = 25, /* RFC 3633, RFC 8415 */
+ SD_DHCP6_OPTION_IA_PD_PREFIX = 26, /* RFC 3633, RFC 8415 */
+ SD_DHCP6_OPTION_NIS_SERVERS = 27, /* RFC 3898 */
+ SD_DHCP6_OPTION_NISP_SERVERS = 28, /* RFC 3898 */
+ SD_DHCP6_OPTION_NIS_DOMAIN_NAME = 29, /* RFC 3898 */
+ SD_DHCP6_OPTION_NISP_DOMAIN_NAME = 30, /* RFC 3898 */
SD_DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075, deprecated */
- SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME = 32, /* RFC 8415, sec. 21.23 */
-
+ SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME = 32, /* RFC 4242, 8415, sec. 21.23 */
+ SD_DHCP6_OPTION_BCMCS_SERVER_D = 33, /* RFC 4280 */
+ SD_DHCP6_OPTION_BCMCS_SERVER_A = 34, /* RFC 4280 */
/* option code 35 is unassigned */
-
- SD_DHCP6_OPTION_FQDN = 39, /* RFC 4704 */
-
+ SD_DHCP6_OPTION_GEOCONF_CIVIC = 36, /* RFC 4776 */
+ SD_DHCP6_OPTION_REMOTE_ID = 37, /* RFC 4649 */
+ SD_DHCP6_OPTION_SUBSCRIBER_ID = 38, /* RFC 4580 */
+ SD_DHCP6_OPTION_CLIENT_FQDN = 39, /* RFC 4704 */
+ SD_DHCP6_OPTION_PANA_AGENT = 40, /* RFC 5192 */
+ SD_DHCP6_OPTION_NEW_POSIX_TIMEZONE = 41, /* RFC 4833 */
+ SD_DHCP6_OPTION_NEW_TZDB_TIMEZONE = 42, /* RFC 4833 */
+ SD_DHCP6_OPTION_ERO = 43, /* RFC 4994 */
+ SD_DHCP6_OPTION_LQ_QUERY = 44, /* RFC 5007 */
+ SD_DHCP6_OPTION_CLIENT_DATA = 45, /* RFC 5007 */
+ SD_DHCP6_OPTION_CLT_TIME = 46, /* RFC 5007 */
+ SD_DHCP6_OPTION_LQ_RELAY_DATA = 47, /* RFC 5007 */
+ SD_DHCP6_OPTION_LQ_CLIENT_LINK = 48, /* RFC 5007 */
+ SD_DHCP6_OPTION_MIP6_HNIDF = 49, /* RFC 6610 */
+ SD_DHCP6_OPTION_MIP6_VDINF = 50, /* RFC 6610 */
+ SD_DHCP6_OPTION_V6_LOST = 51, /* RFC 5223 */
+ SD_DHCP6_OPTION_CAPWAP_AC_V6 = 52, /* RFC 5417 */
+ SD_DHCP6_OPTION_RELAY_ID = 53, /* RFC 5460 */
+ SD_DHCP6_OPTION_IPV6_ADDRESS_MOS = 54, /* RFC 5678 */
+ SD_DHCP6_OPTION_IPV6_FQDN_MOS = 55, /* RFC 5678 */
SD_DHCP6_OPTION_NTP_SERVER = 56, /* RFC 5908 */
- SD_DHCP6_OPTION_MUD_URL = 112, /* RFC 8250 */
-
- /* option codes 89-142 are unassigned */
+ SD_DHCP6_OPTION_V6_ACCESS_DOMAIN = 57, /* RFC 5986 */
+ SD_DHCP6_OPTION_SIP_UA_CS_LIST = 58, /* RFC 6011 */
+ SD_DHCP6_OPTION_BOOTFILE_URL = 59, /* RFC 5970 */
+ SD_DHCP6_OPTION_BOOTFILE_PARAM = 60, /* RFC 5970 */
+ SD_DHCP6_OPTION_CLIENT_ARCH_TYPE = 61, /* RFC 5970 */
+ SD_DHCP6_OPTION_NII = 62, /* RFC 5970 */
+ SD_DHCP6_OPTION_GEOLOCATION = 63, /* RFC 6225 */
+ SD_DHCP6_OPTION_AFTR_NAME = 64, /* RFC 6334 */
+ SD_DHCP6_OPTION_ERP_LOCAL_DOMAIN_NAME = 65, /* RFC 6440 */
+ SD_DHCP6_OPTION_RSOO = 66, /* RFC 6422 */
+ SD_DHCP6_OPTION_PD_EXCLUDE = 67, /* RFC 6603 */
+ SD_DHCP6_OPTION_VSS = 68, /* RFC 6607 */
+ SD_DHCP6_OPTION_MIP6_IDINF = 69, /* RFC 6610 */
+ SD_DHCP6_OPTION_MIP6_UDINF = 70, /* RFC 6610 */
+ SD_DHCP6_OPTION_MIP6_HNP = 71, /* RFC 6610 */
+ SD_DHCP6_OPTION_MIP6_HAA = 72, /* RFC 6610 */
+ SD_DHCP6_OPTION_MIP6_HAF = 73, /* RFC 6610 */
+ SD_DHCP6_OPTION_RDNSS_SELECTION = 74, /* RFC 6731 */
+ SD_DHCP6_OPTION_KRB_PRINCIPAL_NAME = 75, /* RFC 6784 */
+ SD_DHCP6_OPTION_KRB_REALM_NAME = 76, /* RFC 6784 */
+ SD_DHCP6_OPTION_KRB_DEFAULT_REALM_NAME = 77, /* RFC 6784 */
+ SD_DHCP6_OPTION_KRB_KDC = 78, /* RFC 6784 */
+ SD_DHCP6_OPTION_CLIENT_LINKLAYER_ADDR = 79, /* RFC 6939 */
+ SD_DHCP6_OPTION_LINK_ADDRESS = 80, /* RFC 6977 */
+ SD_DHCP6_OPTION_RADIUS = 81, /* RFC 7037 */
+ SD_DHCP6_OPTION_SOL_MAX_RT = 82, /* RFC 7083, RFC 8415 */
+ SD_DHCP6_OPTION_INF_MAX_RT = 83, /* RFC 7083, RFC 8415 */
+ SD_DHCP6_OPTION_ADDRSEL = 84, /* RFC 7078 */
+ SD_DHCP6_OPTION_ADDRSEL_TABLE = 85, /* RFC 7078 */
+ SD_DHCP6_OPTION_V6_PCP_SERVER = 86, /* RFC 7291 */
+ SD_DHCP6_OPTION_DHCPV4_MSG = 87, /* RFC 7341 */
+ SD_DHCP6_OPTION_DHCP4_O_DHCP6_SERVER = 88, /* RFC 7341 */
+ SD_DHCP6_OPTION_S46_RULE = 89, /* RFC 7598 */
+ SD_DHCP6_OPTION_S46_BR = 90, /* RFC 7598, RFC 8539 */
+ SD_DHCP6_OPTION_S46_DMR = 91, /* RFC 7598 */
+ SD_DHCP6_OPTION_S46_V4V6BIND = 92, /* RFC 7598 */
+ SD_DHCP6_OPTION_S46_PORTPARAMS = 93, /* RFC 7598 */
+ SD_DHCP6_OPTION_S46_CONT_MAPE = 94, /* RFC 7598 */
+ SD_DHCP6_OPTION_S46_CONT_MAPT = 95, /* RFC 7598 */
+ SD_DHCP6_OPTION_S46_CONT_LW = 96, /* RFC 7598 */
+ SD_DHCP6_OPTION_4RD = 97, /* RFC 7600 */
+ SD_DHCP6_OPTION_4RD_MAP_RULE = 98, /* RFC 7600 */
+ SD_DHCP6_OPTION_4RD_NON_MAP_RULE = 99, /* RFC 7600 */
+ SD_DHCP6_OPTION_LQ_BASE_TIME = 100, /* RFC 7653 */
+ SD_DHCP6_OPTION_LQ_START_TIME = 101, /* RFC 7653 */
+ SD_DHCP6_OPTION_LQ_END_TIME = 102, /* RFC 7653 */
+ SD_DHCP6_OPTION_CAPTIVE_PORTAL = 103, /* RFC 8910 */
+ SD_DHCP6_OPTION_MPL_PARAMETERS = 104, /* RFC 7774 */
+ SD_DHCP6_OPTION_ANI_ATT = 105, /* RFC 7839 */
+ SD_DHCP6_OPTION_ANI_NETWORK_NAME = 106, /* RFC 7839 */
+ SD_DHCP6_OPTION_ANI_AP_NAME = 107, /* RFC 7839 */
+ SD_DHCP6_OPTION_ANI_AP_BSSID = 108, /* RFC 7839 */
+ SD_DHCP6_OPTION_ANI_OPERATOR_ID = 109, /* RFC 7839 */
+ SD_DHCP6_OPTION_ANI_OPERATOR_REALM = 110, /* RFC 7839 */
+ SD_DHCP6_OPTION_S46_PRIORITY = 111, /* RFC 8026 */
+ SD_DHCP6_OPTION_MUD_URL_V6 = 112, /* RFC 8520 */
+ SD_DHCP6_OPTION_V6_PREFIX64 = 113, /* RFC 8115 */
+ SD_DHCP6_OPTION_F_BINDING_STATUS = 114, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_CONNECT_FLAGS = 115, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_DNS_REMOVAL_INFO = 116, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_DNS_HOST_NAME = 117, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_DNS_ZONE_NAME = 118, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_DNS_FLAGS = 119, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_EXPIRATION_TIME = 120, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_MAX_UNACKED_BNDUPD = 121, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_MCLT = 122, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_PARTNER_LIFETIME = 123, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_PARTNER_LIFETIME_SENT = 124, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_PARTNER_DOWN_TIME = 125, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_PARTNER_RAW_CLT_TIME = 126, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_PROTOCOL_VERSION = 127, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_KEEPALIVE_TIME = 128, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_RECONFIGURE_DATA = 129, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_RELATIONSHIP_NAME = 130, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_SERVER_FLAGS = 131, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_SERVER_STATE = 132, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_START_TIME_OF_STATE = 133, /* RFC 8156 */
+ SD_DHCP6_OPTION_F_STATE_EXPIRATION_TIME = 134, /* RFC 8156 */
+ SD_DHCP6_OPTION_RELAY_PORT = 135, /* RFC 8357 */
+ SD_DHCP6_OPTION_V6_SZTP_REDIRECT = 136, /* RFC 8572 */
+ SD_DHCP6_OPTION_S46_BIND_IPV6_PREFIX = 137, /* RFC 8539 */
+ SD_DHCP6_OPTION_IA_LL = 138, /* RFC 8947 */
+ SD_DHCP6_OPTION_LLADDR = 139, /* RFC 8947 */
+ SD_DHCP6_OPTION_SLAP_QUAD = 140, /* RFC 8948 */
+ SD_DHCP6_OPTION_V6_DOTS_RI = 141, /* RFC 8973 */
+ SD_DHCP6_OPTION_V6_DOTS_ADDRESS = 142, /* RFC 8973 */
+ SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF = 143, /* RFC 6153 */
/* option codes 144-65535 are unassigned */
};
diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h
index a10901e5cb..472276def1 100644
--- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h
+++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h
@@ -21,6 +21,7 @@
#include <inttypes.h>
#include <netinet/in.h>
+#include <sys/types.h>
#include "_sd-common.h"
@@ -28,6 +29,9 @@ _SD_BEGIN_DECLARATIONS;
typedef struct sd_dhcp6_lease sd_dhcp6_lease;
+int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret);
+int sd_dhcp6_lease_get_server_address(sd_dhcp6_lease *lease, struct in6_addr *ret);
+
void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease);
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease,
struct in6_addr *addr,
diff --git a/src/libnm-systemd-core/src/systemd/sd-event.h b/src/libnm-systemd-core/src/systemd/sd-event.h
index 2ae2a0da48..63984eef15 100644
--- a/src/libnm-systemd-core/src/systemd/sd-event.h
+++ b/src/libnm-systemd-core/src/systemd/sd-event.h
@@ -93,6 +93,7 @@ int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_sign
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_inotify_fd(sd_event *e, sd_event_source **s, int fd, 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);
int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata);
@@ -165,6 +166,7 @@ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b);
int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, unsigned burst);
int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval_usec, unsigned *ret_burst);
int sd_event_source_is_ratelimited(sd_event_source *s);
+int sd_event_source_set_ratelimit_expire_callback(sd_event_source *s, sd_event_handler_t callback);
/* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref);
diff --git a/src/libnm-systemd-core/src/systemd/sd-ndisc.h b/src/libnm-systemd-core/src/systemd/sd-ndisc.h
index f45b2ad65e..ab9ff55ddb 100644
--- a/src/libnm-systemd-core/src/systemd/sd-ndisc.h
+++ b/src/libnm-systemd-core/src/systemd/sd-ndisc.h
@@ -82,9 +82,6 @@ int sd_ndisc_set_ifname(sd_ndisc *nd, const char *interface_name);
int sd_ndisc_get_ifname(sd_ndisc *nd, const char **ret);
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
-int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *ret);
-int sd_ndisc_get_hop_limit(sd_ndisc *nd, uint8_t *ret);
-
int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size);
sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt);
sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt);
diff --git a/src/libnm-systemd-shared/sd-adapt-shared/filesystems.h b/src/libnm-systemd-shared/sd-adapt-shared/filesystems.h
new file mode 100644
index 0000000000..637892c2d6
--- /dev/null
+++ b/src/libnm-systemd-shared/sd-adapt-shared/filesystems.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/src/libnm-systemd-shared/sd-adapt-shared/hmac.h b/src/libnm-systemd-shared/sd-adapt-shared/hmac.h
new file mode 100644
index 0000000000..637892c2d6
--- /dev/null
+++ b/src/libnm-systemd-shared/sd-adapt-shared/hmac.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/src/libnm-systemd-shared/sd-adapt-shared/missing_magic.h b/src/libnm-systemd-shared/sd-adapt-shared/missing_magic.h
index 637892c2d6..a5dce206a8 100644
--- a/src/libnm-systemd-shared/sd-adapt-shared/missing_magic.h
+++ b/src/libnm-systemd-shared/sd-adapt-shared/missing_magic.h
@@ -1,3 +1,5 @@
#pragma once
/* dummy header */
+
+#include <linux/magic.h>
diff --git a/src/libnm-systemd-shared/sd-adapt-shared/netif-util.h b/src/libnm-systemd-shared/sd-adapt-shared/netif-util.h
new file mode 100644
index 0000000000..637892c2d6
--- /dev/null
+++ b/src/libnm-systemd-shared/sd-adapt-shared/netif-util.h
@@ -0,0 +1,3 @@
+#pragma once
+
+/* dummy header */
diff --git a/src/libnm-systemd-shared/src/basic/alloc-util.h b/src/libnm-systemd-shared/src/basic/alloc-util.h
index e587fe79e7..65d5175619 100644
--- a/src/libnm-systemd-shared/src/basic/alloc-util.h
+++ b/src/libnm-systemd-shared/src/basic/alloc-util.h
@@ -22,20 +22,25 @@ typedef void (*free_func_t)(void *p);
#define new0(t, n) ((t*) calloc((n) ?: 1, sizeof(t)))
+#define alloca_safe(n) \
+ ({ \
+ size_t _nn_ = n; \
+ assert(_nn_ <= ALLOCA_MAX); \
+ alloca(_nn_ == 0 ? 1 : _nn_); \
+ }) \
+
#define newa(t, n) \
({ \
size_t _n_ = n; \
assert(!size_multiply_overflow(sizeof(t), _n_)); \
- assert(sizeof(t)*_n_ <= ALLOCA_MAX); \
- (t*) alloca((sizeof(t)*_n_) ?: 1); \
+ (t*) alloca_safe(sizeof(t)*_n_); \
})
#define newa0(t, n) \
({ \
size_t _n_ = n; \
assert(!size_multiply_overflow(sizeof(t), _n_)); \
- assert(sizeof(t)*_n_ <= ALLOCA_MAX); \
- (t*) alloca0((sizeof(t)*_n_) ?: 1); \
+ (t*) alloca0((sizeof(t)*_n_)); \
})
#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
@@ -44,12 +49,6 @@ typedef void (*free_func_t)(void *p);
#define malloc0(n) (calloc(1, (n) ?: 1))
-#define mfree(memory) \
- ({ \
- free(memory); \
- (typeof(memory)) NULL; \
- })
-
#define free_and_replace(a, b) \
({ \
typeof(a)* _a = &(a); \
@@ -67,8 +66,7 @@ void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, s
({ \
void *_q_; \
size_t _l_ = l; \
- assert(_l_ <= ALLOCA_MAX); \
- _q_ = alloca(_l_ ?: 1); \
+ _q_ = alloca_safe(_l_); \
memcpy_safe(_q_, p, _l_); \
})
@@ -76,8 +74,7 @@ void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, s
({ \
void *_q_; \
size_t _l_ = l; \
- assert(_l_ <= ALLOCA_MAX); \
- _q_ = alloca(_l_ + 1); \
+ _q_ = alloca_safe(_l_ + 1); \
((uint8_t*) _q_)[_l_] = 0; \
memcpy_safe(_q_, p, _l_); \
})
@@ -144,9 +141,8 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
({ \
char *_new_; \
size_t _len_ = n; \
- assert(_len_ <= ALLOCA_MAX); \
- _new_ = alloca(_len_ ?: 1); \
- (void *) memset(_new_, 0, _len_); \
+ _new_ = alloca_safe(_len_); \
+ memset(_new_, 0, _len_); \
})
/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
@@ -155,8 +151,7 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
void *_ptr_; \
size_t _mask_ = (align) - 1; \
size_t _size_ = size; \
- assert(_size_ <= ALLOCA_MAX); \
- _ptr_ = alloca((_size_ + _mask_) ?: 1); \
+ _ptr_ = alloca_safe(_size_ + _mask_); \
(void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \
})
@@ -165,7 +160,7 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
void *_new_; \
size_t _xsize_ = (size); \
_new_ = alloca_align(_xsize_, (align)); \
- (void*)memset(_new_, 0, _xsize_); \
+ memset(_new_, 0, _xsize_); \
})
#if HAS_FEATURE_MEMORY_SANITIZER
@@ -193,3 +188,19 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
MALLOC_SIZEOF_SAFE(x)/sizeof((x)[0]), \
VOID_0))
+
+
+/* These are like strdupa()/strndupa(), but honour ALLOCA_MAX */
+#define strdupa_safe(s) \
+ ({ \
+ const char *_t = (s); \
+ (char*) memdupa_suffix0(_t, strlen(_t)); \
+ })
+
+#define strndupa_safe(s, n) \
+ ({ \
+ const char *_t = (s); \
+ (char*) memdupa_suffix0(_t, strnlen(_t, (n))); \
+ })
+
+#include "memory-util.h"
diff --git a/src/libnm-systemd-shared/src/basic/cgroup-util.h b/src/libnm-systemd-shared/src/basic/cgroup-util.h
index 90ccd2c032..461c01b3c2 100644
--- a/src/libnm-systemd-shared/src/basic/cgroup-util.h
+++ b/src/libnm-systemd-shared/src/basic/cgroup-util.h
@@ -2,6 +2,7 @@
#pragma once
#include <dirent.h>
+#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
@@ -33,6 +34,9 @@ typedef enum CGroupController {
CGROUP_CONTROLLER_BPF_FOREIGN,
CGROUP_CONTROLLER_BPF_SOCKET_BIND,
CGROUP_CONTROLLER_BPF_RESTRICT_NETWORK_INTERFACES,
+ /* The BPF hook implementing RestrictFileSystems= is not defined here.
+ * It's applied as late as possible in exec_child() so we don't block
+ * our own unit setup code. */
_CGROUP_CONTROLLER_MAX,
_CGROUP_CONTROLLER_INVALID = -EINVAL,
@@ -123,6 +127,20 @@ static inline bool CGROUP_CPU_SHARES_IS_OK(uint64_t x) {
(x >= CGROUP_CPU_SHARES_MIN && x <= CGROUP_CPU_SHARES_MAX);
}
+/* Special values for the special {blkio,io}.bfq.weight attribute */
+#define CGROUP_BFQ_WEIGHT_INVALID UINT64_MAX
+#define CGROUP_BFQ_WEIGHT_MIN UINT64_C(1)
+#define CGROUP_BFQ_WEIGHT_MAX UINT64_C(1000)
+#define CGROUP_BFQ_WEIGHT_DEFAULT UINT64_C(100)
+
+/* Convert the normal io.weight value to io.bfq.weight */
+static inline uint64_t BFQ_WEIGHT(uint64_t io_weight) {
+ return
+ io_weight <= CGROUP_WEIGHT_DEFAULT ?
+ CGROUP_BFQ_WEIGHT_DEFAULT - (CGROUP_WEIGHT_DEFAULT - io_weight) * (CGROUP_BFQ_WEIGHT_DEFAULT - CGROUP_BFQ_WEIGHT_MIN) / (CGROUP_WEIGHT_DEFAULT - CGROUP_WEIGHT_MIN) :
+ CGROUP_BFQ_WEIGHT_DEFAULT + (io_weight - CGROUP_WEIGHT_DEFAULT) * (CGROUP_BFQ_WEIGHT_MAX - CGROUP_BFQ_WEIGHT_DEFAULT) / (CGROUP_WEIGHT_MAX - CGROUP_WEIGHT_DEFAULT);
+}
+
/* Special values for the blkio.weight attribute */
#define CGROUP_BLKIO_WEIGHT_INVALID UINT64_MAX
#define CGROUP_BLKIO_WEIGHT_MIN UINT64_C(10)
@@ -236,6 +254,7 @@ int cg_is_empty_recursive(const char *controller, const char *path);
int cg_get_root_path(char **path);
+int cg_path_get_cgroupid(const char *path, uint64_t *ret);
int cg_path_get_session(const char *path, char **session);
int cg_path_get_owner_uid(const char *path, uid_t *uid);
int cg_path_get_unit(const char *path, char **unit);
@@ -311,3 +330,12 @@ typedef enum ManagedOOMPreference {
const char* managed_oom_preference_to_string(ManagedOOMPreference a) _const_;
ManagedOOMPreference managed_oom_preference_from_string(const char *s) _pure_;
+
+/* The structure to pass to name_to_handle_at() on cgroupfs2 */
+typedef union {
+ struct file_handle file_handle;
+ uint8_t space[offsetof(struct file_handle, f_handle) + sizeof(uint64_t)];
+} cg_file_handle;
+
+#define CG_FILE_HANDLE_INIT { .file_handle.handle_bytes = sizeof(uint64_t) }
+#define CG_FILE_HANDLE_CGROUPID(fh) (*(uint64_t*) (fh).file_handle.f_handle)
diff --git a/src/libnm-systemd-shared/src/basic/env-util.c b/src/libnm-systemd-shared/src/basic/env-util.c
index 431862f6fb..f47ddefe96 100644
--- a/src/libnm-systemd-shared/src/basic/env-util.c
+++ b/src/libnm-systemd-shared/src/basic/env-util.c
@@ -10,6 +10,7 @@
#include "alloc-util.h"
#include "env-util.h"
+#include "errno-util.h"
#include "escape.h"
#include "extract-word.h"
#include "macro.h"
@@ -397,7 +398,7 @@ int strv_env_replace_consume(char ***l, char *p) {
return -EINVAL;
}
- name = strndupa(p, t - p);
+ name = strndupa_safe(p, t - p);
STRV_FOREACH(f, *l)
if (env_entry_has_name(*f, name)) {
@@ -484,7 +485,7 @@ char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
const char *t;
- t = strndupa(name, k);
+ t = strndupa_safe(name, k);
return getenv(t);
};
@@ -791,15 +792,12 @@ int getenv_bool_secure(const char *p) {
#if 0 /* NM_IGNORED */
int set_unset_env(const char *name, const char *value, bool overwrite) {
- int r;
+ assert(name);
if (value)
- r = setenv(name, value, overwrite);
- else
- r = unsetenv(name);
- if (r < 0)
- return -errno;
- return 0;
+ return RET_NERRNO(setenv(name, value, overwrite));
+
+ return RET_NERRNO(unsetenv(name));
}
int putenv_dup(const char *assignment, bool override) {
@@ -809,12 +807,10 @@ int putenv_dup(const char *assignment, bool override) {
if (!e)
return -EINVAL;
- n = strndupa(assignment, e - assignment);
+ n = strndupa_safe(assignment, e - assignment);
/* This is like putenv(), but uses setenv() so that our memory doesn't become part of environ[]. */
- if (setenv(n, e + 1, override) < 0)
- return -errno;
- return 0;
+ return RET_NERRNO(setenv(n, e + 1, override));
}
int setenv_systemd_exec_pid(bool update_only) {
diff --git a/src/libnm-systemd-shared/src/basic/errno-util.h b/src/libnm-systemd-shared/src/basic/errno-util.h
index 3f2d0af56d..09abf0b751 100644
--- a/src/libnm-systemd-shared/src/basic/errno-util.h
+++ b/src/libnm-systemd-shared/src/basic/errno-util.h
@@ -13,7 +13,7 @@ static inline void _reset_errno_(int *saved_errno) {
errno = *saved_errno;
}
-#define PROTECT_ERRNO \
+#define PROTECT_ERRNO \
_cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno
#define UNPROTECT_ERRNO \
@@ -31,6 +31,29 @@ static inline int negative_errno(void) {
return -errno;
}
+static inline int RET_NERRNO(int ret) {
+
+ /* Helper to wrap system calls in to make them return negative errno errors. This brings system call
+ * error handling in sync with how we usually handle errors in our own code, i.e. with immediate
+ * returning of negative errno. Usage is like this:
+ *
+ * …
+ * r = RET_NERRNO(unlink(t));
+ * …
+ *
+ * or
+ *
+ * …
+ * fd = RET_NERRNO(open("/etc/fstab", O_RDONLY|O_CLOEXEC));
+ * …
+ */
+
+ if (ret < 0)
+ return negative_errno();
+
+ return ret;
+}
+
static inline const char *strerror_safe(int error) {
/* 'safe' here does NOT mean thread safety. */
return strerror(abs(error)); /* lgtm [cpp/potentially-dangerous-function] */
@@ -47,6 +70,13 @@ static inline int errno_or_else(int fallback) {
return -abs(fallback);
}
+/* For send()/recv() or read()/write(). */
+static inline bool ERRNO_IS_TRANSIENT(int r) {
+ return IN_SET(abs(r),
+ EAGAIN,
+ EINTR);
+}
+
/* Hint #1: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5.
*
* Hint #2: The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases. See the
@@ -77,10 +107,8 @@ static inline bool ERRNO_IS_DISCONNECT(int r) {
* the accept(2) man page. */
static inline bool ERRNO_IS_ACCEPT_AGAIN(int r) {
return ERRNO_IS_DISCONNECT(r) ||
- IN_SET(abs(r),
- EAGAIN,
- EINTR,
- EOPNOTSUPP);
+ ERRNO_IS_TRANSIENT(r) ||
+ abs(r) == EOPNOTSUPP;
}
/* Resource exhaustion, could be our fault or general system trouble */
diff --git a/src/libnm-systemd-shared/src/basic/escape.c b/src/libnm-systemd-shared/src/basic/escape.c
index 9328856351..4dfb9a1637 100644
--- a/src/libnm-systemd-shared/src/basic/escape.c
+++ b/src/libnm-systemd-shared/src/basic/escape.c
@@ -547,7 +547,7 @@ char* shell_maybe_quote(const char *s, ShellEscapeFlags flags) {
return str_realloc(buf);
}
-char* quote_command_line(char **argv) {
+char* quote_command_line(char **argv, ShellEscapeFlags flags) {
_cleanup_free_ char *result = NULL;
assert(argv);
@@ -556,7 +556,7 @@ char* quote_command_line(char **argv) {
STRV_FOREACH(a, argv) {
_cleanup_free_ char *t = NULL;
- t = shell_maybe_quote(*a, SHELL_ESCAPE_EMPTY);
+ t = shell_maybe_quote(*a, flags);
if (!t)
return NULL;
@@ -564,6 +564,6 @@ char* quote_command_line(char **argv) {
return NULL;
}
- return TAKE_PTR(result);
+ return str_realloc(TAKE_PTR(result));
}
#endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/escape.h b/src/libnm-systemd-shared/src/basic/escape.h
index d490510deb..318da6f220 100644
--- a/src/libnm-systemd-shared/src/basic/escape.h
+++ b/src/libnm-systemd-shared/src/basic/escape.h
@@ -69,4 +69,4 @@ char* escape_non_printable_full(const char *str, size_t console_width, XEscapeFl
char* shell_escape(const char *s, const char *bad);
char* shell_maybe_quote(const char *s, ShellEscapeFlags flags);
-char* quote_command_line(char **argv);
+char* quote_command_line(char **argv, ShellEscapeFlags flags);
diff --git a/src/libnm-systemd-shared/src/basic/ether-addr-util.c b/src/libnm-systemd-shared/src/basic/ether-addr-util.c
index c73dcff158..4504b6be1f 100644
--- a/src/libnm-systemd-shared/src/basic/ether-addr-util.c
+++ b/src/libnm-systemd-shared/src/basic/ether-addr-util.c
@@ -9,20 +9,29 @@
#include <sys/types.h>
#include "ether-addr-util.h"
+#include "hexdecoct.h"
#include "macro.h"
#include "string-util.h"
-char* hw_addr_to_string(const struct hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]) {
+char *hw_addr_to_string_full(
+ const struct hw_addr_data *addr,
+ HardwareAddressToStringFlags flags,
+ char buffer[static HW_ADDR_TO_STRING_MAX]) {
+
assert(addr);
assert(buffer);
assert(addr->length <= HW_ADDR_MAX_SIZE);
- for (size_t i = 0; i < addr->length; i++) {
- sprintf(&buffer[3*i], "%02"PRIx8, addr->bytes[i]);
- if (i < addr->length - 1)
- buffer[3*i + 2] = ':';
+ for (size_t i = 0, j = 0; i < addr->length; i++) {
+ buffer[j++] = hexchar(addr->bytes[i] >> 4);
+ buffer[j++] = hexchar(addr->bytes[i] & 0x0f);
+ if (!FLAGS_SET(flags, HW_ADDR_TO_STRING_NO_COLON))
+ buffer[j++] = ':';
}
+ buffer[addr->length == 0 || FLAGS_SET(flags, HW_ADDR_TO_STRING_NO_COLON) ?
+ addr->length * 2 :
+ addr->length * 3 - 1] = '\0';
return buffer;
}
@@ -39,7 +48,7 @@ int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b)
return memcmp(a->bytes, b->bytes, a->length);
}
-static void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *state) {
+void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *state) {
assert(p);
assert(state);
@@ -48,6 +57,7 @@ static void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *stat
}
DEFINE_HASH_OPS(hw_addr_hash_ops, struct hw_addr_data, hw_addr_hash_func, hw_addr_compare);
+DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(hw_addr_hash_ops_free, struct hw_addr_data, hw_addr_hash_func, hw_addr_compare, free);
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
assert(addr);
@@ -93,75 +103,163 @@ static void ether_addr_hash_func(const struct ether_addr *p, struct siphash *sta
}
DEFINE_HASH_OPS(ether_addr_hash_ops, struct ether_addr, ether_addr_hash_func, ether_addr_compare);
+DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(ether_addr_hash_ops_free, struct ether_addr, ether_addr_hash_func, ether_addr_compare, free);
-int ether_addr_from_string(const char *s, struct ether_addr *ret) {
- size_t pos = 0, n, field;
- char sep = '\0';
- const char *hex = HEXDIGITS, *hexoff;
- size_t x;
- bool touched;
-
-#define parse_fields(v) \
- for (field = 0; field < ELEMENTSOF(v); field++) { \
- touched = false; \
- for (n = 0; n < (2 * sizeof(v[0])); n++) { \
- if (s[pos] == '\0') \
- break; \
- hexoff = strchr(hex, s[pos]); \
- if (!hexoff) \
- break; \
- assert(hexoff >= hex); \
- x = hexoff - hex; \
- if (x >= 16) \
- x -= 6; /* A-F */ \
- assert(x < 16); \
- touched = true; \
- v[field] <<= 4; \
- v[field] += x; \
- pos++; \
- } \
- if (!touched) \
- return -EINVAL; \
- if (field < (ELEMENTSOF(v)-1)) { \
- if (s[pos] != sep) \
- return -EINVAL; \
- else \
- pos++; \
- } \
- }
+static int parse_hw_addr_one_field(const char **s, char sep, size_t len, uint8_t *buf) {
+ const char *hex = HEXDIGITS, *p;
+ uint16_t data = 0;
+ bool cont;
assert(s);
- assert(ret);
+ assert(*s);
+ assert(IN_SET(len, 1, 2));
+ assert(buf);
- s += strspn(s, WHITESPACE);
- sep = s[strspn(s, hex)];
+ p = *s;
- if (sep == '.') {
- uint16_t shorts[3] = { 0 };
+ for (size_t i = 0; i < len * 2; i++) {
+ const char *hexoff;
+ size_t x;
- parse_fields(shorts);
+ if (*p == '\0' || *p == sep) {
+ if (i == 0)
+ return -EINVAL;
+ break;
+ }
- if (s[pos] != '\0')
+ hexoff = strchr(hex, *p);
+ if (!hexoff)
return -EINVAL;
- for (n = 0; n < ELEMENTSOF(shorts); n++) {
- ret->ether_addr_octet[2*n] = ((shorts[n] & (uint16_t)0xff00) >> 8);
- ret->ether_addr_octet[2*n + 1] = (shorts[n] & (uint16_t)0x00ff);
+ assert(hexoff >= hex);
+ x = hexoff - hex;
+ if (x >= 16)
+ x -= 6; /* A-F */
+
+ assert(x < 16);
+ data <<= 4;
+ data += x;
+
+ p++;
+ }
+
+ if (*p != '\0' && *p != sep)
+ return -EINVAL;
+
+ switch (len) {
+ case 1:
+ buf[0] = data;
+ break;
+ case 2:
+ buf[0] = (data & 0xff00) >> 8;
+ buf[1] = data & 0xff;
+ break;
+ default:
+ assert_not_reached();
+ }
+
+ cont = *p == sep;
+ *s = p + cont;
+ return cont;
+}
+
+int parse_hw_addr_full(const char *s, size_t expected_len, struct hw_addr_data *ret) {
+ size_t field_size, max_len, len = 0;
+ uint8_t bytes[HW_ADDR_MAX_SIZE];
+ char sep;
+ int r;
+
+ assert(s);
+ assert(expected_len <= HW_ADDR_MAX_SIZE || expected_len == SIZE_MAX);
+ assert(ret);
+
+ /* This accepts the following formats:
+ *
+ * Dot separated 2 bytes format: xxyy.zzaa.bbcc
+ * Colon separated 1 bytes format: xx:yy:zz:aa:bb:cc
+ * Hyphen separated 1 bytes format: xx-yy-zz-aa-bb-cc
+ *
+ * Moreover, if expected_len == 0, 4, or 16, this also accepts:
+ *
+ * IPv4 format: used by IPv4 tunnel, e.g. ipgre
+ * IPv6 format: used by IPv6 tunnel, e.g. ip6gre
+ *
+ * The expected_len argument controls the length of acceptable addresses:
+ *
+ * 0: accepts 4 (AF_INET), 16 (AF_INET6), 6 (ETH_ALEN), or 20 (INFINIBAND_ALEN).
+ * SIZE_MAX: accepts arbitrary length, but at least one separator must be included.
+ * Otherwise: accepts addresses with matching length.
+ */
+
+ if (IN_SET(expected_len, 0, sizeof(struct in_addr), sizeof(struct in6_addr))) {
+ union in_addr_union a;
+ int family;
+
+ if (expected_len == 0)
+ r = in_addr_from_string_auto(s, &family, &a);
+ else {
+ family = expected_len == sizeof(struct in_addr) ? AF_INET : AF_INET6;
+ r = in_addr_from_string(family, s, &a);
+ }
+ if (r >= 0) {
+ ret->length = FAMILY_ADDRESS_SIZE(family);
+ memcpy(ret->bytes, a.bytes, ret->length);
+ return 0;
}
+ }
- } else if (IN_SET(sep, ':', '-')) {
- struct ether_addr out = ETHER_ADDR_NULL;
+ max_len =
+ expected_len == 0 ? INFINIBAND_ALEN :
+ expected_len == SIZE_MAX ? HW_ADDR_MAX_SIZE : expected_len;
+ sep = s[strspn(s, HEXDIGITS)];
- parse_fields(out.ether_addr_octet);
+ if (sep == '.')
+ field_size = 2;
+ else if (IN_SET(sep, ':', '-'))
+ field_size = 1;
+ else
+ return -EINVAL;
- if (s[pos] != '\0')
- return -EINVAL;
+ if (max_len % field_size != 0)
+ return -EINVAL;
- for (n = 0; n < ELEMENTSOF(out.ether_addr_octet); n++)
- ret->ether_addr_octet[n] = out.ether_addr_octet[n];
+ for (size_t i = 0; i < max_len / field_size; i++) {
+ r = parse_hw_addr_one_field(&s, sep, field_size, bytes + i * field_size);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ len = (i + 1) * field_size;
+ break;
+ }
+ }
- } else
+ if (len == 0)
return -EINVAL;
+ if (expected_len == 0) {
+ if (!IN_SET(len, 4, 16, ETH_ALEN, INFINIBAND_ALEN))
+ return -EINVAL;
+ } else if (expected_len != SIZE_MAX) {
+ if (len != expected_len)
+ return -EINVAL;
+ }
+
+ ret->length = len;
+ memcpy(ret->bytes, bytes, ret->length);
+ return 0;
+}
+
+int parse_ether_addr(const char *s, struct ether_addr *ret) {
+ struct hw_addr_data a;
+ int r;
+
+ assert(s);
+ assert(ret);
+
+ r = parse_hw_addr_full(s, ETH_ALEN, &a);
+ if (r < 0)
+ return r;
+
+ *ret = a.ether;
return 0;
}
diff --git a/src/libnm-systemd-shared/src/basic/ether-addr-util.h b/src/libnm-systemd-shared/src/basic/ether-addr-util.h
index 794fc55bb8..32f45fe813 100644
--- a/src/libnm-systemd-shared/src/basic/ether-addr-util.h
+++ b/src/libnm-systemd-shared/src/basic/ether-addr-util.h
@@ -6,6 +6,9 @@
#include <stdbool.h>
#include "hash-funcs.h"
+#include "in-addr-util.h"
+#include "macro.h"
+#include "memory-util.h"
/* This is MAX_ADDR_LEN as defined in linux/netdevice.h, but net/if_arp.h
* defines a macro of the same name with a much lower size. */
@@ -16,29 +19,51 @@ struct hw_addr_data {
union {
struct ether_addr ether;
uint8_t infiniband[INFINIBAND_ALEN];
+ struct in_addr in;
+ struct in6_addr in6;
uint8_t bytes[HW_ADDR_MAX_SIZE];
};
};
+int parse_hw_addr_full(const char *s, size_t expected_len, struct hw_addr_data *ret);
+static inline int parse_hw_addr(const char *s, struct hw_addr_data *ret) {
+ return parse_hw_addr_full(s, 0, ret);
+}
+int parse_ether_addr(const char *s, struct ether_addr *ret);
+
+typedef enum HardwareAddressToStringFlags {
+ HW_ADDR_TO_STRING_NO_COLON = 1 << 0,
+} HardwareAddressToStringFlags;
+
#define HW_ADDR_TO_STRING_MAX (3*HW_ADDR_MAX_SIZE)
-char* hw_addr_to_string(const struct hw_addr_data *addr, char buffer[HW_ADDR_TO_STRING_MAX]);
+char *hw_addr_to_string_full(
+ const struct hw_addr_data *addr,
+ HardwareAddressToStringFlags flags,
+ char buffer[static HW_ADDR_TO_STRING_MAX]);
+static inline char *hw_addr_to_string(const struct hw_addr_data *addr, char buffer[static HW_ADDR_TO_STRING_MAX]) {
+ return hw_addr_to_string_full(addr, 0, buffer);
+}
/* Note: the lifetime of the compound literal is the immediately surrounding block,
* see C11 §6.5.2.5, and
* https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */
-#define HW_ADDR_TO_STR(hw_addr) hw_addr_to_string((hw_addr), (char[HW_ADDR_TO_STRING_MAX]){})
+#define HW_ADDR_TO_STR_FULL(hw_addr, flags) hw_addr_to_string_full((hw_addr), flags, (char[HW_ADDR_TO_STRING_MAX]){})
+#define HW_ADDR_TO_STR(hw_addr) HW_ADDR_TO_STR_FULL(hw_addr, 0)
#define HW_ADDR_NULL ((const struct hw_addr_data){})
+void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *state);
int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b);
static inline bool hw_addr_equal(const struct hw_addr_data *a, const struct hw_addr_data *b) {
return hw_addr_compare(a, b) == 0;
}
static inline bool hw_addr_is_null(const struct hw_addr_data *addr) {
- return hw_addr_equal(addr, &HW_ADDR_NULL);
+ assert(addr);
+ return addr->length == 0 || memeqzero(addr->bytes, addr->length);
}
extern const struct hash_ops hw_addr_hash_ops;
+extern const struct hash_ops hw_addr_hash_ops_free;
#define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X"
#define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5]
@@ -60,6 +85,29 @@ static inline bool ether_addr_is_null(const struct ether_addr *addr) {
return ether_addr_equal(addr, &ETHER_ADDR_NULL);
}
-int ether_addr_from_string(const char *s, struct ether_addr *ret);
+static inline bool ether_addr_is_broadcast(const struct ether_addr *addr) {
+ assert(addr);
+ return memeqbyte(0xff, addr->ether_addr_octet, ETH_ALEN);
+}
+
+static inline bool ether_addr_is_multicast(const struct ether_addr *addr) {
+ assert(addr);
+ return FLAGS_SET(addr->ether_addr_octet[0], 0x01);
+}
+
+static inline bool ether_addr_is_unicast(const struct ether_addr *addr) {
+ return !ether_addr_is_multicast(addr);
+}
+
+static inline bool ether_addr_is_local(const struct ether_addr *addr) {
+ /* Determine if the Ethernet address is locally-assigned one (IEEE 802) */
+ assert(addr);
+ return FLAGS_SET(addr->ether_addr_octet[0], 0x02);
+}
+
+static inline bool ether_addr_is_global(const struct ether_addr *addr) {
+ return !ether_addr_is_local(addr);
+}
extern const struct hash_ops ether_addr_hash_ops;
+extern const struct hash_ops ether_addr_hash_ops_free;
diff --git a/src/libnm-systemd-shared/src/basic/fd-util.c b/src/libnm-systemd-shared/src/basic/fd-util.c
index ee2a4caf7b..c3df68de58 100644
--- a/src/libnm-systemd-shared/src/basic/fd-util.c
+++ b/src/libnm-systemd-shared/src/basic/fd-util.c
@@ -154,10 +154,7 @@ int fd_nonblock(int fd, bool nonblock) {
if (nflags == flags)
return 0;
- if (fcntl(fd, F_SETFL, nflags) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(fcntl(fd, F_SETFL, nflags));
}
int fd_cloexec(int fd, bool cloexec) {
@@ -173,10 +170,7 @@ int fd_cloexec(int fd, bool cloexec) {
if (nflags == flags)
return 0;
- if (fcntl(fd, F_SETFD, nflags) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(fcntl(fd, F_SETFD, nflags));
}
#if 0 /* NM_IGNORED */
@@ -190,7 +184,7 @@ _pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) {
return false;
}
-static int get_max_fd(void) {
+int get_max_fd(void) {
struct rlimit rl;
rlim_t m;
@@ -211,37 +205,147 @@ static int get_max_fd(void) {
return (int) (m - 1);
}
-int close_all_fds_full(int except[], size_t n_except, bool allow_alloc) {
- static bool have_close_range = true; /* Assume we live in the future */
+static int close_all_fds_frugal(const int except[], size_t n_except) {
+ int max_fd, r = 0;
+
+ assert(n_except == 0 || except);
+
+ /* This is the inner fallback core of close_all_fds(). This never calls malloc() or opendir() or so
+ * and hence is safe to be called in signal handler context. Most users should call close_all_fds(),
+ * but when we assume we are called from signal handler context, then use this simpler call
+ * instead. */
+
+ max_fd = get_max_fd();
+ if (max_fd < 0)
+ return max_fd;
+
+ /* Refuse to do the loop over more too many elements. It's better to fail immediately than to
+ * spin the CPU for a long time. */
+ if (max_fd > MAX_FD_LOOP_LIMIT)
+ return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
+ "Refusing to loop over %d potential fds.",
+ max_fd);
+
+ for (int fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
+ int q;
+
+ if (fd_in_set(fd, except, n_except))
+ continue;
+
+ q = close_nointr(fd);
+ if (q < 0 && q != -EBADF && r >= 0)
+ r = q;
+ }
+
+ return r;
+}
+
+static bool have_close_range = true; /* Assume we live in the future */
+
+static int close_all_fds_special_case(const int except[], size_t n_except) {
+ assert(n_except == 0 || except);
+
+ /* Handles a few common special cases separately, since they are common and can be optimized really
+ * nicely, since we won't need sorting for them. Returns > 0 if the special casing worked, 0
+ * otherwise. */
+
+ if (!have_close_range)
+ return 0;
+
+ switch (n_except) {
+
+ case 0:
+ /* Close everything. Yay! */
+
+ if (close_range(3, -1, 0) >= 0)
+ return 1;
+
+ if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) {
+ have_close_range = false;
+ return 0;
+ }
+
+ return -errno;
+
+ case 1:
+ /* Close all but exactly one, then we don't need no sorting. This is a pretty common
+ * case, hence let's handle it specially. */
+
+ if ((except[0] <= 3 || close_range(3, except[0]-1, 0) >= 0) &&
+ (except[0] >= INT_MAX || close_range(MAX(3, except[0]+1), -1, 0) >= 0))
+ return 1;
+
+ if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) {
+ have_close_range = false;
+ return 0;
+ }
+
+ return -errno;
+
+ default:
+ return 0;
+ }
+}
+
+int close_all_fds_without_malloc(const int except[], size_t n_except) {
+ int r;
+
+ assert(n_except == 0 || except);
+
+ r = close_all_fds_special_case(except, n_except);
+ if (r < 0)
+ return r;
+ if (r > 0) /* special case worked! */
+ return 0;
+
+ return close_all_fds_frugal(except, n_except);
+}
+
+int close_all_fds(const int except[], size_t n_except) {
_cleanup_closedir_ DIR *d = NULL;
int r = 0;
assert(n_except == 0 || except);
+ r = close_all_fds_special_case(except, n_except);
+ if (r < 0)
+ return r;
+ if (r > 0) /* special case worked! */
+ return 0;
+
if (have_close_range) {
+ _cleanup_free_ int *sorted_malloc = NULL;
+ size_t n_sorted;
+ int *sorted;
+
/* In the best case we have close_range() to close all fds between a start and an end fd,
* which we can use on the "inverted" exception array, i.e. all intervals between all
* adjacent pairs from the sorted exception array. This changes loop complexity from O(n)
* where n is number of open fds to O(mâ‹…log(m)) where m is the number of fds to keep
* open. Given that we assume n ≫ m that's preferable to us. */
- if (n_except == 0) {
- /* Close everything. Yay! */
+ assert(n_except < SIZE_MAX);
+ n_sorted = n_except + 1;
- if (close_range(3, -1, 0) >= 0)
- return 0;
+ if (n_sorted > 64) /* Use heap for large numbers of fds, stack otherwise */
+ sorted = sorted_malloc = new(int, n_sorted);
+ else
+ sorted = newa(int, n_sorted);
- if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno))
- have_close_range = false;
- else
- return -errno;
+ if (sorted) {
+ memcpy(sorted, except, n_except * sizeof(int));
- } else {
- typesafe_qsort(except, n_except, cmp_int);
+ /* Let's add fd 2 to the list of fds, to simplify the loop below, as this
+ * allows us to cover the head of the array the same way as the body */
+ sorted[n_sorted-1] = 2;
- for (size_t i = 0; i < n_except; i++) {
- int start = i == 0 ? 2 : MAX(except[i-1], 2); /* The first three fds shall always remain open */
- int end = MAX(except[i], 2);
+ typesafe_qsort(sorted, n_sorted, cmp_int);
+
+ for (size_t i = 0; i < n_sorted-1; i++) {
+ int start, end;
+
+ start = MAX(sorted[i], 2); /* The first three fds shall always remain open */
+ end = MAX(sorted[i+1], 2);
assert(end >= start);
@@ -250,83 +354,58 @@ int close_all_fds_full(int except[], size_t n_except, bool allow_alloc) {
/* Close everything between the start and end fds (both of which shall stay open) */
if (close_range(start + 1, end - 1, 0) < 0) {
- if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno))
- have_close_range = false;
- else
+ if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
return -errno;
- goto opendir_fallback;
+
+ have_close_range = false;
+ break;
}
}
- /* The loop succeeded. Let's now close everything beyond the end */
+ if (have_close_range) {
+ /* The loop succeeded. Let's now close everything beyond the end */
- if (except[n_except-1] >= INT_MAX) /* Don't let the addition below overflow */
- return 0;
+ if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
+ return 0;
- int start = MAX(except[n_except-1], 2);
+ if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0)
+ return 0;
- if (close_range(start + 1, -1, 0) >= 0)
- return 0;
+ if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
+ return -errno;
- if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno))
have_close_range = false;
- else
- return -errno;
+ }
}
- }
-
- /* Fallback for when close_range() is not supported */
- opendir_fallback:
- d = allow_alloc ? opendir("/proc/self/fd") : NULL;
- if (d) {
- struct dirent *de;
-
- FOREACH_DIRENT(de, d, return -errno) {
- int fd = -1, q;
-
- if (safe_atoi(de->d_name, &fd) < 0)
- /* Let's better ignore this, just in case */
- continue;
- if (fd < 3)
- continue;
-
- if (fd == dirfd(d))
- continue;
+ /* Fallback on OOM or if close_range() is not supported */
+ }
- if (fd_in_set(fd, except, n_except))
- continue;
+ d = opendir("/proc/self/fd");
+ if (!d)
+ return close_all_fds_frugal(except, n_except); /* ultimate fallback if /proc/ is not available */
- q = close_nointr(fd);
- if (q < 0 && q != -EBADF && r >= 0) /* Valgrind has its own FD and doesn't want to have it closed */
- r = q;
- }
+ FOREACH_DIRENT(de, d, return -errno) {
+ int fd = -1, q;
- return r;
- }
-
- /* Fallback for when /proc isn't available (for example in chroots) or when we cannot allocate by
- * brute-forcing through the file descriptor table. */
+ if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
+ continue;
- int max_fd = get_max_fd();
- if (max_fd < 0)
- return max_fd;
+ if (safe_atoi(de->d_name, &fd) < 0)
+ /* Let's better ignore this, just in case */
+ continue;
- /* Refuse to do the loop over more too many elements. It's better to fail immediately than to
- * spin the CPU for a long time. */
- if (max_fd > MAX_FD_LOOP_LIMIT)
- return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
- "/proc/self/fd is inaccessible. Refusing to loop over %d potential fds.",
- max_fd);
+ if (fd < 3)
+ continue;
- for (int fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
- int q;
+ if (fd == dirfd(d))
+ continue;
if (fd_in_set(fd, except, n_except))
continue;
q = close_nointr(fd);
- if (q < 0 && q != -EBADF && r >= 0)
+ if (q < 0 && q != -EBADF && r >= 0) /* Valgrind has its own FD and doesn't want to have it closed */
r = q;
}
@@ -652,7 +731,7 @@ finish:
}
int fd_reopen(int fd, int flags) {
- int new_fd;
+ int new_fd, r;
/* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to
* turn O_RDWR fds into O_RDONLY fds.
@@ -661,15 +740,28 @@ int fd_reopen(int fd, int flags) {
*
* This implicitly resets the file read index to 0. */
+ if (FLAGS_SET(flags, O_DIRECTORY)) {
+ /* If we shall reopen the fd as directory we can just go via "." and thus bypass the whole
+ * magic /proc/ directory, and make ourselves independent of that being mounted. */
+ new_fd = openat(fd, ".", flags);
+ if (new_fd < 0)
+ return -errno;
+
+ return new_fd;
+ }
+
new_fd = open(FORMAT_PROC_FD_PATH(fd), flags);
if (new_fd < 0) {
if (errno != ENOENT)
return -errno;
- if (proc_mounted() == 0)
+ r = proc_mounted();
+ if (r == 0)
return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
- return -ENOENT;
+ return r > 0 ? -EBADF : -ENOENT; /* If /proc/ is definitely around then this means the fd is
+ * not valid, otherwise let's propagate the original
+ * error */
}
return new_fd;
@@ -710,9 +802,6 @@ int btrfs_defrag_fd(int fd) {
if (r < 0)
return r;
- if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(ioctl(fd, BTRFS_IOC_DEFRAG, NULL));
}
#endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/fd-util.h b/src/libnm-systemd-shared/src/basic/fd-util.h
index 2382d52d40..f5cfcb4ede 100644
--- a/src/libnm-systemd-shared/src/basic/fd-util.h
+++ b/src/libnm-systemd-shared/src/basic/fd-util.h
@@ -57,10 +57,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(DIR*, closedir, NULL);
int fd_nonblock(int fd, bool nonblock);
int fd_cloexec(int fd, bool cloexec);
-int close_all_fds_full(int except[], size_t n_except, bool allow_alloc);
-static inline int close_all_fds(int except[], size_t n_except) {
- return close_all_fds_full(except, n_except, true);
-}
+int get_max_fd(void);
+
+int close_all_fds(const int except[], size_t n_except);
+int close_all_fds_without_malloc(const int except[], size_t n_except);
int same_fd(int a, int b);
@@ -91,9 +91,10 @@ static inline int make_null_stdio(void) {
/* Like TAKE_PTR() but for file descriptors, resetting them to -1 */
#define TAKE_FD(fd) \
({ \
- int _fd_ = (fd); \
- (fd) = -1; \
- _fd_; \
+ int *_fd_ = &(fd); \
+ int _ret_ = *_fd_; \
+ *_fd_ = -1; \
+ _ret_; \
})
/* Like free_and_replace(), but for file descriptors */
diff --git a/src/libnm-systemd-shared/src/basic/fileio.c b/src/libnm-systemd-shared/src/basic/fileio.c
index 322638a2d4..c66bc67bcb 100644
--- a/src/libnm-systemd-shared/src/basic/fileio.c
+++ b/src/libnm-systemd-shared/src/basic/fileio.c
@@ -169,7 +169,7 @@ int write_string_stream_ts(
* it won't be equal to the new value. */
if (read_virtual_file_fd(fd, strlen(line)+1, &t, NULL) > 0 &&
streq_skip_trailing_chars(line, t, NEWLINE)) {
- log_debug("No change in value '%s', supressing write", line);
+ log_debug("No change in value '%s', suppressing write", line);
return 0;
}
@@ -551,12 +551,25 @@ int read_virtual_file_fd(int fd, size_t max_size, char **ret_contents, size_t *r
return !truncated;
}
-int read_virtual_file(const char *filename, size_t max_size, char **ret_contents, size_t *ret_size) {
+int read_virtual_file_at(
+ int dir_fd,
+ const char *filename,
+ size_t max_size,
+ char **ret_contents,
+ size_t *ret_size) {
+
_cleanup_close_ int fd = -1;
- assert(filename);
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
- fd = open(filename, O_RDONLY | O_NOCTTY | O_CLOEXEC);
+ if (!filename) {
+ if (dir_fd == AT_FDCWD)
+ return -EBADF;
+
+ return read_virtual_file_fd(dir_fd, max_size, ret_contents, ret_size);
+ }
+
+ fd = openat(dir_fd, filename, O_RDONLY | O_NOCTTY | O_CLOEXEC);
if (fd < 0)
return -errno;
@@ -934,6 +947,9 @@ DIR *xopendirat(int fd, const char *name, int flags) {
assert(!(flags & O_CREAT));
+ if (fd == AT_FDCWD && flags == 0)
+ return opendir(name);
+
nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
if (nfd < 0)
return NULL;
diff --git a/src/libnm-systemd-shared/src/basic/fileio.h b/src/libnm-systemd-shared/src/basic/fileio.h
index 899def946b..cea3dd893d 100644
--- a/src/libnm-systemd-shared/src/basic/fileio.h
+++ b/src/libnm-systemd-shared/src/basic/fileio.h
@@ -69,7 +69,10 @@ static inline int read_full_file(const char *filename, char **ret_contents, size
}
int read_virtual_file_fd(int fd, size_t max_size, char **ret_contents, size_t *ret_size);
-int read_virtual_file(const char *filename, size_t max_size, char **ret_contents, size_t *ret_size);
+int read_virtual_file_at(int dir_fd, const char *filename, size_t max_size, char **ret_contents, size_t *ret_size);
+static inline int read_virtual_file(const char *filename, size_t max_size, char **ret_contents, size_t *ret_size) {
+ return read_virtual_file_at(AT_FDCWD, filename, max_size, ret_contents, ret_size);
+}
static inline int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size) {
return read_virtual_file(filename, SIZE_MAX, ret_contents, ret_size);
}
diff --git a/src/libnm-systemd-shared/src/basic/format-util.h b/src/libnm-systemd-shared/src/basic/format-util.h
index 7dd422b987..7db8b61d89 100644
--- a/src/libnm-systemd-shared/src/basic/format-util.h
+++ b/src/libnm-systemd-shared/src/basic/format-util.h
@@ -26,11 +26,15 @@ assert_cc(sizeof(gid_t) == sizeof(uint32_t));
# error Unknown time_t size
#endif
-#if defined __x86_64__ && defined __ILP32__
+#if 0 /* NM_IGNORED */
+#if SIZEOF_TIMEX_MEMBER == 8
# define PRI_TIMEX PRIi64
-#else
+#elif SIZEOF_TIMEX_MEMBER == 4
# define PRI_TIMEX "li"
+#else
+# error Unknown timex member size
#endif
+#endif /* NM_IGNORED */
#if SIZEOF_RLIM_T == 8
# define RLIM_FMT "%" PRIu64
diff --git a/src/libnm-systemd-shared/src/basic/fs-util.c b/src/libnm-systemd-shared/src/basic/fs-util.c
index 3f309868f1..b524a6fd1b 100644
--- a/src/libnm-systemd-shared/src/basic/fs-util.c
+++ b/src/libnm-systemd-shared/src/basic/fs-util.c
@@ -14,6 +14,7 @@
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
+#include "hostname-util.h"
#include "log.h"
#include "macro.h"
#include "missing_fcntl.h"
@@ -31,18 +32,13 @@
#include "strv.h"
#include "time-util.h"
#include "tmpfile-util.h"
+#include "umask-util.h"
#include "user-util.h"
#include "util.h"
int unlink_noerrno(const char *path) {
PROTECT_ERRNO;
- int r;
-
- r = unlink(path);
- if (r < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(unlink(path));
}
#if 0 /* NM_IGNORED */
@@ -59,7 +55,7 @@ int rmdir_parents(const char *path, const char *stop) {
if (!path_is_safe(stop))
return -EINVAL;
- p = strdupa(path);
+ p = strdupa_safe(path);
for (;;) {
char *slash = NULL;
@@ -99,8 +95,8 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
* want — though not atomic (i.e. for a short period both the new and the old filename will exist). */
if (linkat(olddirfd, oldpath, newdirfd, newpath, 0) >= 0) {
- if (unlinkat(olddirfd, oldpath, 0) < 0) {
- r = -errno; /* Backup errno before the following unlinkat() alters it */
+ r = RET_NERRNO(unlinkat(olddirfd, oldpath, 0));
+ if (r < 0) {
(void) unlinkat(newdirfd, newpath, 0);
return r;
}
@@ -119,10 +115,7 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
if (errno != ENOENT)
return -errno;
- if (renameat(olddirfd, oldpath, newdirfd, newpath) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(renameat(olddirfd, oldpath, newdirfd, newpath));
}
#endif /* NM_IGNORED */
@@ -290,14 +283,9 @@ int fchmod_and_chown_with_fallback(int fd, const char *path, mode_t mode, uid_t
}
int fchmod_umask(int fd, mode_t m) {
- mode_t u;
- int r;
-
- u = umask(0777);
- r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
- umask(u);
+ _cleanup_umask_ mode_t u = umask(0777);
- return r;
+ return RET_NERRNO(fchmod(fd, m & (~u)));
}
int fchmod_opath(int fd, mode_t m) {
@@ -550,7 +538,6 @@ int mkfifoat_atomic(int dirfd, const char *path, mode_t mode) {
int get_files_in_directory(const char *path, char ***list) {
_cleanup_strv_free_ char **l = NULL;
_cleanup_closedir_ DIR *d = NULL;
- struct dirent *de;
size_t n = 0;
assert(path);
@@ -830,7 +817,7 @@ int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
int open_parent(const char *path, int flags, mode_t mode) {
_cleanup_free_ char *parent = NULL;
- int fd, r;
+ int r;
r = path_extract_directory(path, &parent);
if (r < 0)
@@ -844,11 +831,7 @@ int open_parent(const char *path, int flags, mode_t mode) {
else if (!FLAGS_SET(flags, O_TMPFILE))
flags |= O_DIRECTORY|O_RDONLY;
- fd = open(parent, flags, mode);
- if (fd < 0)
- return -errno;
-
- return fd;
+ return RET_NERRNO(open(parent, flags, mode));
}
#endif /* NM_IGNORED */
@@ -962,3 +945,152 @@ int posix_fallocate_loop(int fd, uint64_t offset, uint64_t size) {
return -EINTR;
}
+
+int parse_cifs_service(
+ const char *s,
+ char **ret_host,
+ char **ret_service,
+ char **ret_path) {
+
+ _cleanup_free_ char *h = NULL, *ss = NULL, *x = NULL;
+ const char *p, *e, *d;
+ char delimiter;
+
+ /* Parses a CIFS service in form of //host/service/path… and splitting it in three parts. The last
+ * part is optional, in which case NULL is returned there. To maximize compatibility syntax with
+ * backslashes instead of slashes is accepted too. */
+
+ if (!s)
+ return -EINVAL;
+
+ p = startswith(s, "//");
+ if (!p) {
+ p = startswith(s, "\\\\");
+ if (!p)
+ return -EINVAL;
+ }
+
+ delimiter = s[0];
+ e = strchr(p, delimiter);
+ if (!e)
+ return -EINVAL;
+
+ h = strndup(p, e - p);
+ if (!h)
+ return -ENOMEM;
+
+ if (!hostname_is_valid(h, 0))
+ return -EINVAL;
+
+ e++;
+
+ d = strchrnul(e, delimiter);
+
+ ss = strndup(e, d - e);
+ if (!ss)
+ return -ENOMEM;
+
+ if (!filename_is_valid(ss))
+ return -EINVAL;
+
+ if (!isempty(d)) {
+ x = strdup(skip_leading_chars(d, CHAR_TO_STR(delimiter)));
+ if (!x)
+ return -EINVAL;
+
+ /* Make sure to convert Windows-style "\" → Unix-style / */
+ for (char *i = x; *i; i++)
+ if (*i == delimiter)
+ *i = '/';
+
+ if (!path_is_valid(x))
+ return -EINVAL;
+
+ path_simplify(x);
+ if (!path_is_normalized(x))
+ return -EINVAL;
+ }
+
+ if (ret_host)
+ *ret_host = TAKE_PTR(h);
+ if (ret_service)
+ *ret_service = TAKE_PTR(ss);
+ if (ret_path)
+ *ret_path = TAKE_PTR(x);
+
+ return 0;
+}
+
+int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
+ _cleanup_close_ int fd = -1, parent_fd = -1;
+ _cleanup_free_ char *fname = NULL;
+ bool made;
+ int r;
+
+ /* Creates a directory with mkdirat() and then opens it, in the "most atomic" fashion we can
+ * do. Guarantees that the returned fd refers to a directory. If O_EXCL is specified will fail if the
+ * dir already exists. Otherwise will open an existing dir, but only if it is one. */
+
+ if (flags & ~(O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_EXCL|O_NOATIME|O_NOFOLLOW|O_PATH))
+ return -EINVAL;
+ if ((flags & O_ACCMODE) != O_RDONLY)
+ return -EINVAL;
+
+ /* Note that O_DIRECTORY|O_NOFOLLOW is implied, but we allow specifying it anyway. The following
+ * flags actually make sense to specify: O_CLOEXEC, O_EXCL, O_NOATIME, O_PATH */
+
+ if (isempty(path))
+ return -EINVAL;
+
+ if (!filename_is_valid(path)) {
+ _cleanup_free_ char *parent = NULL;
+
+ /* If this is not a valid filename, it's a path. Let's open the parent directory then, so
+ * that we can pin it, and operate below it. */
+
+ r = path_extract_directory(path, &parent);
+ if (r < 0)
+ return r;
+
+ r = path_extract_filename(path, &fname);
+ if (r < 0)
+ return r;
+
+ parent_fd = openat(dirfd, parent, O_PATH|O_DIRECTORY|O_CLOEXEC);
+ if (parent_fd < 0)
+ return -errno;
+
+ dirfd = parent_fd;
+ path = fname;
+ }
+
+ r = RET_NERRNO(mkdirat(dirfd, path, mode));
+ if (r == -EEXIST) {
+ if (FLAGS_SET(flags, O_EXCL))
+ return -EEXIST;
+
+ made = false;
+ } else if (r < 0)
+ return r;
+ else
+ made = true;
+
+ fd = RET_NERRNO(openat(dirfd, path, (flags & ~O_EXCL)|O_DIRECTORY|O_NOFOLLOW));
+ if (fd < 0) {
+ if (fd == -ENOENT) /* We got ENOENT? then someone else immediately removed it after we
+ * created it. In that case let's return immediately without unlinking
+ * anything, because there simply isn't anything to unlink anymore. */
+ return -ENOENT;
+ if (fd == -ELOOP) /* is a symlink? exists already → created by someone else, don't unlink */
+ return -EEXIST;
+ if (fd == -ENOTDIR) /* not a directory? exists already → created by someone else, don't unlink */
+ return -EEXIST;
+
+ if (made)
+ (void) unlinkat(dirfd, path, AT_REMOVEDIR);
+
+ return fd;
+ }
+
+ return TAKE_FD(fd);
+}
diff --git a/src/libnm-systemd-shared/src/basic/fs-util.h b/src/libnm-systemd-shared/src/basic/fs-util.h
index f8a7657a07..0bbb3f6298 100644
--- a/src/libnm-systemd-shared/src/basic/fs-util.h
+++ b/src/libnm-systemd-shared/src/basic/fs-util.h
@@ -47,7 +47,7 @@ int fd_warn_permissions(const char *path, int fd);
int stat_warn_permissions(const char *path, const struct stat *st);
#define laccess(path, mode) \
- (faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) < 0 ? -errno : 0)
+ RET_NERRNO(faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW))
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
int touch(const char *path);
@@ -106,3 +106,7 @@ static inline int conservative_rename(const char *oldpath, const char *newpath)
}
int posix_fallocate_loop(int fd, uint64_t offset, uint64_t size);
+
+int parse_cifs_service(const char *s, char **ret_host, char **ret_service, char **ret_path);
+
+int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode);
diff --git a/src/libnm-systemd-shared/src/basic/hostname-util.c b/src/libnm-systemd-shared/src/basic/hostname-util.c
index 3063cc7c8f..1d1c2f5142 100644
--- a/src/libnm-systemd-shared/src/basic/hostname-util.c
+++ b/src/libnm-systemd-shared/src/basic/hostname-util.c
@@ -49,8 +49,7 @@ int gethostname_full(GetHostnameFlags flags, char **ret) {
assert_se(uname(&u) >= 0);
s = u.nodename;
- if (isempty(s) ||
- (!FLAGS_SET(flags, GET_HOSTNAME_ALLOW_NONE) && streq(s, "(none)")) ||
+ if (isempty(s) || streq(s, "(none)") ||
(!FLAGS_SET(flags, GET_HOSTNAME_ALLOW_LOCALHOST) && is_localhost(s)) ||
(FLAGS_SET(flags, GET_HOSTNAME_SHORT) && s[0] == '.')) {
if (!FLAGS_SET(flags, GET_HOSTNAME_FALLBACK_DEFAULT))
diff --git a/src/libnm-systemd-shared/src/basic/hostname-util.h b/src/libnm-systemd-shared/src/basic/hostname-util.h
index 0d1574db9e..d435bed50e 100644
--- a/src/libnm-systemd-shared/src/basic/hostname-util.h
+++ b/src/libnm-systemd-shared/src/basic/hostname-util.h
@@ -9,10 +9,9 @@
#include "strv.h"
typedef enum GetHostnameFlags {
- GET_HOSTNAME_ALLOW_NONE = 1 << 0, /* accepts "(none)". */
- GET_HOSTNAME_ALLOW_LOCALHOST = 1 << 1, /* accepts "localhost" or friends. */
- GET_HOSTNAME_FALLBACK_DEFAULT = 1 << 2, /* use default hostname if no hostname is set. */
- GET_HOSTNAME_SHORT = 1 << 3, /* kills the FQDN part if present. */
+ GET_HOSTNAME_ALLOW_LOCALHOST = 1 << 0, /* accepts "localhost" or friends. */
+ GET_HOSTNAME_FALLBACK_DEFAULT = 1 << 1, /* use default hostname if no hostname is set. */
+ GET_HOSTNAME_SHORT = 1 << 2, /* kills the FQDN part if present. */
} GetHostnameFlags;
int gethostname_full(GetHostnameFlags flags, char **ret);
diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.c b/src/libnm-systemd-shared/src/basic/in-addr-util.c
index bd4dd8fca3..1bf0764de1 100644
--- a/src/libnm-systemd-shared/src/basic/in-addr-util.c
+++ b/src/libnm-systemd-shared/src/basic/in-addr-util.c
@@ -629,65 +629,120 @@ int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mas
return 0;
}
-#if 0 /* NM_IGNORED */
-int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
+int in4_addr_mask(struct in_addr *addr, unsigned char prefixlen) {
+ struct in_addr mask;
+
assert(addr);
- if (family == AF_INET) {
- struct in_addr mask;
+ if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
+ return -EINVAL;
- if (!in4_addr_prefixlen_to_netmask(&mask, prefixlen))
- return -EINVAL;
+ addr->s_addr &= mask.s_addr;
+ return 0;
+}
- addr->in.s_addr &= mask.s_addr;
- return 0;
- }
+int in6_addr_mask(struct in6_addr *addr, unsigned char prefixlen) {
+ unsigned i;
- if (family == AF_INET6) {
- unsigned i;
+ for (i = 0; i < 16; i++) {
+ uint8_t mask;
- for (i = 0; i < 16; i++) {
- uint8_t mask;
+ if (prefixlen >= 8) {
+ mask = 0xFF;
+ prefixlen -= 8;
+ } else if (prefixlen > 0) {
+ mask = 0xFF << (8 - prefixlen);
+ prefixlen = 0;
+ } else {
+ assert(prefixlen == 0);
+ mask = 0;
+ }
- if (prefixlen >= 8) {
- mask = 0xFF;
- prefixlen -= 8;
- } else {
- mask = 0xFF << (8 - prefixlen);
- prefixlen = 0;
- }
+ addr->s6_addr[i] &= mask;
+ }
- addr->in6.s6_addr[i] &= mask;
- }
+ return 0;
+}
- return 0;
+#if 0 /* NM_IGNORED */
+int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) {
+ assert(addr);
+
+ switch (family) {
+ case AF_INET:
+ return in4_addr_mask(&addr->in, prefixlen);
+ case AF_INET6:
+ return in6_addr_mask(&addr->in6, prefixlen);
+ default:
+ return -EAFNOSUPPORT;
}
+}
- return -EAFNOSUPPORT;
+int in4_addr_prefix_covers(
+ const struct in_addr *prefix,
+ unsigned char prefixlen,
+ const struct in_addr *address) {
+
+ struct in_addr masked_prefix, masked_address;
+ int r;
+
+ assert(prefix);
+ assert(address);
+
+ masked_prefix = *prefix;
+ r = in4_addr_mask(&masked_prefix, prefixlen);
+ if (r < 0)
+ return r;
+
+ masked_address = *address;
+ r = in4_addr_mask(&masked_address, prefixlen);
+ if (r < 0)
+ return r;
+
+ return in4_addr_equal(&masked_prefix, &masked_address);
}
-int in_addr_prefix_covers(int family,
- const union in_addr_union *prefix,
- unsigned char prefixlen,
- const union in_addr_union *address) {
+int in6_addr_prefix_covers(
+ const struct in6_addr *prefix,
+ unsigned char prefixlen,
+ const struct in6_addr *address) {
- union in_addr_union masked_prefix, masked_address;
+ struct in6_addr masked_prefix, masked_address;
int r;
assert(prefix);
assert(address);
masked_prefix = *prefix;
- r = in_addr_mask(family, &masked_prefix, prefixlen);
+ r = in6_addr_mask(&masked_prefix, prefixlen);
if (r < 0)
return r;
masked_address = *address;
- r = in_addr_mask(family, &masked_address, prefixlen);
+ r = in6_addr_mask(&masked_address, prefixlen);
if (r < 0)
return r;
- return in_addr_equal(family, &masked_prefix, &masked_address);
+ return in6_addr_equal(&masked_prefix, &masked_address);
+}
+
+int in_addr_prefix_covers(
+ int family,
+ const union in_addr_union *prefix,
+ unsigned char prefixlen,
+ const union in_addr_union *address) {
+
+ assert(prefix);
+ assert(address);
+
+ switch (family) {
+ case AF_INET:
+ return in4_addr_prefix_covers(&prefix->in, prefixlen, &address->in);
+ case AF_INET6:
+ return in6_addr_prefix_covers(&prefix->in6, prefixlen, &address->in6);
+ default:
+ return -EAFNOSUPPORT;
+ }
}
int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret) {
@@ -855,4 +910,10 @@ int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
}
DEFINE_HASH_OPS(in6_addr_hash_ops, struct in6_addr, in6_addr_hash_func, in6_addr_compare_func);
+DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
+ in6_addr_hash_ops_free,
+ struct in6_addr,
+ in6_addr_hash_func,
+ in6_addr_compare_func,
+ free);
#endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.h b/src/libnm-systemd-shared/src/basic/in-addr-util.h
index c74b0d512b..0178391e5f 100644
--- a/src/libnm-systemd-shared/src/basic/in-addr-util.h
+++ b/src/libnm-systemd-shared/src/basic/in-addr-util.h
@@ -89,7 +89,11 @@ unsigned char in4_addr_netmask_to_prefixlen(const struct in_addr *addr);
struct in_addr* in4_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
int in4_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask);
+int in4_addr_mask(struct in_addr *addr, unsigned char prefixlen);
+int in6_addr_mask(struct in6_addr *addr, unsigned char prefixlen);
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen);
+int in4_addr_prefix_covers(const struct in_addr *prefix, unsigned char prefixlen, const struct in_addr *address);
+int in6_addr_prefix_covers(const struct in6_addr *prefix, unsigned char prefixlen, const struct in6_addr *address);
int in_addr_prefix_covers(int family, const union in_addr_union *prefix, unsigned char prefixlen, const union in_addr_union *address);
int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret);
int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
@@ -110,6 +114,13 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) {
return family == AF_INET6 ? 16 : 4;
}
+#define FAMILY_ADDRESS_SIZE_SAFE(f) \
+ ({ \
+ int _f = (f); \
+ _f == AF_INET ? sizeof(struct in_addr) : \
+ _f == AF_INET6 ? sizeof(struct in6_addr) : 0; \
+ })
+
/* Workaround for clang, explicitly specify the maximum-size element here.
* See also oss-fuzz#11344. */
#define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} })
@@ -119,6 +130,7 @@ int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b);
extern const struct hash_ops in_addr_data_hash_ops;
extern const struct hash_ops in6_addr_hash_ops;
+extern const struct hash_ops in6_addr_hash_ops_free;
#define IPV4_ADDRESS_FMT_STR "%u.%u.%u.%u"
#define IPV4_ADDRESS_FMT_VAL(address) \
diff --git a/src/libnm-systemd-shared/src/basic/inotify-util.c b/src/libnm-systemd-shared/src/basic/inotify-util.c
index cc2a92ad7d..59e03e620e 100644
--- a/src/libnm-systemd-shared/src/basic/inotify-util.c
+++ b/src/libnm-systemd-shared/src/basic/inotify-util.c
@@ -4,14 +4,26 @@
#include "fd-util.h"
#include "inotify-util.h"
+#include "stat-util.h"
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
- int wd;
+ int wd, r;
/* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
wd = inotify_add_watch(fd, FORMAT_PROC_FD_PATH(what), mask);
- if (wd < 0)
- return -errno;
+ if (wd < 0) {
+ if (errno != ENOENT)
+ return -errno;
+
+ /* Didn't work with ENOENT? If so, then either /proc/ isn't mounted, or the fd is bad */
+ r = proc_mounted();
+ if (r == 0)
+ return -ENOSYS;
+ if (r > 0)
+ return -EBADF;
+
+ return -ENOENT; /* OK, no clue, let's propagate the original error */
+ }
return wd;
}
diff --git a/src/libnm-systemd-shared/src/basic/list.h b/src/libnm-systemd-shared/src/basic/list.h
index e488fff9f0..f827e721eb 100644
--- a/src/libnm-systemd-shared/src/basic/list.h
+++ b/src/libnm-systemd-shared/src/basic/list.h
@@ -134,7 +134,7 @@
} while (false)
#define LIST_JUST_US(name,item) \
- (!(item)->name##_prev && !(item)->name##_next) \
+ (!(item)->name##_prev && !(item)->name##_next)
#define LIST_FOREACH(name,i,head) \
for ((i) = (head); (i); (i) = (i)->name##_next)
@@ -181,3 +181,12 @@
} \
(b) = NULL; \
} while (false)
+
+#define LIST_POP(name, a) \
+ ({ \
+ typeof(a)* _a = &(a); \
+ typeof(a) _p = *_a; \
+ if (_p) \
+ LIST_REMOVE(name, *_a, _p); \
+ _p; \
+ })
diff --git a/src/libnm-systemd-shared/src/basic/log.h b/src/libnm-systemd-shared/src/basic/log.h
index b11eac2171..88d278fdce 100644
--- a/src/libnm-systemd-shared/src/basic/log.h
+++ b/src/libnm-systemd-shared/src/basic/log.h
@@ -27,10 +27,14 @@ typedef enum LogTarget{
_LOG_TARGET_INVALID = -EINVAL,
} LogTarget;
-/* Note to readers: << and >> have lower precedence than & and | */
+/* This log level disables logging completely. It can only be passed to log_set_max_level() and cannot be
+ * used a regular log level. */
+#define LOG_NULL (LOG_EMERG - 1)
+
+/* Note to readers: << and >> have lower precedence (are evaluated earlier) than & and | */
#define SYNTHETIC_ERRNO(num) (1 << 30 | (num))
#define IS_SYNTHETIC_ERRNO(val) ((val) >> 30 & 1)
-#define ERRNO_VALUE(val) (abs(val) & 255)
+#define ERRNO_VALUE(val) (abs(val) & ~(1 << 30))
/* The callback function to be invoked when syntax warnings are seen
* in the unit files. */
@@ -90,6 +94,7 @@ int log_open(void);
void log_close(void);
void log_forget_fds(void);
+void log_parse_environment_variables(void);
void log_parse_environment(void);
#if 0 /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/macro.h b/src/libnm-systemd-shared/src/basic/macro.h
index 33d28332f9..79437775a5 100644
--- a/src/libnm-systemd-shared/src/basic/macro.h
+++ b/src/libnm-systemd-shared/src/basic/macro.h
@@ -25,7 +25,7 @@
#define _public_ __attribute__((__visibility__("default")))
#define _hidden_ __attribute__((__visibility__("hidden")))
#define _weakref_(x) __attribute__((__weakref__(#x)))
-#define _alignas_(x) __attribute__((__aligned__(__alignof(x))))
+#define _alignas_(x) __attribute__((__aligned__(__alignof__(x))))
#define _alignptr_ __attribute__((__aligned__(sizeof(void*))))
#define _warn_unused_result_ __attribute__((__warn_unused_result__))
@@ -154,24 +154,6 @@
#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) (p)))
#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) (p)))
-static inline size_t ALIGN_TO(size_t l, size_t ali) {
- /* Check that alignment is exponent of 2 */
-#if SIZE_MAX == UINT_MAX
- assert(__builtin_popcount(ali) == 1);
-#elif SIZE_MAX == ULONG_MAX
- assert(__builtin_popcountl(ali) == 1);
-#elif SIZE_MAX == ULLONG_MAX
- assert(__builtin_popcountll(ali) == 1);
-#else
-#error "Unexpected size_t"
-#endif
-
- if (l > SIZE_MAX - (ali - 1))
- return SIZE_MAX; /* indicate overflow */
-
- return ((l + ali - 1) & ~(ali - 1));
-}
-
#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) (p), (ali)))
/* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */
@@ -355,13 +337,6 @@ static inline int __coverity_check_and_return__(int condition) {
ans; \
})
-#define UPDATE_FLAG(orig, flag, b) \
- ((b) ? ((orig) | (flag)) : ((orig) & ~(flag)))
-#define SET_FLAG(v, flag, b) \
- (v) = UPDATE_FLAG(v, flag, b)
-#define FLAGS_SET(v, flags) \
- ((~(v) & (flags)) == 0)
-
#define SWAP_TWO(x, y) do { \
typeof(x) _t = (x); \
(x) = (y); \
diff --git a/src/libnm-systemd-shared/src/basic/missing_syscall.h b/src/libnm-systemd-shared/src/basic/missing_syscall.h
index aeb994f061..41c83ec522 100644
--- a/src/libnm-systemd-shared/src/basic/missing_syscall.h
+++ b/src/libnm-systemd-shared/src/basic/missing_syscall.h
@@ -20,6 +20,7 @@
#include <asm/sgidefs.h>
#endif
+#include "macro.h"
#include "missing_keyctl.h"
#include "missing_stat.h"
#include "missing_syscall_def.h"
@@ -79,7 +80,8 @@ static inline int missing_memfd_create(const char *name, unsigned int flags) {
/* ======================================================================= */
#if !HAVE_GETRANDOM
-static inline int missing_getrandom(void *buffer, size_t count, unsigned flags) {
+/* glibc says getrandom() returns ssize_t */
+static inline ssize_t missing_getrandom(void *buffer, size_t count, unsigned flags) {
# ifdef __NR_getrandom
return syscall(__NR_getrandom, buffer, count, flags);
# else
@@ -466,8 +468,52 @@ struct mount_attr {
struct mount_attr;
#endif
+#ifndef MOUNT_ATTR_RDONLY
+#define MOUNT_ATTR_RDONLY 0x00000001 /* Mount read-only */
+#endif
+
+#ifndef MOUNT_ATTR_NOSUID
+#define MOUNT_ATTR_NOSUID 0x00000002 /* Ignore suid and sgid bits */
+#endif
+
+#ifndef MOUNT_ATTR_NODEV
+#define MOUNT_ATTR_NODEV 0x00000004 /* Disallow access to device special files */
+#endif
+
+#ifndef MOUNT_ATTR_NOEXEC
+#define MOUNT_ATTR_NOEXEC 0x00000008 /* Disallow program execution */
+#endif
+
+#ifndef MOUNT_ATTR__ATIME
+#define MOUNT_ATTR__ATIME 0x00000070 /* Setting on how atime should be updated */
+#endif
+
+#ifndef MOUNT_ATTR_RELATIME
+#define MOUNT_ATTR_RELATIME 0x00000000 /* - Update atime relative to mtime/ctime. */
+#endif
+
+#ifndef MOUNT_ATTR_NOATIME
+#define MOUNT_ATTR_NOATIME 0x00000010 /* - Do not update access times. */
+#endif
+
+#ifndef MOUNT_ATTR_STRICTATIME
+#define MOUNT_ATTR_STRICTATIME 0x00000020 /* - Always perform atime updates */
+#endif
+
+#ifndef MOUNT_ATTR_NODIRATIME
+#define MOUNT_ATTR_NODIRATIME 0x00000080 /* Do not update directory access times */
+#endif
+
#ifndef MOUNT_ATTR_IDMAP
-#define MOUNT_ATTR_IDMAP 0x00100000
+#define MOUNT_ATTR_IDMAP 0x00100000 /* Idmap mount to @userns_fd in struct mount_attr. */
+#endif
+
+#ifndef MOUNT_ATTR_NOSYMFOLLOW
+#define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 /* Do not follow symlinks */
+#endif
+
+#ifndef MOUNT_ATTR_SIZE_VER0
+#define MOUNT_ATTR_SIZE_VER0 32 /* sizeof first published struct */
#endif
#ifndef AT_RECURSIVE
@@ -545,4 +591,20 @@ static inline int missing_move_mount(
# define move_mount missing_move_mount
#endif
+
+/* ======================================================================= */
+
+#if !HAVE_GETDENTS64
+
+static inline ssize_t missing_getdents64(int fd, void *buffer, size_t length) {
+# if defined __NR_getdents64 && __NR_getdents64 >= 0
+ return syscall(__NR_getdents64, fd, buffer, length);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+
+# define getdents64 missing_getdents64
+#endif
#endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/parse-util.c b/src/libnm-systemd-shared/src/basic/parse-util.c
index f81bf1da28..4ba2657c2b 100644
--- a/src/libnm-systemd-shared/src/basic/parse-util.c
+++ b/src/libnm-systemd-shared/src/basic/parse-util.c
@@ -651,7 +651,7 @@ int parse_ip_port(const char *s, uint16_t *ret) {
uint16_t l;
int r;
- r = safe_atou16(s, &l);
+ r = safe_atou16_full(s, SAFE_ATO_REFUSE_LEADING_WHITESPACE, &l);
if (r < 0)
return r;
@@ -711,7 +711,7 @@ int parse_dev(const char *s, dev_t *ret) {
if (s[n] != ':')
return -EINVAL;
- major = strndupa(s, n);
+ major = strndupa_safe(s, n);
r = safe_atou(major, &x);
if (r < 0)
return r;
@@ -772,7 +772,7 @@ int parse_loadavg_fixed_point(const char *s, loadavg_t *ret) {
if (!d)
return -EINVAL;
- i_str = strndupa(s, d - s);
+ i_str = strndupa_safe(s, d - s);
f_str = d + 1;
r = safe_atolu_full(i_str, 10, &i);
diff --git a/src/libnm-systemd-shared/src/basic/path-util.c b/src/libnm-systemd-shared/src/basic/path-util.c
index 92c5504866..f391848fcb 100644
--- a/src/libnm-systemd-shared/src/basic/path-util.c
+++ b/src/libnm-systemd-shared/src/basic/path-util.c
@@ -1246,8 +1246,6 @@ char *file_in_same_dir(const char *path, const char *filename) {
}
bool hidden_or_backup_file(const char *filename) {
- const char *p;
-
assert(filename);
if (filename[0] == '.' ||
@@ -1257,24 +1255,25 @@ bool hidden_or_backup_file(const char *filename) {
endswith(filename, "~"))
return true;
- p = strrchr(filename, '.');
- if (!p)
+ const char *dot = strrchr(filename, '.');
+ if (!dot)
return false;
- /* Please, let's not add more entries to the list below. If external projects think it's a good idea to come up
- * with always new suffixes and that everybody else should just adjust to that, then it really should be on
- * them. Hence, in future, let's not add any more entries. Instead, let's ask those packages to instead adopt
- * one of the generic suffixes/prefixes for hidden files or backups, possibly augmented with an additional
- * string. Specifically: there's now:
+ /* Please, let's not add more entries to the list below. If external projects think it's a good idea
+ * to come up with always new suffixes and that everybody else should just adjust to that, then it
+ * really should be on them. Hence, in future, let's not add any more entries. Instead, let's ask
+ * those packages to instead adopt one of the generic suffixes/prefixes for hidden files or backups,
+ * possibly augmented with an additional string. Specifically: there's now:
*
* The generic suffixes "~" and ".bak" for backup files
* The generic prefix "." for hidden files
*
- * Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old", ".foopkg-dist"
- * or so registered, let's refuse that and ask them to use ".foopkg.new", ".foopkg.old" or ".foopkg~" instead.
+ * Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old",
+ * ".foopkg-dist" or so registered, let's refuse that and ask them to use ".foopkg.new",
+ * ".foopkg.old" or ".foopkg~" instead.
*/
- return STR_IN_SET(p + 1,
+ return STR_IN_SET(dot + 1,
"rpmnew",
"rpmsave",
"rpmorig",
@@ -1296,15 +1295,16 @@ bool hidden_or_backup_file(const char *filename) {
bool is_device_path(const char *path) {
- /* Returns true on paths that likely refer to a device, either by path in sysfs or to something in /dev */
+ /* Returns true for paths that likely refer to a device, either by path in sysfs or to something in
+ * /dev. */
return PATH_STARTSWITH_SET(path, "/dev/", "/sys/");
}
bool valid_device_node_path(const char *path) {
- /* Some superficial checks whether the specified path is a valid device node path, all without looking at the
- * actual device node. */
+ /* Some superficial checks whether the specified path is a valid device node path, all without
+ * looking at the actual device node. */
if (!PATH_STARTSWITH_SET(path, "/dev/", "/run/systemd/inaccessible/"))
return false;
@@ -1318,8 +1318,8 @@ bool valid_device_node_path(const char *path) {
bool valid_device_allow_pattern(const char *path) {
assert(path);
- /* Like valid_device_node_path(), but also allows full-subsystem expressions, like DeviceAllow= and DeviceDeny=
- * accept it */
+ /* Like valid_device_node_path(), but also allows full-subsystem expressions like those accepted by
+ * DeviceAllow= and DeviceDeny=. */
if (STARTSWITH_SET(path, "block-", "char-"))
return true;
@@ -1412,8 +1412,8 @@ bool dot_or_dot_dot(const char *path) {
#if 0 /* NM_IGNORED */
bool empty_or_root(const char *path) {
- /* For operations relative to some root directory, returns true if the specified root directory is redundant,
- * i.e. either / or NULL or the empty string or any equivalent. */
+ /* For operations relative to some root directory, returns true if the specified root directory is
+ * redundant, i.e. either / or NULL or the empty string or any equivalent. */
if (isempty(path))
return true;
diff --git a/src/libnm-systemd-shared/src/basic/process-util.c b/src/libnm-systemd-shared/src/basic/process-util.c
index 96d0912c59..70564bd398 100644
--- a/src/libnm-systemd-shared/src/basic/process-util.c
+++ b/src/libnm-systemd-shared/src/basic/process-util.c
@@ -187,13 +187,13 @@ static int get_process_cmdline_nulstr(
return r;
}
-int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **line) {
+int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **ret) {
_cleanup_free_ char *t = NULL;
size_t k;
char *ans;
- assert(line);
assert(pid >= 0);
+ assert(ret);
/* Retrieve and format a commandline. See above for discussion of retrieval options.
*
@@ -220,25 +220,23 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags
assert(!(flags & PROCESS_CMDLINE_USE_LOCALE));
_cleanup_strv_free_ char **args = NULL;
+ char **p;
args = strv_parse_nulstr(t, k);
if (!args)
return -ENOMEM;
- for (size_t i = 0; args[i]; i++) {
- char *e;
-
- e = shell_maybe_quote(args[i], shflags);
- if (!e)
- return -ENOMEM;
+ /* Drop trailing empty strings. See issue #21186. */
+ STRV_FOREACH_BACKWARDS(p, args) {
+ if (!isempty(*p))
+ break;
- free_and_replace(args[i], e);
+ *p = mfree(*p);
}
- ans = strv_join(args, " ");
+ ans = quote_command_line(args, shflags);
if (!ans)
return -ENOMEM;
-
} else {
/* Arguments are separated by NULs. Let's replace those with spaces. */
for (size_t i = 0; i < k - 1; i++)
@@ -257,7 +255,7 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags
ans = str_realloc(ans);
}
- *line = ans;
+ *ret = ans;
return 0;
}
@@ -464,29 +462,29 @@ int is_kernel_thread(pid_t pid) {
return !!(flags & PF_KTHREAD);
}
-int get_process_capeff(pid_t pid, char **capeff) {
+int get_process_capeff(pid_t pid, char **ret) {
const char *p;
int r;
- assert(capeff);
assert(pid >= 0);
+ assert(ret);
p = procfs_file_alloca(pid, "status");
- r = get_proc_field(p, "CapEff", WHITESPACE, capeff);
+ r = get_proc_field(p, "CapEff", WHITESPACE, ret);
if (r == -ENOENT)
return -ESRCH;
return r;
}
-static int get_process_link_contents(const char *proc_file, char **name) {
+static int get_process_link_contents(const char *proc_file, char **ret) {
int r;
assert(proc_file);
- assert(name);
+ assert(ret);
- r = readlink_malloc(proc_file, name);
+ r = readlink_malloc(proc_file, ret);
if (r == -ENOENT)
return -ESRCH;
if (r < 0)
@@ -495,32 +493,33 @@ static int get_process_link_contents(const char *proc_file, char **name) {
return 0;
}
-int get_process_exe(pid_t pid, char **name) {
+int get_process_exe(pid_t pid, char **ret) {
const char *p;
char *d;
int r;
assert(pid >= 0);
+ assert(ret);
p = procfs_file_alloca(pid, "exe");
- r = get_process_link_contents(p, name);
+ r = get_process_link_contents(p, ret);
if (r < 0)
return r;
- d = endswith(*name, " (deleted)");
+ d = endswith(*ret, " (deleted)");
if (d)
*d = '\0';
return 0;
}
-static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
+static int get_process_id(pid_t pid, const char *field, uid_t *ret) {
_cleanup_fclose_ FILE *f = NULL;
const char *p;
int r;
assert(field);
- assert(uid);
+ assert(ret);
if (pid < 0)
return -EINVAL;
@@ -550,60 +549,62 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
l[strcspn(l, WHITESPACE)] = 0;
- return parse_uid(l, uid);
+ return parse_uid(l, ret);
}
}
return -EIO;
}
-int get_process_uid(pid_t pid, uid_t *uid) {
+int get_process_uid(pid_t pid, uid_t *ret) {
if (pid == 0 || pid == getpid_cached()) {
- *uid = getuid();
+ *ret = getuid();
return 0;
}
- return get_process_id(pid, "Uid:", uid);
+ return get_process_id(pid, "Uid:", ret);
}
-int get_process_gid(pid_t pid, gid_t *gid) {
+int get_process_gid(pid_t pid, gid_t *ret) {
if (pid == 0 || pid == getpid_cached()) {
- *gid = getgid();
+ *ret = getgid();
return 0;
}
assert_cc(sizeof(uid_t) == sizeof(gid_t));
- return get_process_id(pid, "Gid:", gid);
+ return get_process_id(pid, "Gid:", ret);
}
-int get_process_cwd(pid_t pid, char **cwd) {
+int get_process_cwd(pid_t pid, char **ret) {
const char *p;
assert(pid >= 0);
+ assert(ret);
if (pid == 0 || pid == getpid_cached())
- return safe_getcwd(cwd);
+ return safe_getcwd(ret);
p = procfs_file_alloca(pid, "cwd");
- return get_process_link_contents(p, cwd);
+ return get_process_link_contents(p, ret);
}
-int get_process_root(pid_t pid, char **root) {
+int get_process_root(pid_t pid, char **ret) {
const char *p;
assert(pid >= 0);
+ assert(ret);
p = procfs_file_alloca(pid, "root");
- return get_process_link_contents(p, root);
+ return get_process_link_contents(p, ret);
}
#define ENVIRONMENT_BLOCK_MAX (5U*1024U*1024U)
-int get_process_environ(pid_t pid, char **env) {
+int get_process_environ(pid_t pid, char **ret) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *outcome = NULL;
size_t sz = 0;
@@ -611,7 +612,7 @@ int get_process_environ(pid_t pid, char **env) {
int r;
assert(pid >= 0);
- assert(env);
+ assert(ret);
p = procfs_file_alloca(pid, "environ");
@@ -643,7 +644,7 @@ int get_process_environ(pid_t pid, char **env) {
}
outcome[sz] = '\0';
- *env = TAKE_PTR(outcome);
+ *ret = TAKE_PTR(outcome);
return 0;
}
@@ -702,13 +703,13 @@ int get_process_ppid(pid_t pid, pid_t *ret) {
return 0;
}
-int get_process_umask(pid_t pid, mode_t *umask) {
+int get_process_umask(pid_t pid, mode_t *ret) {
_cleanup_free_ char *m = NULL;
const char *p;
int r;
- assert(umask);
assert(pid >= 0);
+ assert(ret);
p = procfs_file_alloca(pid, "status");
@@ -716,7 +717,7 @@ int get_process_umask(pid_t pid, mode_t *umask) {
if (r == -ENOENT)
return -ESRCH;
- return parse_mode(m, umask);
+ return parse_mode(m, ret);
}
int wait_for_terminate(pid_t pid, siginfo_t *status) {
@@ -830,7 +831,7 @@ int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) {
if (n >= until)
break;
- r = sigtimedwait(&mask, NULL, timespec_store(&ts, until - n)) < 0 ? -errno : 0;
+ r = RET_NERRNO(sigtimedwait(&mask, NULL, timespec_store(&ts, until - n)));
/* Assuming we woke due to the child exiting. */
if (waitid(P_PID, pid, &status, WEXITED|WNOHANG) == 0) {
if (status.si_pid == pid) {
@@ -863,8 +864,8 @@ int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) {
void sigkill_wait(pid_t pid) {
assert(pid > 1);
- if (kill(pid, SIGKILL) >= 0)
- (void) wait_for_terminate(pid, NULL);
+ (void) kill(pid, SIGKILL);
+ (void) wait_for_terminate(pid, NULL);
}
void sigkill_waitp(pid_t *pid) {
@@ -881,14 +882,14 @@ void sigkill_waitp(pid_t *pid) {
void sigterm_wait(pid_t pid) {
assert(pid > 1);
- if (kill_and_sigcont(pid, SIGTERM) >= 0)
- (void) wait_for_terminate(pid, NULL);
+ (void) kill_and_sigcont(pid, SIGTERM);
+ (void) wait_for_terminate(pid, NULL);
}
int kill_and_sigcont(pid_t pid, int sig) {
int r;
- r = kill(pid, sig) < 0 ? -errno : 0;
+ r = RET_NERRNO(kill(pid, sig));
/* If this worked, also send SIGCONT, unless we already just sent a SIGCONT, or SIGKILL was sent which isn't
* affected by a process being suspended anyway. */
@@ -1064,8 +1065,8 @@ unsigned long personality_from_string(const char *p) {
if (architecture == native_architecture())
return PER_LINUX;
-#ifdef SECONDARY_ARCHITECTURE
- if (architecture == SECONDARY_ARCHITECTURE)
+#ifdef ARCHITECTURE_SECONDARY
+ if (architecture == ARCHITECTURE_SECONDARY)
return PER_LINUX32;
#endif
@@ -1077,9 +1078,9 @@ const char* personality_to_string(unsigned long p) {
if (p == PER_LINUX)
architecture = native_architecture();
-#ifdef SECONDARY_ARCHITECTURE
+#ifdef ARCHITECTURE_SECONDARY
else if (p == PER_LINUX32)
- architecture = SECONDARY_ARCHITECTURE;
+ architecture = ARCHITECTURE_SECONDARY;
#endif
if (architecture < 0)
@@ -1150,23 +1151,6 @@ int pid_compare_func(const pid_t *a, const pid_t *b) {
/* Suitable for usage in qsort() */
return CMP(*a, *b);
}
-
-int ioprio_parse_priority(const char *s, int *ret) {
- int i, r;
-
- assert(s);
- assert(ret);
-
- r = safe_atoi(s, &i);
- if (r < 0)
- return r;
-
- if (!ioprio_priority_is_valid(i))
- return -EINVAL;
-
- *ret = i;
- return 0;
-}
#endif /* NM_IGNORED */
/* The cached PID, possible values:
@@ -1256,7 +1240,7 @@ static void restore_sigsetp(sigset_t **ssp) {
int safe_fork_full(
const char *name,
- int except_fds[],
+ const int except_fds[],
size_t n_except_fds,
ForkFlags flags,
pid_t *ret_pid) {
@@ -1451,7 +1435,7 @@ int safe_fork_full(
int namespace_fork(
const char *outer_name,
const char *inner_name,
- int except_fds[],
+ const int except_fds[],
size_t n_except_fds,
ForkFlags flags,
int pidns_fd,
@@ -1467,8 +1451,7 @@ int namespace_fork(
* process. This ensures that we are fully a member of the destination namespace, with pidns an all, so that
* /proc/self/fd works correctly. */
- r = safe_fork_full(outer_name, except_fds, n_except_fds,
- (flags|FORK_DEATHSIG) & ~(FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE), ret_pid);
+ r = safe_fork_full(outer_name, except_fds, n_except_fds, (flags|FORK_DEATHSIG) & ~(FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE), ret_pid);
if (r < 0)
return r;
if (r == 0) {
@@ -1513,7 +1496,7 @@ int set_oom_score_adjust(int value) {
}
int get_oom_score_adjust(int *ret) {
- _cleanup_free_ char *t;
+ _cleanup_free_ char *t = NULL;
int r, a;
r = read_virtual_file("/proc/self/oom_score_adj", SIZE_MAX, &t, NULL);
@@ -1628,14 +1611,27 @@ bool invoked_as(char *argv[], const char *token) {
return strstr(last_path_component(argv[0]), token);
}
-static const char *const ioprio_class_table[] = {
- [IOPRIO_CLASS_NONE] = "none",
- [IOPRIO_CLASS_RT] = "realtime",
- [IOPRIO_CLASS_BE] = "best-effort",
- [IOPRIO_CLASS_IDLE] = "idle",
-};
+_noreturn_ void freeze(void) {
+ log_close();
+
+ /* Make sure nobody waits for us (i.e. on one of our sockets) anymore. Note that we use
+ * close_all_fds_without_malloc() instead of plain close_all_fds() here, since we want this function
+ * to be compatible with being called from signal handlers. */
+ (void) close_all_fds_without_malloc(NULL, 0);
+
+ /* Let's not freeze right away, but keep reaping zombies. */
+ for (;;) {
+ siginfo_t si = {};
+
+ if (waitid(P_ALL, 0, &si, WEXITED) < 0 && errno != EINTR)
+ break;
+ }
+
+ /* waitid() failed with an unexpected error, things are really borked. Freeze now! */
+ for (;;)
+ pause();
+}
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, IOPRIO_N_CLASSES);
static const char *const sigchld_code_table[] = {
[CLD_EXITED] = "exited",
diff --git a/src/libnm-systemd-shared/src/basic/process-util.h b/src/libnm-systemd-shared/src/basic/process-util.h
index bc16d328f4..a957cab29d 100644
--- a/src/libnm-systemd-shared/src/basic/process-util.h
+++ b/src/libnm-systemd-shared/src/basic/process-util.h
@@ -14,7 +14,6 @@
#include "alloc-util.h"
#include "format-util.h"
#include "macro.h"
-#include "missing_ioprio.h"
#include "time-util.h"
#define procfs_file_alloca(pid, field) \
@@ -39,17 +38,17 @@ typedef enum ProcessCmdlineFlags {
PROCESS_CMDLINE_QUOTE_POSIX = 1 << 3,
} ProcessCmdlineFlags;
-int get_process_comm(pid_t pid, char **name);
-int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **line);
-int get_process_exe(pid_t pid, char **name);
-int get_process_uid(pid_t pid, uid_t *uid);
-int get_process_gid(pid_t pid, gid_t *gid);
-int get_process_capeff(pid_t pid, char **capeff);
-int get_process_cwd(pid_t pid, char **cwd);
-int get_process_root(pid_t pid, char **root);
-int get_process_environ(pid_t pid, char **environ);
-int get_process_ppid(pid_t pid, pid_t *ppid);
-int get_process_umask(pid_t pid, mode_t *umask);
+int get_process_comm(pid_t pid, char **ret);
+int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **ret);
+int get_process_exe(pid_t pid, char **ret);
+int get_process_uid(pid_t pid, uid_t *ret);
+int get_process_gid(pid_t pid, gid_t *ret);
+int get_process_capeff(pid_t pid, char **ret);
+int get_process_cwd(pid_t pid, char **ret);
+int get_process_root(pid_t pid, char **ret);
+int get_process_environ(pid_t pid, char **ret);
+int get_process_ppid(pid_t pid, pid_t *ret);
+int get_process_umask(pid_t pid, mode_t *ret);
int wait_for_terminate(pid_t pid, siginfo_t *status);
@@ -97,9 +96,6 @@ const char *personality_to_string(unsigned long);
int safe_personality(unsigned long p);
int opinionated_personality(unsigned long *ret);
-int ioprio_class_to_string_alloc(int i, char **s);
-int ioprio_class_from_string(const char *s);
-
const char *sigchld_code_to_string(int i) _const_;
int sigchld_code_from_string(const char *s) _pure_;
@@ -131,21 +127,11 @@ static inline bool sched_priority_is_valid(int i) {
return i >= 0 && i <= sched_get_priority_max(SCHED_RR);
}
-static inline bool ioprio_class_is_valid(int i) {
- return IN_SET(i, IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE);
-}
-
-static inline bool ioprio_priority_is_valid(int i) {
- return i >= 0 && i < IOPRIO_BE_NR;
-}
-
static inline bool pid_is_valid(pid_t p) {
return p > 0;
}
#endif /* NM_IGNORED */
-int ioprio_parse_priority(const char *s, int *ret);
-
pid_t getpid_cached(void);
void reset_cached_pid(void);
@@ -168,13 +154,13 @@ typedef enum ForkFlags {
FORK_NEW_USERNS = 1 << 13, /* Run child in its own user namespace */
} ForkFlags;
-int safe_fork_full(const char *name, int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
+int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
return safe_fork_full(name, NULL, 0, flags, ret_pid);
}
-int namespace_fork(const char *outer_name, const char *inner_name, int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid);
+int namespace_fork(const char *outer_name, const char *inner_name, const int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid);
int set_oom_score_adjust(int value);
int get_oom_score_adjust(int *ret);
@@ -194,8 +180,9 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX);
/* Like TAKE_PTR() but for child PIDs, resetting them to 0 */
#define TAKE_PID(pid) \
({ \
- pid_t _pid_ = (pid); \
- (pid) = 0; \
+ pid_t *_ppid_ = &(pid); \
+ pid_t _pid_ = *_ppid_; \
+ *_ppid_ = 0; \
_pid_; \
})
@@ -204,3 +191,5 @@ int pidfd_get_pid(int fd, pid_t *ret);
int setpriority_closest(int priority);
bool invoked_as(char *argv[], const char *token);
+
+_noreturn_ void freeze(void);
diff --git a/src/libnm-systemd-shared/src/basic/random-util.c b/src/libnm-systemd-shared/src/basic/random-util.c
index 063784dc83..9832f8efc9 100644
--- a/src/libnm-systemd-shared/src/basic/random-util.c
+++ b/src/libnm-systemd-shared/src/basic/random-util.c
@@ -163,7 +163,6 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
static int have_syscall = -1;
_cleanup_close_ int fd = -1;
bool got_some = false;
- int r;
/* Gathers some high-quality randomness from the kernel (or potentially mid-quality randomness from
* the CPU if the RANDOM_ALLOW_RDRAND flag is set). This call won't block, unless the RANDOM_BLOCK
@@ -222,25 +221,26 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) {
for (;;) {
+ ssize_t l;
#if !HAVE_GETRANDOM
/* NetworkManager Note: systemd calls the syscall directly in this case. Don't add that workaround.
* If you don't compile against a libc that provides getrandom(), you don't get it. */
- r = -1;
+ l = -1;
errno = ENOSYS;
#else
- r = getrandom(p, n,
+ l = getrandom(p, n,
(FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_NONBLOCK) |
(FLAGS_SET(flags, RANDOM_ALLOW_INSECURE) ? GRND_INSECURE : 0));
#endif
- if (r > 0) {
+ if (l > 0) {
have_syscall = true;
- if ((size_t) r == n)
+ if ((size_t) l == n)
return 0; /* Yay, success! */
- assert((size_t) r < n);
- p = (uint8_t*) p + r;
- n -= r;
+ assert((size_t) l < n);
+ p = (uint8_t*) p + l;
+ n -= l;
if (FLAGS_SET(flags, RANDOM_EXTEND_WITH_PSEUDO)) {
/* Fill in the remaining bytes using pseudo-random values */
@@ -257,7 +257,7 @@ int genuine_random_bytes(void *p, size_t n, RandomFlags flags) {
/* Fill in the rest with /dev/urandom */
break;
- } else if (r == 0) {
+ } else if (l == 0) {
have_syscall = true;
return -EIO;
diff --git a/src/libnm-systemd-shared/src/basic/signal-util.c b/src/libnm-systemd-shared/src/basic/signal-util.c
index f96eb4d488..6d8c9920f0 100644
--- a/src/libnm-systemd-shared/src/basic/signal-util.c
+++ b/src/libnm-systemd-shared/src/basic/signal-util.c
@@ -5,6 +5,7 @@
#include <errno.h>
#include <stdarg.h>
+#include "errno-util.h"
#include "macro.h"
#include "parse-util.h"
#include "signal-util.h"
@@ -42,10 +43,7 @@ int reset_signal_mask(void) {
if (sigemptyset(&ss) < 0)
return -errno;
- if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(sigprocmask(SIG_SETMASK, &ss, NULL));
}
int sigaction_many_internal(const struct sigaction *sa, ...) {
@@ -122,7 +120,7 @@ int sigprocmask_many(int how, sigset_t *old, ...) {
return 0;
}
-static const char *const __signal_table[] = {
+static const char *const static_signal_table[] = {
[SIGHUP] = "HUP",
[SIGINT] = "INT",
[SIGQUIT] = "QUIT",
@@ -158,13 +156,13 @@ static const char *const __signal_table[] = {
[SIGSYS] = "SYS"
};
-DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP(static_signal, int);
const char *signal_to_string(int signo) {
static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int)];
const char *name;
- name = __signal_to_string(signo);
+ name = static_signal_to_string(signo);
if (name)
return name;
@@ -193,7 +191,7 @@ int signal_from_string(const char *s) {
s += 3;
/* Check that the input is a signal name. */
- signo = __signal_from_string(s);
+ signo = static_signal_from_string(s);
if (signo > 0)
return signo;
@@ -250,11 +248,7 @@ int signal_is_blocked(int sig) {
if (r != 0)
return -r;
- r = sigismember(&ss, sig);
- if (r < 0)
- return -errno;
-
- return r;
+ return RET_NERRNO(sigismember(&ss, sig));
}
int pop_pending_signal_internal(int sig, ...) {
diff --git a/src/libnm-systemd-shared/src/basic/socket-util.c b/src/libnm-systemd-shared/src/basic/socket-util.c
index 49a4df4476..6478fdee49 100644
--- a/src/libnm-systemd-shared/src/basic/socket-util.c
+++ b/src/libnm-systemd-shared/src/basic/socket-util.c
@@ -405,6 +405,41 @@ const union in_addr_union *sockaddr_in_addr(const struct sockaddr *_sa) {
}
}
+int sockaddr_set_in_addr(
+ union sockaddr_union *u,
+ int family,
+ const union in_addr_union *a,
+ uint16_t port) {
+
+ assert(u);
+ assert(a);
+
+ switch (family) {
+
+ case AF_INET:
+ u->in = (struct sockaddr_in) {
+ .sin_family = AF_INET,
+ .sin_addr = a->in,
+ .sin_port = htobe16(port),
+ };
+
+ return 0;
+
+ case AF_INET6:
+ u->in6 = (struct sockaddr_in6) {
+ .sin6_family = AF_INET6,
+ .sin6_addr = a->in6,
+ .sin6_port = htobe16(port),
+ };
+
+ return 0;
+
+ default:
+ return -EAFNOSUPPORT;
+
+ }
+}
+
int sockaddr_pretty(
const struct sockaddr *_sa,
socklen_t salen,
@@ -556,7 +591,7 @@ int getpeername_pretty(int fd, bool include_port, char **ret) {
return -errno;
if (sa.sa.sa_family == AF_UNIX) {
- struct ucred ucred = {};
+ struct ucred ucred = UCRED_INVALID;
/* UNIX connection sockets are anonymous, so let's use
* PID/UID as pretty credentials instead */
@@ -1238,10 +1273,7 @@ int socket_bind_to_ifname(int fd, const char *ifname) {
/* Call with NULL to drop binding */
- if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen_ptr(ifname)) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen_ptr(ifname)));
}
int socket_bind_to_ifindex(int fd, int ifindex) {
@@ -1250,13 +1282,9 @@ int socket_bind_to_ifindex(int fd, int ifindex) {
assert(fd >= 0);
- if (ifindex <= 0) {
+ if (ifindex <= 0)
/* Drop binding */
- if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, NULL, 0) < 0)
- return -errno;
-
- return 0;
- }
+ return RET_NERRNO(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, NULL, 0));
r = setsockopt_int(fd, SOL_SOCKET, SO_BINDTOIFINDEX, ifindex);
if (r != -ENOPROTOOPT)
@@ -1345,16 +1373,10 @@ int socket_set_unicast_if(int fd, int af, int ifi) {
switch (af) {
case AF_INET:
- if (setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_be, sizeof(ifindex_be)) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_be, sizeof(ifindex_be)));
case AF_INET6:
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_be, sizeof(ifindex_be)) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_be, sizeof(ifindex_be)));
default:
return -EAFNOSUPPORT;
diff --git a/src/libnm-systemd-shared/src/basic/socket-util.h b/src/libnm-systemd-shared/src/basic/socket-util.h
index 4caa27c8f2..ddea535008 100644
--- a/src/libnm-systemd-shared/src/basic/socket-util.h
+++ b/src/libnm-systemd-shared/src/basic/socket-util.h
@@ -15,6 +15,7 @@
#include <sys/un.h>
#include "errno-util.h"
+#include "in-addr-util.h"
#include "macro.h"
#include "missing_network.h"
#include "missing_socket.h"
@@ -108,6 +109,7 @@ bool socket_ipv6_is_enabled(void);
int sockaddr_port(const struct sockaddr *_sa, unsigned *port);
const union in_addr_union *sockaddr_in_addr(const struct sockaddr *sa);
+int sockaddr_set_in_addr(union sockaddr_union *u, int family, const union in_addr_union *a, uint16_t port);
int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret);
int getpeername_pretty(int fd, bool include_port, char **ret);
@@ -331,3 +333,6 @@ static inline int socket_set_recvfragsize(int fd, int af, bool b) {
#endif /* NM_IGNORED */
int socket_get_mtu(int fd, int af, size_t *ret);
+
+/* an initializer for struct ucred that initialized all fields to the invalid value appropriate for each */
+#define UCRED_INVALID { .pid = 0, .uid = UID_INVALID, .gid = GID_INVALID }
diff --git a/src/libnm-systemd-shared/src/basic/sort-util.h b/src/libnm-systemd-shared/src/basic/sort-util.h
index a8984fc164..28c06c40fc 100644
--- a/src/libnm-systemd-shared/src/basic/sort-util.h
+++ b/src/libnm-systemd-shared/src/basic/sort-util.h
@@ -5,14 +5,20 @@
#include "macro.h"
+/* This is the same as glibc's internal __compar_d_fn_t type. glibc exports a public comparison_fn_t, for the
+ * external type __compar_fn_t, but doesn't do anything similar for __compar_d_fn_t. Let's hence do that
+ * ourselves, picking a name that is obvious, but likely enough to not clash with glibc's choice of naming if
+ * they should ever add one. */
+typedef int (*comparison_userdata_fn_t)(const void *, const void *, void *);
+
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
- __compar_d_fn_t compar, void *arg);
+ comparison_userdata_fn_t compar, void *arg);
#define typesafe_bsearch_r(k, b, n, func, userdata) \
({ \
const typeof(b[0]) *_k = k; \
int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \
- xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_d_fn_t) _func_, userdata); \
+ xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (comparison_userdata_fn_t) _func_, userdata); \
})
/**
@@ -20,7 +26,7 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
* that only if nmemb > 0.
*/
static inline void* bsearch_safe(const void *key, const void *base,
- size_t nmemb, size_t size, __compar_fn_t compar) {
+ size_t nmemb, size_t size, comparison_fn_t compar) {
if (nmemb <= 0)
return NULL;
@@ -32,14 +38,14 @@ static inline void* bsearch_safe(const void *key, const void *base,
({ \
const typeof(b[0]) *_k = k; \
int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \
- bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_fn_t) _func_); \
+ bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (comparison_fn_t) _func_); \
})
/**
* Normal qsort requires base to be nonnull. Here were require
* that only if nmemb > 0.
*/
-static inline void _qsort_safe(void *base, size_t nmemb, size_t size, __compar_fn_t compar) {
+static inline void _qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) {
if (nmemb <= 1)
return;
@@ -52,11 +58,11 @@ static inline void _qsort_safe(void *base, size_t nmemb, size_t size, __compar_f
#define typesafe_qsort(p, n, func) \
({ \
int (*_func_)(const typeof(p[0])*, const typeof(p[0])*) = func; \
- _qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \
+ _qsort_safe((p), (n), sizeof((p)[0]), (comparison_fn_t) _func_); \
})
#if 0 /* NM_IGNORED */
-static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_d_fn_t compar, void *userdata) {
+static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, comparison_userdata_fn_t compar, void *userdata) {
if (nmemb <= 1)
return;
@@ -67,7 +73,7 @@ static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_
#define typesafe_qsort_r(p, n, func, userdata) \
({ \
int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
- qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \
+ qsort_r_safe((p), (n), sizeof((p)[0]), (comparison_userdata_fn_t) _func_, userdata); \
})
#endif /* NM_IGNORED */
diff --git a/src/libnm-systemd-shared/src/basic/sparse-endian.h b/src/libnm-systemd-shared/src/basic/sparse-endian.h
index 9583dda9e5..c795d3da8f 100644
--- a/src/libnm-systemd-shared/src/basic/sparse-endian.h
+++ b/src/libnm-systemd-shared/src/basic/sparse-endian.h
@@ -55,9 +55,9 @@ typedef uint64_t __sd_bitwise be64_t;
#undef le64toh
#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define bswap_16_on_le(x) __bswap_16(x)
-#define bswap_32_on_le(x) __bswap_32(x)
-#define bswap_64_on_le(x) __bswap_64(x)
+#define bswap_16_on_le(x) bswap_16(x)
+#define bswap_32_on_le(x) bswap_32(x)
+#define bswap_64_on_le(x) bswap_64(x)
#define bswap_16_on_be(x) (x)
#define bswap_32_on_be(x) (x)
#define bswap_64_on_be(x) (x)
@@ -65,9 +65,9 @@ typedef uint64_t __sd_bitwise be64_t;
#define bswap_16_on_le(x) (x)
#define bswap_32_on_le(x) (x)
#define bswap_64_on_le(x) (x)
-#define bswap_16_on_be(x) __bswap_16(x)
-#define bswap_32_on_be(x) __bswap_32(x)
-#define bswap_64_on_be(x) __bswap_64(x)
+#define bswap_16_on_be(x) bswap_16(x)
+#define bswap_32_on_be(x) bswap_32(x)
+#define bswap_64_on_be(x) bswap_64(x)
#endif
static inline le16_t htole16(uint16_t value) { return (le16_t __sd_force) bswap_16_on_be(value); }
diff --git a/src/libnm-systemd-shared/src/basic/stat-util.c b/src/libnm-systemd-shared/src/basic/stat-util.c
index 133828bc42..8126ce086a 100644
--- a/src/libnm-systemd-shared/src/basic/stat-util.c
+++ b/src/libnm-systemd-shared/src/basic/stat-util.c
@@ -15,10 +15,13 @@
#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
+#include "filesystems.h"
+#include "fs-util.h"
#include "macro.h"
#include "missing_fs.h"
#include "missing_magic.h"
#include "missing_syscall.h"
+#include "nulstr-util.h"
#include "parse-util.h"
#include "stat-util.h"
#include "string-util.h"
@@ -75,27 +78,41 @@ int is_device_node(const char *path) {
int dir_is_empty_at(int dir_fd, const char *path) {
_cleanup_close_ int fd = -1;
- _cleanup_closedir_ DIR *d = NULL;
+ /* Allocate space for at least 3 full dirents, since every dir has at least two entries ("." +
+ * ".."), and only once we have seen if there's a third we know whether the dir is empty or not. */
+ DEFINE_DIRENT_BUFFER(buffer, 3);
struct dirent *de;
+ ssize_t n;
if (path) {
+ assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+
fd = openat(dir_fd, path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
if (fd < 0)
return -errno;
+ } else if (dir_fd == AT_FDCWD) {
+ fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
} else {
- /* Note that DUPing is not enough, as the internal pointer
- * would still be shared and moved by FOREACH_DIRENT. */
- fd = fd_reopen(dir_fd, O_CLOEXEC);
+ /* Note that DUPing is not enough, as the internal pointer would still be shared and moved
+ * getedents64(). */
+ assert(dir_fd >= 0);
+
+ fd = fd_reopen(dir_fd, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
if (fd < 0)
return fd;
}
- d = take_fdopendir(&fd);
- if (!d)
+ n = getdents64(fd, &buffer, sizeof(buffer));
+ if (n < 0)
return -errno;
- FOREACH_DIRENT(de, d, return -errno)
- return 0;
+ msan_unpoison(&buffer, n);
+
+ FOREACH_DIRENT_IN_BUFFER(de, &buffer.de, n)
+ if (!dot_or_dot_dot(de->d_name))
+ return 0;
return 1;
}
@@ -178,7 +195,6 @@ int files_same(const char *filea, const char *fileb, int flags) {
a.st_ino == b.st_ino;
}
-#if 0 /* NM_IGNORED */
bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
assert(s);
assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
@@ -186,6 +202,7 @@ bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
return F_TYPE_EQUAL(s->f_type, magic_value);
}
+#if 0 /* NM_IGNORED */
int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
struct statfs s;
@@ -194,6 +211,7 @@ int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
return is_fs_type(&s, magic_value);
}
+#endif /* NM_IGNORE */
int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
struct statfs s;
@@ -204,20 +222,13 @@ int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
return is_fs_type(&s, magic_value);
}
+#if 0 /* NM_IGNORE */
bool is_temporary_fs(const struct statfs *s) {
- return is_fs_type(s, TMPFS_MAGIC) ||
- is_fs_type(s, RAMFS_MAGIC);
+ return fs_in_group(s, FILESYSTEM_SET_TEMPORARY);
}
bool is_network_fs(const struct statfs *s) {
- return is_fs_type(s, CIFS_MAGIC_NUMBER) ||
- is_fs_type(s, CODA_SUPER_MAGIC) ||
- is_fs_type(s, NCP_SUPER_MAGIC) ||
- is_fs_type(s, NFS_SUPER_MAGIC) ||
- is_fs_type(s, SMB_SUPER_MAGIC) ||
- is_fs_type(s, V9FS_MAGIC) ||
- is_fs_type(s, AFS_SUPER_MAGIC) ||
- is_fs_type(s, OCFS2_SUPER_MAGIC);
+ return fs_in_group(s, FILESYSTEM_SET_NETWORK);
}
int fd_is_temporary_fs(int fd) {
@@ -395,6 +406,7 @@ int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret
return 0;
}
+#endif /* NM_IGNORED */
int proc_mounted(void) {
int r;
@@ -408,6 +420,7 @@ int proc_mounted(void) {
return r;
}
+#if 0 /* NM_IGNORED */
bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
/* Returns if the specified stat structures reference the same, unmodified inode. This check tries to
diff --git a/src/libnm-systemd-shared/src/basic/string-util.h b/src/libnm-systemd-shared/src/basic/string-util.h
index 775d694c67..a1d88fbb95 100644
--- a/src/libnm-systemd-shared/src/basic/string-util.h
+++ b/src/libnm-systemd-shared/src/basic/string-util.h
@@ -60,6 +60,10 @@ static inline const char *empty_to_null(const char *p) {
return isempty(p) ? NULL : p;
}
+static inline const char *empty_to_na(const char *p) {
+ return isempty(p) ? "n/a" : p;
+}
+
static inline const char *empty_to_dash(const char *str) {
return isempty(str) ? "-" : str;
}
diff --git a/src/libnm-systemd-shared/src/basic/strv.c b/src/libnm-systemd-shared/src/basic/strv.c
index 1d84092392..3e0faf9590 100644
--- a/src/libnm-systemd-shared/src/basic/strv.c
+++ b/src/libnm-systemd-shared/src/basic/strv.c
@@ -18,7 +18,7 @@
#include "string-util.h"
#include "strv.h"
-char *strv_find(char * const *l, const char *name) {
+char* strv_find(char * const *l, const char *name) {
char * const *i;
assert(name);
@@ -30,7 +30,7 @@ char *strv_find(char * const *l, const char *name) {
return NULL;
}
-char *strv_find_case(char * const *l, const char *name) {
+char* strv_find_case(char * const *l, const char *name) {
char * const *i;
assert(name);
@@ -42,7 +42,7 @@ char *strv_find_case(char * const *l, const char *name) {
return NULL;
}
-char *strv_find_prefix(char * const *l, const char *name) {
+char* strv_find_prefix(char * const *l, const char *name) {
char * const *i;
assert(name);
@@ -54,7 +54,7 @@ char *strv_find_prefix(char * const *l, const char *name) {
return NULL;
}
-char *strv_find_startswith(char * const *l, const char *name) {
+char* strv_find_startswith(char * const *l, const char *name) {
char * const *i, *e;
assert(name);
@@ -71,19 +71,17 @@ char *strv_find_startswith(char * const *l, const char *name) {
return NULL;
}
-char **strv_free(char **l) {
- char **k;
-
+char** strv_free(char **l) {
if (!l)
return NULL;
- for (k = l; *k; k++)
+ for (char **k = l; *k; k++)
free(*k);
return mfree(l);
}
-char **strv_free_erase(char **l) {
+char** strv_free_erase(char **l) {
char **i;
STRV_FOREACH(i, l)
@@ -92,7 +90,7 @@ char **strv_free_erase(char **l) {
return mfree(l);
}
-char **strv_copy(char * const *l) {
+char** strv_copy(char * const *l) {
char **r, **k;
k = r = new(char*, strv_length(l) + 1);
@@ -124,7 +122,7 @@ size_t strv_length(char * const *l) {
return n;
}
-char **strv_new_ap(const char *x, va_list ap) {
+char** strv_new_ap(const char *x, va_list ap) {
_cleanup_strv_free_ char **a = NULL;
size_t n = 0, i = 0;
va_list aq;
@@ -163,7 +161,7 @@ char **strv_new_ap(const char *x, va_list ap) {
return TAKE_PTR(a);
}
-char **strv_new_internal(const char *x, ...) {
+char** strv_new_internal(const char *x, ...) {
char **r;
va_list ap;
@@ -176,7 +174,7 @@ char **strv_new_internal(const char *x, ...) {
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
char * const *s, **t;
- size_t p, q, i = 0, j;
+ size_t p, q, i = 0;
assert(a);
@@ -197,7 +195,6 @@ int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
*a = t;
STRV_FOREACH(s, b) {
-
if (filter_duplicates && strv_contains(t, *s))
continue;
@@ -214,7 +211,7 @@ int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
return (int) i;
rollback:
- for (j = 0; j < i; j++)
+ for (size_t j = 0; j < i; j++)
free(t[p + j]);
t[p] = NULL;
@@ -289,7 +286,6 @@ int strv_split_full(char ***t, const char *s, const char *separators, ExtractFla
return -ENOMEM;
l[n++] = TAKE_PTR(word);
-
l[n] = NULL;
}
@@ -376,7 +372,7 @@ int strv_split_colon_pairs(char ***t, const char *s) {
}
#endif /* NM_IGNORED */
-char *strv_join_full(char * const *l, const char *separator, const char *prefix, bool unescape_separators) {
+char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool unescape_separators) {
char * const *s;
char *r, *e;
size_t n, k, m;
@@ -483,7 +479,7 @@ int strv_push_pair(char ***l, char *a, char *b) {
int strv_insert(char ***l, size_t position, char *value) {
char **c;
- size_t n, m, i;
+ size_t n, m;
if (!value)
return 0;
@@ -500,18 +496,14 @@ int strv_insert(char ***l, size_t position, char *value) {
if (!c)
return -ENOMEM;
- for (i = 0; i < position; i++)
+ for (size_t i = 0; i < position; i++)
c[i] = (*l)[i];
c[position] = value;
- for (i = position; i < n; i++)
+ for (size_t i = position; i < n; i++)
c[i+1] = (*l)[i];
-
c[n+1] = NULL;
- free(*l);
- *l = c;
-
- return 0;
+ return free_and_replace(*l, c);
}
int strv_consume(char ***l, char *value) {
@@ -608,7 +600,7 @@ int strv_extend_front(char ***l, const char *value) {
return 0;
}
-char **strv_uniq(char **l) {
+char** strv_uniq(char **l) {
char **i;
/* Drops duplicate entries. The first identical string will be
@@ -630,7 +622,7 @@ bool strv_is_uniq(char * const *l) {
return true;
}
-char **strv_remove(char **l, const char *s) {
+char** strv_remove(char **l, const char *s) {
char **f, **t;
if (!l)
@@ -651,7 +643,7 @@ char **strv_remove(char **l, const char *s) {
return l;
}
-char **strv_parse_nulstr(const char *s, size_t l) {
+char** strv_parse_nulstr(const char *s, size_t l) {
/* l is the length of the input data, which will be split at NULs into
* elements of the resulting strv. Hence, the number of items in the resulting strv
* will be equal to one plus the number of NUL bytes in the l bytes starting at s,
@@ -663,7 +655,6 @@ char **strv_parse_nulstr(const char *s, size_t l) {
* empty strings in s.
*/
- const char *p;
size_t c = 0, i = 0;
char **v;
@@ -672,7 +663,7 @@ char **strv_parse_nulstr(const char *s, size_t l) {
if (l <= 0)
return new0(char*, 1);
- for (p = s; p < s + l; p++)
+ for (const char *p = s; p < s + l; p++)
if (*p == 0)
c++;
@@ -683,8 +674,7 @@ char **strv_parse_nulstr(const char *s, size_t l) {
if (!v)
return NULL;
- p = s;
- while (p < s + l) {
+ for (const char *p = s; p < s + l; ) {
const char *e;
e = memchr(p, 0, s + l - p);
@@ -709,7 +699,7 @@ char **strv_parse_nulstr(const char *s, size_t l) {
}
#if 0 /* NM_IGNORED */
-char **strv_split_nulstr(const char *s) {
+char** strv_split_nulstr(const char *s) {
const char *i;
char **r = NULL;
@@ -786,7 +776,7 @@ static int str_compare(char * const *a, char * const *b) {
return strcmp(*a, *b);
}
-char **strv_sort(char **l) {
+char** strv_sort(char **l) {
typesafe_qsort(l, strv_length(l), str_compare);
return l;
}
@@ -836,21 +826,21 @@ int strv_extendf(char ***l, const char *format, ...) {
return strv_consume(l, x);
}
-char **strv_reverse(char **l) {
- size_t n, i;
+char** strv_reverse(char **l) {
+ size_t n;
n = strv_length(l);
if (n <= 1)
return l;
- for (i = 0; i < n / 2; i++)
+ for (size_t i = 0; i < n / 2; i++)
SWAP_TWO(l[i], l[n-1-i]);
return l;
}
#if 0 /* NM_IGNORED */
-char **strv_shell_escape(char **l, const char *bad) {
+char** strv_shell_escape(char **l, const char *bad) {
char **s;
/* Escapes every character in every string in l that is in bad,
@@ -882,19 +872,7 @@ bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *
return false;
}
-char ***strv_free_free(char ***l) {
- char ***i;
-
- if (!l)
- return NULL;
-
- for (i = l; *i; i++)
- strv_free(*i);
-
- return mfree(l);
-}
-
-char **strv_skip(char **l, size_t n) {
+char** strv_skip(char **l, size_t n) {
while (n > 0) {
if (strv_isempty(l))
@@ -907,7 +885,7 @@ char **strv_skip(char **l, size_t n) {
}
int strv_extend_n(char ***l, const char *value, size_t n) {
- size_t i, j, k;
+ size_t i, k;
char **nl;
assert(l);
@@ -934,15 +912,15 @@ int strv_extend_n(char ***l, const char *value, size_t n) {
if (!nl[i])
goto rollback;
}
-
nl[i] = NULL;
+
return 0;
rollback:
- for (j = k; j < i; j++)
+ for (size_t j = k; j < i; j++)
free(nl[j]);
-
nl[k] = NULL;
+
return -ENOMEM;
}
diff --git a/src/libnm-systemd-shared/src/basic/strv.h b/src/libnm-systemd-shared/src/basic/strv.h
index a56ef94139..092d40c84b 100644
--- a/src/libnm-systemd-shared/src/basic/strv.h
+++ b/src/libnm-systemd-shared/src/basic/strv.h
@@ -13,23 +13,23 @@
#include "macro.h"
#include "string-util.h"
-char *strv_find(char * const *l, const char *name) _pure_;
-char *strv_find_case(char * const *l, const char *name) _pure_;
-char *strv_find_prefix(char * const *l, const char *name) _pure_;
-char *strv_find_startswith(char * const *l, const char *name) _pure_;
+char* strv_find(char * const *l, const char *name) _pure_;
+char* strv_find_case(char * const *l, const char *name) _pure_;
+char* strv_find_prefix(char * const *l, const char *name) _pure_;
+char* strv_find_startswith(char * const *l, const char *name) _pure_;
#define strv_contains(l, s) (!!strv_find((l), (s)))
#define strv_contains_case(l, s) (!!strv_find_case((l), (s)))
-char **strv_free(char **l);
+char** strv_free(char **l);
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
#define _cleanup_strv_free_ _cleanup_(strv_freep)
-char **strv_free_erase(char **l);
+char** strv_free_erase(char **l);
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase);
#define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep)
-char **strv_copy(char * const *l);
+char** strv_copy(char * const *l);
size_t strv_length(char * const *l) _pure_;
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates);
@@ -50,8 +50,8 @@ int strv_consume(char ***l, char *value);
int strv_consume_pair(char ***l, char *a, char *b);
int strv_consume_prepend(char ***l, char *value);
-char **strv_remove(char **l, const char *s);
-char **strv_uniq(char **l);
+char** strv_remove(char **l, const char *s);
+char** strv_uniq(char **l);
bool strv_is_uniq(char * const *l);
int strv_compare(char * const *a, char * const *b);
@@ -59,8 +59,8 @@ static inline bool strv_equal(char * const *a, char * const *b) {
return strv_compare(a, b) == 0;
}
-char **strv_new_internal(const char *x, ...) _sentinel_;
-char **strv_new_ap(const char *x, va_list ap);
+char** strv_new_internal(const char *x, ...) _sentinel_;
+char** strv_new_ap(const char *x, va_list ap);
#define strv_new(...) strv_new_internal(__VA_ARGS__, NULL)
#define STRV_IGNORE ((const char *) POINTER_MAX)
@@ -74,7 +74,7 @@ static inline bool strv_isempty(char * const *l) {
}
int strv_split_full(char ***t, const char *s, const char *separators, ExtractFlags flags);
-static inline char **strv_split(const char *s, const char *separators) {
+static inline char** strv_split(const char *s, const char *separators) {
char **ret;
if (strv_split_full(&ret, s, separators, 0) < 0)
@@ -87,7 +87,7 @@ int strv_split_and_extend_full(char ***t, const char *s, const char *separators,
#define strv_split_and_extend(t, s, sep, dup) strv_split_and_extend_full(t, s, sep, dup, 0)
int strv_split_newlines_full(char ***ret, const char *s, ExtractFlags flags);
-static inline char **strv_split_newlines(const char *s) {
+static inline char** strv_split_newlines(const char *s) {
char **ret;
if (strv_split_newlines_full(&ret, s, 0) < 0)
@@ -101,13 +101,13 @@ static inline char **strv_split_newlines(const char *s) {
* string in the vector is an empty string. */
int strv_split_colon_pairs(char ***t, const char *s);
-char *strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separtor);
+char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separtor);
static inline char *strv_join(char * const *l, const char *separator) {
return strv_join_full(l, separator, NULL, false);
}
-char **strv_parse_nulstr(const char *s, size_t l);
-char **strv_split_nulstr(const char *s);
+char** strv_parse_nulstr(const char *s, size_t l);
+char** strv_split_nulstr(const char *s);
int strv_make_nulstr(char * const *l, char **p, size_t *n);
static inline int strv_from_nulstr(char ***a, const char *nulstr) {
@@ -136,7 +136,7 @@ bool strv_overlap(char * const *a, char * const *b) _pure_;
#define STRV_FOREACH_PAIR(x, y, l) \
for ((x) = (l), (y) = (x) ? (x+1) : NULL; (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
-char **strv_sort(char **l);
+char** strv_sort(char **l);
void strv_print(char * const *l);
#define strv_from_stdarg_alloca(first) \
@@ -206,13 +206,16 @@ void strv_print(char * const *l);
_found; \
})
-#define FOREACH_STRING(x, y, ...) \
- for (char **_l = STRV_MAKE(({ x = y; }), ##__VA_ARGS__); \
+#define _FOREACH_STRING(uniq, x, y, ...) \
+ for (char **UNIQ_T(l, uniq) = STRV_MAKE(({ x = y; }), ##__VA_ARGS__); \
x; \
- x = *(++_l))
+ x = *(++UNIQ_T(l, uniq)))
-char **strv_reverse(char **l);
-char **strv_shell_escape(char **l, const char *bad);
+#define FOREACH_STRING(x, y, ...) \
+ _FOREACH_STRING(UNIQ, x, y, ##__VA_ARGS__)
+
+char** strv_reverse(char **l);
+char** strv_shell_escape(char **l, const char *bad);
bool strv_fnmatch_full(char* const* patterns, const char *s, int flags, size_t *matched_pos);
static inline bool strv_fnmatch(char* const* patterns, const char *s) {
@@ -225,10 +228,7 @@ static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, i
strv_fnmatch_full(patterns, s, flags, NULL);
}
-char ***strv_free_free(char ***l);
-DEFINE_TRIVIAL_CLEANUP_FUNC(char***, strv_free_free);
-
-char **strv_skip(char **l, size_t n);
+char** strv_skip(char **l, size_t n);
int strv_extend_n(char ***l, const char *value, size_t n);
diff --git a/src/libnm-systemd-shared/src/basic/strxcpyx.c b/src/libnm-systemd-shared/src/basic/strxcpyx.c
index 39aebb8897..2788dd821f 100644
--- a/src/libnm-systemd-shared/src/basic/strxcpyx.c
+++ b/src/libnm-systemd-shared/src/basic/strxcpyx.c
@@ -17,57 +17,73 @@
#include <stdio.h>
#include <string.h>
+#include "string-util.h"
#include "strxcpyx.h"
-size_t strnpcpy(char **dest, size_t size, const char *src, size_t len) {
+size_t strnpcpy_full(char **dest, size_t size, const char *src, size_t len, bool *ret_truncated) {
+ bool truncated = false;
+
assert(dest);
assert(src);
- if (size == 0)
+ if (size == 0) {
+ if (ret_truncated)
+ *ret_truncated = len > 0;
return 0;
+ }
if (len >= size) {
if (size > 1)
*dest = mempcpy(*dest, src, size-1);
size = 0;
+ truncated = true;
} else if (len > 0) {
*dest = mempcpy(*dest, src, len);
size -= len;
}
+ if (ret_truncated)
+ *ret_truncated = truncated;
+
*dest[0] = '\0';
return size;
}
-size_t strpcpy(char **dest, size_t size, const char *src) {
+size_t strpcpy_full(char **dest, size_t size, const char *src, bool *ret_truncated) {
assert(dest);
assert(src);
- return strnpcpy(dest, size, src, strlen(src));
+ return strnpcpy_full(dest, size, src, strlen(src), ret_truncated);
}
-size_t strpcpyf(char **dest, size_t size, const char *src, ...) {
+size_t strpcpyf_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) {
+ bool truncated = false;
va_list va;
int i;
assert(dest);
assert(src);
- if (size == 0)
- return 0;
-
va_start(va, src);
i = vsnprintf(*dest, size, src, va);
- if (i < (int)size) {
+ va_end(va);
+
+ if (i < (int) size) {
*dest += i;
size -= i;
- } else
+ } else {
size = 0;
- va_end(va);
+ truncated = i > 0;
+ }
+
+ if (ret_truncated)
+ *ret_truncated = truncated;
+
return size;
}
-size_t strpcpyl(char **dest, size_t size, const char *src, ...) {
+size_t strpcpyl_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) {
+ bool truncated = false;
va_list va;
assert(dest);
@@ -75,31 +91,38 @@ size_t strpcpyl(char **dest, size_t size, const char *src, ...) {
va_start(va, src);
do {
- size = strpcpy(dest, size, src);
+ bool t;
+
+ size = strpcpy_full(dest, size, src, &t);
+ truncated = truncated || t;
src = va_arg(va, char *);
} while (src);
va_end(va);
+
+ if (ret_truncated)
+ *ret_truncated = truncated;
return size;
}
-size_t strnscpy(char *dest, size_t size, const char *src, size_t len) {
+size_t strnscpy_full(char *dest, size_t size, const char *src, size_t len, bool *ret_truncated) {
char *s;
assert(dest);
assert(src);
s = dest;
- return strnpcpy(&s, size, src, len);
+ return strnpcpy_full(&s, size, src, len, ret_truncated);
}
-size_t strscpy(char *dest, size_t size, const char *src) {
+size_t strscpy_full(char *dest, size_t size, const char *src, bool *ret_truncated) {
assert(dest);
assert(src);
- return strnscpy(dest, size, src, strlen(src));
+ return strnscpy_full(dest, size, src, strlen(src), ret_truncated);
}
-size_t strscpyl(char *dest, size_t size, const char *src, ...) {
+size_t strscpyl_full(char *dest, size_t size, bool *ret_truncated, const char *src, ...) {
+ bool truncated = false;
va_list va;
char *s;
@@ -109,10 +132,16 @@ size_t strscpyl(char *dest, size_t size, const char *src, ...) {
va_start(va, src);
s = dest;
do {
- size = strpcpy(&s, size, src);
+ bool t;
+
+ size = strpcpy_full(&s, size, src, &t);
+ truncated = truncated || t;
src = va_arg(va, char *);
} while (src);
va_end(va);
+ if (ret_truncated)
+ *ret_truncated = truncated;
+
return size;
}
diff --git a/src/libnm-systemd-shared/src/basic/strxcpyx.h b/src/libnm-systemd-shared/src/basic/strxcpyx.h
index cdef492db1..4a648ed033 100644
--- a/src/libnm-systemd-shared/src/basic/strxcpyx.h
+++ b/src/libnm-systemd-shared/src/basic/strxcpyx.h
@@ -1,14 +1,33 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <stdbool.h>
#include <stddef.h>
#include "macro.h"
-size_t strnpcpy(char **dest, size_t size, const char *src, size_t len);
-size_t strpcpy(char **dest, size_t size, const char *src);
-size_t strpcpyf(char **dest, size_t size, const char *src, ...) _printf_(3, 4);
-size_t strpcpyl(char **dest, size_t size, const char *src, ...) _sentinel_;
-size_t strnscpy(char *dest, size_t size, const char *src, size_t len);
-size_t strscpy(char *dest, size_t size, const char *src);
-size_t strscpyl(char *dest, size_t size, const char *src, ...) _sentinel_;
+size_t strnpcpy_full(char **dest, size_t size, const char *src, size_t len, bool *ret_truncated);
+static inline size_t strnpcpy(char **dest, size_t size, const char *src, size_t len) {
+ return strnpcpy_full(dest, size, src, len, NULL);
+}
+size_t strpcpy_full(char **dest, size_t size, const char *src, bool *ret_truncated);
+static inline size_t strpcpy(char **dest, size_t size, const char *src) {
+ return strpcpy_full(dest, size, src, NULL);
+}
+size_t strpcpyf_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) _printf_(4, 5);
+#define strpcpyf(dest, size, src, ...) \
+ strpcpyf_full((dest), (size), NULL, (src), ##__VA_ARGS__)
+size_t strpcpyl_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) _sentinel_;
+#define strpcpyl(dest, size, src, ...) \
+ strpcpyl_full((dest), (size), NULL, (src), ##__VA_ARGS__)
+size_t strnscpy_full(char *dest, size_t size, const char *src, size_t len, bool *ret_truncated);
+static inline size_t strnscpy(char *dest, size_t size, const char *src, size_t len) {
+ return strnscpy_full(dest, size, src, len, NULL);
+}
+size_t strscpy_full(char *dest, size_t size, const char *src, bool *ret_truncated);
+static inline size_t strscpy(char *dest, size_t size, const char *src) {
+ return strscpy_full(dest, size, src, NULL);
+}
+size_t strscpyl_full(char *dest, size_t size, bool *ret_truncated, const char *src, ...) _sentinel_;
+#define strscpyl(dest, size, src, ...) \
+ strscpyl_full(dest, size, NULL, src, ##__VA_ARGS__)
diff --git a/src/libnm-systemd-shared/src/basic/time-util.c b/src/libnm-systemd-shared/src/basic/time-util.c
index 21e7b24a80..d7ea2b38d0 100644
--- a/src/libnm-systemd-shared/src/basic/time-util.c
+++ b/src/libnm-systemd-shared/src/basic/time-util.c
@@ -271,7 +271,6 @@ struct timespec *timespec_store_nsec(struct timespec *ts, nsec_t n) {
return ts;
}
-#if 0 /* NM_IGNORED */
usec_t timeval_load(const struct timeval *tv) {
assert(tv);
@@ -286,6 +285,7 @@ usec_t timeval_load(const struct timeval *tv) {
(usec_t) tv->tv_usec;
}
+#if 0 /* NM_IGNORED */
struct timeval *timeval_store(struct timeval *tv, usec_t u) {
assert(tv);
@@ -676,7 +676,7 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
goto finish;
} else if ((k = endswith(t, " ago"))) {
- t = strndupa(t, k - t);
+ t = strndupa_safe(t, k - t);
r = parse_sec(t, &minus);
if (r < 0)
@@ -685,7 +685,7 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
goto finish;
} else if ((k = endswith(t, " left"))) {
- t = strndupa(t, k - t);
+ t = strndupa_safe(t, k - t);
r = parse_sec(t, &plus);
if (r < 0)
@@ -697,7 +697,7 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
/* See if the timestamp is suffixed with UTC */
utc = endswith_no_case(t, " UTC");
if (utc)
- t = strndupa(t, utc - t);
+ t = strndupa_safe(t, utc - t);
else {
const char *e = NULL;
int j;
@@ -728,7 +728,7 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
if (IN_SET(j, 0, 1)) {
/* Found one of the two timezones specified. */
- t = strndupa(t, e - t - 1);
+ t = strndupa_safe(t, e - t - 1);
dst = j;
tzn = tzname[j];
}
@@ -929,7 +929,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
/* Cut off the timezone if we don't need it. */
if (with_tz)
- t = strndupa(t, last_space - t);
+ t = strndupa_safe(t, last_space - t);
shared->return_value = parse_timestamp_impl(t, &shared->usec, with_tz);
diff --git a/src/libnm-systemd-shared/src/basic/tmpfile-util.c b/src/libnm-systemd-shared/src/basic/tmpfile-util.c
index 8a6404d38e..dc5a49e224 100644
--- a/src/libnm-systemd-shared/src/basic/tmpfile-util.c
+++ b/src/libnm-systemd-shared/src/basic/tmpfile-util.c
@@ -67,16 +67,9 @@ int fopen_temporary(const char *path, FILE **ret_f, char **ret_temp_path) {
/* This is much like mkostemp() but is subject to umask(). */
int mkostemp_safe(char *pattern) {
- int fd = -1; /* avoid false maybe-uninitialized warning */
-
assert(pattern);
-
- RUN_WITH_UMASK(0077)
- fd = mkostemp(pattern, O_CLOEXEC);
- if (fd < 0)
- return -errno;
-
- return fd;
+ BLOCK_WITH_UMASK(0077);
+ return RET_NERRNO(mkostemp(pattern, O_CLOEXEC));
}
#if 0 /* NM_IGNORED */
@@ -288,8 +281,6 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
}
int link_tmpfile(int fd, const char *path, const char *target) {
- int r;
-
assert(fd >= 0);
assert(target);
@@ -300,16 +291,10 @@ int link_tmpfile(int fd, const char *path, const char *target) {
* Note that in both cases we will not replace existing files. This is because linkat() does not support this
* operation currently (renameat2() does), and there is no nice way to emulate this. */
- if (path) {
- r = rename_noreplace(AT_FDCWD, path, AT_FDCWD, target);
- if (r < 0)
- return r;
- } else {
- if (linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
- return -errno;
- }
+ if (path)
+ return rename_noreplace(AT_FDCWD, path, AT_FDCWD, target);
- return 0;
+ return RET_NERRNO(linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), AT_FDCWD, target, AT_SYMLINK_FOLLOW));
}
int mkdtemp_malloc(const char *template, char **ret) {
diff --git a/src/libnm-systemd-shared/src/basic/umask-util.h b/src/libnm-systemd-shared/src/basic/umask-util.h
index bd7c2bdb8c..90d18f70ba 100644
--- a/src/libnm-systemd-shared/src/basic/umask-util.h
+++ b/src/libnm-systemd-shared/src/basic/umask-util.h
@@ -24,3 +24,6 @@ assert_cc((S_IFMT & 0777) == 0);
for (_cleanup_umask_ mode_t _saved_umask_ = umask(mask) | S_IFMT; \
FLAGS_SET(_saved_umask_, S_IFMT); \
_saved_umask_ &= 0777)
+
+#define BLOCK_WITH_UMASK(mask) \
+ _unused_ _cleanup_umask_ mode_t _saved_umask_ = umask(mask);
diff --git a/src/libnm-systemd-shared/src/basic/user-util.h b/src/libnm-systemd-shared/src/basic/user-util.h
index fd00b47b76..bc76de6b41 100644
--- a/src/libnm-systemd-shared/src/basic/user-util.h
+++ b/src/libnm-systemd-shared/src/basic/user-util.h
@@ -112,6 +112,12 @@ bool is_nologin_shell(const char *shell);
int is_this_me(const char *username);
+const char *get_home_root(void);
+
+static inline bool hashed_password_is_locked_or_invalid(const char *password) {
+ return password && password[0] != '$';
+}
+
/* A locked *and* invalid password for "struct spwd"'s .sp_pwdp and "struct passwd"'s .pw_passwd field */
#define PASSWORD_LOCKED_AND_INVALID "!*"
diff --git a/src/libnm-systemd-shared/src/basic/utf8.c b/src/libnm-systemd-shared/src/basic/utf8.c
index dfa010e847..c8e39fe45e 100644
--- a/src/libnm-systemd-shared/src/basic/utf8.c
+++ b/src/libnm-systemd-shared/src/basic/utf8.c
@@ -126,11 +126,9 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
}
bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) {
- const char *p;
-
assert(str);
- for (p = str; length > 0;) {
+ for (const char *p = str; length > 0;) {
int encoded_len, r;
char32_t val;
@@ -293,14 +291,12 @@ char *utf8_escape_non_printable_full(const char *str, size_t console_width, bool
#endif /* NM_IGNORED */
char *ascii_is_valid(const char *str) {
- const char *p;
-
/* Check whether the string consists of valid ASCII bytes,
* i.e values between 0 and 127, inclusive. */
assert(str);
- for (p = str; *p; p++)
+ for (const char *p = str; *p; p++)
if ((unsigned char) *p >= 128)
return NULL;
@@ -322,6 +318,37 @@ char *ascii_is_valid_n(const char *str, size_t len) {
}
#endif /* NM_IGNORED */
+int utf8_to_ascii(const char *str, char replacement_char, char **ret) {
+ /* Convert to a string that has only ASCII chars, replacing anything that is not ASCII
+ * by replacement_char. */
+
+ _cleanup_free_ char *ans = new(char, strlen(str) + 1);
+ if (!ans)
+ return -ENOMEM;
+
+ char *q = ans;
+
+ for (const char *p = str; *p; q++) {
+ int l;
+
+ l = utf8_encoded_valid_unichar(p, SIZE_MAX);
+ if (l < 0) /* Non-UTF-8, let's not even try to propagate the garbage */
+ return l;
+
+ if (l == 1)
+ *q = *p;
+ else
+ /* non-ASCII, we need to replace it */
+ *q = replacement_char;
+
+ p += l;
+ }
+ *q = '\0';
+
+ *ret = TAKE_PTR(ans);
+ return 0;
+}
+
/**
* utf8_encode_unichar() - Encode single UCS-4 character as UTF-8
* @out_utf8: output buffer of at least 4 bytes or NULL
diff --git a/src/libnm-systemd-shared/src/basic/utf8.h b/src/libnm-systemd-shared/src/basic/utf8.h
index b0e969f655..4a06dd62c5 100644
--- a/src/libnm-systemd-shared/src/basic/utf8.h
+++ b/src/libnm-systemd-shared/src/basic/utf8.h
@@ -21,6 +21,8 @@ static inline char *utf8_is_valid(const char *s) {
char *ascii_is_valid(const char *s) _pure_;
char *ascii_is_valid_n(const char *str, size_t len);
+int utf8_to_ascii(const char *str, char replacement_char, char **ret);
+
bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) _pure_;
#define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true)
diff --git a/src/libnm-systemd-shared/src/basic/util.c b/src/libnm-systemd-shared/src/basic/util.c
index ed3284668d..3425d0f0d6 100644
--- a/src/libnm-systemd-shared/src/basic/util.c
+++ b/src/libnm-systemd-shared/src/basic/util.c
@@ -8,7 +8,6 @@
#include "alloc-util.h"
#include "build.h"
-#include "dirent-util.h"
#include "env-file.h"
#include "env-util.h"
#include "fd-util.h"
@@ -118,71 +117,6 @@ void in_initrd_force(bool value) {
saved_in_initrd = value;
}
-int on_ac_power(void) {
- bool found_offline = false, found_online = false;
- _cleanup_closedir_ DIR *d = NULL;
- struct dirent *de;
-
- d = opendir("/sys/class/power_supply");
- if (!d)
- return errno == ENOENT ? true : -errno;
-
- FOREACH_DIRENT(de, d, return -errno) {
- _cleanup_close_ int fd = -1, device = -1;
- char contents[6];
- ssize_t n;
-
- device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (device < 0) {
- if (IN_SET(errno, ENOENT, ENOTDIR))
- continue;
-
- return -errno;
- }
-
- fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0) {
- if (errno == ENOENT)
- continue;
-
- return -errno;
- }
-
- n = read(fd, contents, sizeof(contents));
- if (n < 0)
- return -errno;
-
- if (n != 6 || memcmp(contents, "Mains\n", 6))
- continue;
-
- safe_close(fd);
- fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0) {
- if (errno == ENOENT)
- continue;
-
- return -errno;
- }
-
- n = read(fd, contents, sizeof(contents));
- if (n < 0)
- return -errno;
-
- if (n != 2 || contents[1] != '\n')
- return -EIO;
-
- if (contents[0] == '1') {
- found_online = true;
- break;
- } else if (contents[0] == '0')
- found_offline = true;
- else
- return -EIO;
- }
-
- return found_online || !found_offline;
-}
-
int container_get_leader(const char *machine, pid_t *pid) {
_cleanup_free_ char *s = NULL, *class = NULL;
const char *p;
diff --git a/src/libnm-systemd-shared/src/basic/util.h b/src/libnm-systemd-shared/src/basic/util.h
index b6c51c036e..94804f28e3 100644
--- a/src/libnm-systemd-shared/src/basic/util.h
+++ b/src/libnm-systemd-shared/src/basic/util.h
@@ -20,13 +20,20 @@ int prot_from_flags(int flags) _const_;
bool in_initrd(void);
void in_initrd_force(bool value);
-int on_ac_power(void);
+/* Note: log2(0) == log2(1) == 0 here and below. */
-static inline unsigned u64log2(uint64_t n) {
+#define CONST_LOG2ULL(x) ((x) > 1 ? (unsigned) __builtin_clzll(x) ^ 63U : 0)
+#define NONCONST_LOG2ULL(x) ({ \
+ unsigned long long _x = (x); \
+ _x > 1 ? (unsigned) __builtin_clzll(_x) ^ 63U : 0; \
+ })
+#define LOG2ULL(x) __builtin_choose_expr(__builtin_constant_p(x), CONST_LOG2ULL(x), NONCONST_LOG2ULL(x))
+
+static inline unsigned log2u64(uint64_t x) {
#if __SIZEOF_LONG_LONG__ == 8
- return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0;
+ return LOG2ULL(x);
#else
-#error "Wut?"
+# error "Wut?"
#endif
}
@@ -34,26 +41,27 @@ static inline unsigned u32ctz(uint32_t n) {
#if __SIZEOF_INT__ == 4
return n != 0 ? __builtin_ctz(n) : 32;
#else
-#error "Wut?"
+# error "Wut?"
#endif
}
-static inline unsigned log2i(int x) {
- assert(x > 0);
+#define CONST_LOG2U(x) ((x) > 1 ? __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1 : 0)
+#define NONCONST_LOG2U(x) ({ \
+ unsigned _x = (x); \
+ _x > 1 ? __SIZEOF_INT__ * 8 - __builtin_clz(_x) - 1 : 0; \
+ })
+#define LOG2U(x) __builtin_choose_expr(__builtin_constant_p(x), CONST_LOG2U(x), NONCONST_LOG2U(x))
- return __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1;
+static inline unsigned log2i(int x) {
+ return LOG2U(x);
}
static inline unsigned log2u(unsigned x) {
- assert(x > 0);
-
- return sizeof(unsigned) * 8 - __builtin_clz(x) - 1;
+ return LOG2U(x);
}
static inline unsigned log2u_round_up(unsigned x) {
- assert(x > 0);
-
- if (x == 1)
+ if (x <= 1)
return 0;
return log2u(x - 1) + 1;
diff --git a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
index 20d8dabf29..d597c743bb 100644
--- a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
+++ b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h
@@ -5,13 +5,15 @@
#include <assert.h>
#endif
-#include "type.h"
+#include <limits.h>
+#include "types-fundamental.h"
#define _align_(x) __attribute__((__aligned__(x)))
#define _const_ __attribute__((__const__))
#define _pure_ __attribute__((__pure__))
#define _section_(x) __attribute__((__section__(x)))
#define _packed_ __attribute__((__packed__))
+#define _retain_ __attribute__((__retain__))
#define _used_ __attribute__((__used__))
#define _unused_ __attribute__((__unused__))
#define _cleanup_(x) __attribute__((__cleanup__(x)))
@@ -59,8 +61,19 @@
#define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
#define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#endif
+
+ #define memcpy(a, b, c) CopyMem((a), (b), (c))
+ #define free(a) FreePool(a)
#endif
+/* This passes the argument through after (if asserts are enabled) checking that it is not null. */
+#define ASSERT_PTR(expr) \
+ ({ \
+ typeof(expr) _expr_ = (expr); \
+ assert(_expr_); \
+ _expr_; \
+ })
+
#if defined(static_assert)
#define assert_cc(expr) \
static_assert(expr, #expr)
@@ -81,8 +94,8 @@
#define ONCE __ONCE(UNIQ_T(_once_, UNIQ))
#define __ONCE(o) \
({ \
- static bool (o) = false; \
- __sync_bool_compare_and_swap(&(o), false, true); \
+ static sd_bool (o) = sd_false; \
+ __sync_bool_compare_and_swap(&(o), sd_false, sd_true); \
})
#undef MAX
@@ -232,7 +245,7 @@
#define IN_SET(x, ...) \
({ \
- sd_bool _found = false; \
+ sd_bool _found = sd_false; \
/* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \
* type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \
* the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \
@@ -241,7 +254,7 @@
assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \
switch(x) { \
FOR_EACH_MAKE_CASE(__VA_ARGS__) \
- _found = true; \
+ _found = sd_true; \
break; \
default: \
break; \
@@ -253,8 +266,9 @@
* resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
#define TAKE_PTR(ptr) \
({ \
- typeof(ptr) _ptr_ = (ptr); \
- (ptr) = NULL; \
+ typeof(ptr) *_pptr_ = &(ptr); \
+ typeof(ptr) _ptr_ = *_pptr_; \
+ *_pptr_ = NULL; \
_ptr_; \
})
@@ -264,3 +278,47 @@
* @x: a string literal.
*/
#define STRLEN(x) (sizeof(""x"") - sizeof(typeof(x[0])))
+
+#define mfree(memory) \
+ ({ \
+ free(memory); \
+ (typeof(memory)) NULL; \
+ })
+
+static inline size_t ALIGN_TO(size_t l, size_t ali) {
+ /* sd-boot uses UINTN for size_t, let's make sure SIZE_MAX is correct. */
+ assert_cc(SIZE_MAX == ~(size_t)0);
+
+ /* Check that alignment is exponent of 2 */
+#if SIZE_MAX == UINT_MAX
+ assert(__builtin_popcount(ali) == 1);
+#elif SIZE_MAX == ULONG_MAX
+ assert(__builtin_popcountl(ali) == 1);
+#elif SIZE_MAX == ULLONG_MAX
+ assert(__builtin_popcountll(ali) == 1);
+#else
+ #error "Unexpected size_t"
+#endif
+
+ if (l > SIZE_MAX - (ali - 1))
+ return SIZE_MAX; /* indicate overflow */
+
+ return ((l + ali - 1) & ~(ali - 1));
+}
+
+/* Same as ALIGN_TO but callable in constant contexts. */
+#define CONST_ALIGN_TO(l, ali) \
+ __builtin_choose_expr( \
+ __builtin_constant_p(l) && \
+ __builtin_constant_p(ali) && \
+ __builtin_popcountll(ali) == 1 && /* is power of 2? */ \
+ (l <= SIZE_MAX - (ali - 1)), /* overflow? */ \
+ ((l) + (ali) - 1) & ~((ali) - 1), \
+ VOID_0)
+
+#define UPDATE_FLAG(orig, flag, b) \
+ ((b) ? ((orig) | (flag)) : ((orig) & ~(flag)))
+#define SET_FLAG(v, flag, b) \
+ (v) = UPDATE_FLAG(v, flag, b)
+#define FLAGS_SET(v, flags) \
+ ((~(v) & (flags)) == 0)
diff --git a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c
index f170392603..735697659c 100644
--- a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c
+++ b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c
@@ -10,7 +10,7 @@
#include "string-util-fundamental.h"
sd_char *startswith(const sd_char *s, const sd_char *prefix) {
- sd_size_t l;
+ size_t l;
assert(s);
assert(prefix);
@@ -24,7 +24,7 @@ sd_char *startswith(const sd_char *s, const sd_char *prefix) {
#ifndef SD_BOOT
sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) {
- sd_size_t l;
+ size_t l;
assert(s);
assert(prefix);
@@ -38,7 +38,7 @@ sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) {
#endif
sd_char* endswith(const sd_char *s, const sd_char *postfix) {
- sd_size_t sl, pl;
+ size_t sl, pl;
assert(s);
assert(postfix);
@@ -59,7 +59,7 @@ sd_char* endswith(const sd_char *s, const sd_char *postfix) {
}
sd_char* endswith_no_case(const sd_char *s, const sd_char *postfix) {
- sd_size_t sl, pl;
+ size_t sl, pl;
assert(s);
assert(postfix);
diff --git a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h
index 7455c05492..dc0c1202be 100644
--- a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h
+++ b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h
@@ -68,10 +68,10 @@ static inline const sd_char *yes_no(sd_bool b) {
sd_int strverscmp_improved(const sd_char *a, const sd_char *b);
/* Like startswith(), but operates on arbitrary memory blocks */
-static inline void *memory_startswith(const void *p, sd_size_t sz, const sd_char *token) {
+static inline void *memory_startswith(const void *p, size_t sz, const sd_char *token) {
assert(token);
- sd_size_t n = strlen(token) * sizeof(sd_char);
+ size_t n = strlen(token) * sizeof(sd_char);
if (sz < n)
return NULL;
diff --git a/src/libnm-systemd-shared/src/fundamental/type.h b/src/libnm-systemd-shared/src/fundamental/type.h
deleted file mode 100644
index f645d2de7f..0000000000
--- a/src/libnm-systemd-shared/src/fundamental/type.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#ifdef SD_BOOT
-#include <efi.h>
-
-typedef BOOLEAN sd_bool;
-typedef CHAR16 sd_char;
-typedef INTN sd_int;
-typedef UINTN sd_size_t;
-
-#define true TRUE
-#define false FALSE
-#else
-#include <stdbool.h>
-#include <stdint.h>
-
-typedef bool sd_bool;
-typedef char sd_char;
-typedef int sd_int;
-typedef size_t sd_size_t;
-#endif
diff --git a/src/libnm-systemd-shared/src/fundamental/types-fundamental.h b/src/libnm-systemd-shared/src/fundamental/types-fundamental.h
new file mode 100644
index 0000000000..5977e40c6c
--- /dev/null
+++ b/src/libnm-systemd-shared/src/fundamental/types-fundamental.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+/* This defines a number of basic types that are one thing in userspace and another in the UEFI environment,
+ * but mostly the same in concept and behaviour.
+ *
+ * Note: if the definition of these types/values has slightly different semantics in userspace and in the
+ * UEFI environment then please prefix its name with "sd_" to make clear these types have special semantics,
+ * and *we* defined them. Otherwise, if the types are effectively 100% identical in behaviour in userspace
+ * and UEFI environment you can omit the prefix. (Examples: sd_char is 8 bit in userspace and 16 bit in UEFI
+ * space hence it should have the sd_ prefix; but size_t in userspace and UINTN in UEFI environment are 100%
+ * defined the same way ultimately, hence it's OK to just define size_t as alias to UINTN in UEFI
+ * environment, so that size_t can be used everywhere, without any "sd_" prefix.)
+ *
+ * Note: we generally prefer the userspace names of types and concepts. i.e. if in doubt please name types
+ * after the userspace vocabulary, and let's keep UEFI vocabulary specific to the UEFI build environment. */
+
+#ifdef SD_BOOT
+#include <efi.h>
+
+typedef BOOLEAN sd_bool;
+typedef CHAR16 sd_char;
+typedef INTN sd_int;
+typedef UINTN size_t;
+
+#define sd_true TRUE
+#define sd_false FALSE
+#else
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef bool sd_bool;
+typedef char sd_char;
+typedef int sd_int;
+
+#define sd_true true
+#define sd_false false
+
+#endif
diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.c b/src/libnm-systemd-shared/src/shared/dns-domain.c
index 473f6a0250..b82a9a1cc5 100644
--- a/src/libnm-systemd-shared/src/shared/dns-domain.c
+++ b/src/libnm-systemd-shared/src/shared/dns-domain.c
@@ -687,7 +687,7 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char
}
/* Found it! Now generate the new name */
- prefix = strndupa(name, saved_before - name);
+ prefix = strndupa_safe(name, saved_before - name);
r = dns_name_concat(prefix, new_suffix, 0, ret);
if (r < 0)
@@ -1037,7 +1037,7 @@ static bool dns_service_name_label_is_valid(const char *label, size_t n) {
if (memchr(label, 0, n))
return false;
- s = strndupa(label, n);
+ s = strndupa_safe(label, n);
return dns_service_name_is_valid(s);
}
diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.h b/src/libnm-systemd-shared/src/shared/dns-domain.h
index d0195c5890..c237f761c9 100644
--- a/src/libnm-systemd-shared/src/shared/dns-domain.h
+++ b/src/libnm-systemd-shared/src/shared/dns-domain.h
@@ -62,6 +62,10 @@ static inline int dns_name_is_valid_ldh(const char *s) {
return 1;
}
+static inline bool dns_name_is_empty(const char *s) {
+ return isempty(s) || streq(s, ".");
+}
+
void dns_name_hash_func(const char *s, struct siphash *state);
int dns_name_compare_func(const char *a, const char *b);
extern const struct hash_ops dns_name_hash_ops;