summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.gitlab-ci/run-test.sh2
-rw-r--r--Makefile.am23
-rw-r--r--NEWS19
-rw-r--r--config.h.meson3
-rw-r--r--configure.ac31
-rw-r--r--contrib/fedora/rpm/NetworkManager.spec2
-rwxr-xr-xcontrib/fedora/rpm/release.sh6
-rwxr-xr-xcontrib/fedora/utils/makerepo.sh17
-rwxr-xr-xcontrib/scripts/nm-in-container.d/data-nm-env-prepare.sh97
-rwxr-xr-xcontrib/scripts/nm-in-container.sh51
-rwxr-xr-xexamples/python/gi/checkpoint.py10
-rw-r--r--man/NetworkManager.conf.xml11
-rw-r--r--man/nmcli-examples.xml26
-rw-r--r--man/nmcli.xml32
-rw-r--r--meson.build35
-rw-r--r--meson_options.txt1
-rw-r--r--po/uk.po1177
-rw-r--r--src/c-list/.github/workflows/ci.yml18
-rw-r--r--src/c-list/AUTHORS3
-rw-r--r--src/c-list/NEWS.md13
-rw-r--r--src/c-list/README.md2
-rw-r--r--src/c-list/meson.build37
-rw-r--r--src/c-list/src/c-list.h25
-rw-r--r--src/c-list/src/meson.build6
-rw-r--r--src/c-list/src/test-api.c9
-rw-r--r--src/c-list/src/test-basic.c92
-rw-r--r--src/c-rbtree/.github/workflows/ci.yml30
-rw-r--r--src/c-rbtree/.gitmodules3
-rw-r--r--src/c-rbtree/AUTHORS2
-rw-r--r--src/c-rbtree/NEWS.md15
-rw-r--r--src/c-rbtree/README.md2
-rw-r--r--src/c-rbtree/meson.build15
-rw-r--r--src/c-rbtree/meson_options.txt1
-rw-r--r--src/c-rbtree/src/c-rbtree.h5
-rw-r--r--src/c-rbtree/src/meson.build33
-rw-r--r--src/c-rbtree/src/test-parallel.c3
m---------src/c-rbtree/subprojects/c-stdaux0
-rw-r--r--src/c-rbtree/subprojects/libcstdaux-1.wrap3
-rw-r--r--src/c-siphash/.github/workflows/ci.yml16
-rw-r--r--src/c-siphash/.gitmodules3
-rw-r--r--src/c-siphash/AUTHORS2
-rw-r--r--src/c-siphash/README.md2
-rw-r--r--src/c-siphash/meson.build14
-rw-r--r--src/c-siphash/src/meson.build29
m---------src/c-siphash/subprojects/c-stdaux0
-rw-r--r--src/c-siphash/subprojects/libcstdaux-1.wrap3
-rw-r--r--src/c-stdaux/.github/workflows/ci.yml16
-rw-r--r--src/c-stdaux/AUTHORS2
-rw-r--r--src/c-stdaux/README.md2
-rw-r--r--src/c-stdaux/meson.build77
-rw-r--r--src/c-stdaux/src/meson.build7
-rw-r--r--src/c-stdaux/src/test-basic.c8
-rw-r--r--src/core/NetworkManagerUtils.c3
-rw-r--r--src/core/devices/nm-device-bond.c44
-rw-r--r--src/core/devices/nm-device-bridge.c47
-rw-r--r--src/core/devices/nm-device-vrf.c54
-rw-r--r--src/core/devices/nm-device.c160
-rw-r--r--src/core/devices/nm-device.h19
-rw-r--r--src/core/devices/ovs/nm-device-ovs-bridge.c18
-rw-r--r--src/core/devices/ovs/nm-device-ovs-port.c120
-rw-r--r--src/core/devices/ovs/nm-ovsdb.c5
-rw-r--r--src/core/devices/team/nm-device-team.c70
-rw-r--r--src/core/dhcp/nm-dhcp-client.c11
-rw-r--r--src/core/dhcp/nm-dhcp-nettools.c55
-rw-r--r--src/core/dhcp/nm-dhcp-systemd.c696
-rw-r--r--src/core/dhcp/nm-dhcp-utils.c33
-rw-r--r--src/core/dns/nm-dns-dnsmasq.c123
-rw-r--r--src/core/dns/nm-dns-manager.c202
-rw-r--r--src/core/dns/nm-dns-manager.h9
-rw-r--r--src/core/dns/nm-dns-plugin.c161
-rw-r--r--src/core/dns/nm-dns-plugin.h13
-rw-r--r--src/core/dns/nm-dns-systemd-resolved.c359
-rw-r--r--src/core/dns/nm-dns-unbound.c84
-rw-r--r--src/core/dns/nm-dns-unbound.h27
-rw-r--r--src/core/meson.build1
-rw-r--r--src/core/nm-config.c46
-rw-r--r--src/core/nm-config.h5
-rw-r--r--src/core/nm-core-utils.c13
-rw-r--r--src/core/nm-dhcp-config.c23
-rw-r--r--src/core/nm-dhcp-config.h3
-rw-r--r--src/core/nm-firewall-utils.c3
-rw-r--r--src/core/nm-manager.c70
-rw-r--r--src/core/nm-manager.h4
-rw-r--r--src/core/settings/nm-settings.c53
-rw-r--r--src/core/settings/plugins/keyfile/nms-keyfile-plugin.c10
-rw-r--r--src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c6
-rw-r--r--src/core/tests/test-core.c23
-rw-r--r--src/core/tests/test-systemd.c159
-rw-r--r--src/core/tests/test-utils.c4
-rw-r--r--src/libnm-client-impl/nm-client.c16
-rw-r--r--src/libnm-client-impl/nm-default-libnm.h10
-rw-r--r--src/libnm-client-impl/nm-device-macvlan.c4
-rw-r--r--src/libnm-client-impl/nm-device-olpc-mesh.c3
-rw-r--r--src/libnm-client-impl/nm-device-vxlan.c8
-rw-r--r--src/libnm-client-impl/nm-device-wifi-p2p.c2
-rw-r--r--src/libnm-client-impl/nm-device-wifi.c2
-rw-r--r--src/libnm-client-impl/nm-device-wimax.c3
-rw-r--r--src/libnm-client-impl/nm-libnm-utils.h4
-rw-r--r--src/libnm-client-public/NetworkManager.h108
-rw-r--r--src/libnm-client-public/meson.build1
-rw-r--r--src/libnm-client-public/nm-access-point.h1
-rw-r--r--src/libnm-client-public/nm-active-connection.h21
-rw-r--r--src/libnm-client-public/nm-checkpoint.h1
-rw-r--r--src/libnm-client-public/nm-client.h3
-rw-r--r--src/libnm-client-public/nm-device-6lowpan.h1
-rw-r--r--src/libnm-client-public/nm-device-adsl.h1
-rw-r--r--src/libnm-client-public/nm-device-bond.h1
-rw-r--r--src/libnm-client-public/nm-device-bridge.h1
-rw-r--r--src/libnm-client-public/nm-device-bt.h1
-rw-r--r--src/libnm-client-public/nm-device-dummy.h1
-rw-r--r--src/libnm-client-public/nm-device-ethernet.h1
-rw-r--r--src/libnm-client-public/nm-device-generic.h1
-rw-r--r--src/libnm-client-public/nm-device-infiniband.h1
-rw-r--r--src/libnm-client-public/nm-device-ip-tunnel.h1
-rw-r--r--src/libnm-client-public/nm-device-macsec.h1
-rw-r--r--src/libnm-client-public/nm-device-macvlan.h1
-rw-r--r--src/libnm-client-public/nm-device-modem.h1
-rw-r--r--src/libnm-client-public/nm-device-olpc-mesh.h1
-rw-r--r--src/libnm-client-public/nm-device-ovs-bridge.h1
-rw-r--r--src/libnm-client-public/nm-device-ovs-interface.h1
-rw-r--r--src/libnm-client-public/nm-device-ovs-port.h1
-rw-r--r--src/libnm-client-public/nm-device-ppp.h1
-rw-r--r--src/libnm-client-public/nm-device-team.h1
-rw-r--r--src/libnm-client-public/nm-device-tun.h1
-rw-r--r--src/libnm-client-public/nm-device-veth.h1
-rw-r--r--src/libnm-client-public/nm-device-vlan.h1
-rw-r--r--src/libnm-client-public/nm-device-vrf.h1
-rw-r--r--src/libnm-client-public/nm-device-vxlan.h1
-rw-r--r--src/libnm-client-public/nm-device-wifi-p2p.h1
-rw-r--r--src/libnm-client-public/nm-device-wifi.h1
-rw-r--r--src/libnm-client-public/nm-device-wimax.h1
-rw-r--r--src/libnm-client-public/nm-device-wireguard.h1
-rw-r--r--src/libnm-client-public/nm-device-wpan.h1
-rw-r--r--src/libnm-client-public/nm-device.h1
-rw-r--r--src/libnm-client-public/nm-dhcp-config.h1
-rw-r--r--src/libnm-client-public/nm-enum-types.c.template38
-rw-r--r--src/libnm-client-public/nm-ip-config.h1
-rw-r--r--src/libnm-client-public/nm-object.h7
-rw-r--r--src/libnm-client-public/nm-remote-connection.h1
-rw-r--r--src/libnm-client-public/nm-secret-agent-old.h2
-rw-r--r--src/libnm-client-public/nm-types.h56
-rw-r--r--src/libnm-client-public/nm-vpn-connection.h1
-rw-r--r--src/libnm-client-public/nm-vpn-editor.h1
-rw-r--r--src/libnm-client-public/nm-vpn-plugin-old.h4
-rw-r--r--src/libnm-client-public/nm-vpn-service-plugin.h4
-rw-r--r--src/libnm-client-public/nm-wifi-p2p-peer.h1
-rw-r--r--src/libnm-client-public/nm-wimax-nsp.h1
-rw-r--r--src/libnm-core-impl/nm-connection.c18
-rw-r--r--src/libnm-core-impl/nm-keyfile-utils.c6
-rw-r--r--src/libnm-core-impl/nm-keyfile.c5
-rw-r--r--src/libnm-core-impl/nm-setting-bond.c9
-rw-r--r--src/libnm-core-impl/nm-setting-bridge.c11
-rw-r--r--src/libnm-core-impl/nm-setting-ethtool.c4
-rw-r--r--src/libnm-core-impl/nm-setting-ip-config.c10
-rw-r--r--src/libnm-core-impl/nm-utils.c3
-rw-r--r--src/libnm-core-intern/nm-core-internal.h2
-rw-r--r--src/libnm-core-intern/nm-keyfile-utils.h4
-rw-r--r--src/libnm-core-public/nm-version-macros.h.in1
-rw-r--r--src/libnm-core-public/nm-version.h14
-rw-r--r--src/libnm-glib-aux/nm-default-glib.h44
-rw-r--r--src/libnm-glib-aux/nm-enum-utils.c2
-rw-r--r--src/libnm-glib-aux/nm-io-utils.c285
-rw-r--r--src/libnm-glib-aux/nm-io-utils.h11
-rw-r--r--src/libnm-glib-aux/nm-macros-internal.h18
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.c661
-rw-r--r--src/libnm-glib-aux/nm-shared-utils.h104
-rw-r--r--src/libnm-glib-aux/nm-str-buf.h98
-rw-r--r--src/libnm-glib-aux/nm-test-utils.h3
-rw-r--r--src/libnm-glib-aux/tests/test-shared-general.c823
-rw-r--r--src/libnm-log-core/nm-logging.c2
-rw-r--r--src/libnm-platform/nm-platform.h165
-rw-r--r--src/libnm-std-aux/nm-default-std.h97
-rw-r--r--src/libnm-std-aux/nm-std-utils.h5
-rw-r--r--src/libnm-systemd-core/meson.build9
-rw-r--r--src/libnm-systemd-core/nm-sd-utils-core.c27
-rw-r--r--src/libnm-systemd-core/nm-sd-utils-core.h17
-rw-r--r--src/libnm-systemd-core/nm-sd-utils-dhcp.c40
-rw-r--r--src/libnm-systemd-core/nm-sd-utils-dhcp.h19
-rw-r--r--src/libnm-systemd-core/nm-sd.c1
-rw-r--r--src/libnm-systemd-core/nm-sd.h12
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/arp-util.c142
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/arp-util.h36
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h84
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h90
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c257
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c443
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c196
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/dhcp-protocol.h108
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/network-internal.c243
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/network-internal.h31
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c2285
-rw-r--r--src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c1508
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-dhcp-client.h345
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h91
-rw-r--r--src/libnm-systemd-core/src/systemd/sd-dhcp-option.h38
-rw-r--r--src/libnm-systemd-shared/nm-sd-utils-shared.c60
-rw-r--r--src/libnm-systemd-shared/nm-sd-utils-shared.h17
-rw-r--r--src/libnmc-base/nm-polkit-listener.c5
-rw-r--r--src/n-dhcp4/src/libndhcp4.sym1
-rw-r--r--src/n-dhcp4/src/n-dhcp4-c-lease.c16
-rw-r--r--src/n-dhcp4/src/test-api.c1
-rw-r--r--src/nm-daemon-helper/nm-daemon-helper.c4
-rw-r--r--src/nm-initrd-generator/nmi-cmdline-reader.c3
-rw-r--r--src/nm-priv-helper/nm-priv-helper.c1
-rw-r--r--src/nmcli/common.c152
-rw-r--r--src/nmcli/connections.c262
-rw-r--r--src/nmcli/meson.build4
-rw-r--r--src/nmcli/nmcli.c11
-rw-r--r--src/nmcli/nmcli.h68
-rw-r--r--src/nmtui/nmt-connect-connection-list.c1
-rw-r--r--src/tests/client/test-client.check-on-disk/test_offline.expected137
-rwxr-xr-xsrc/tests/client/test-client.py256
-rwxr-xr-xtools/meson-post-install.sh5
213 files changed, 5501 insertions, 9042 deletions
diff --git a/.gitlab-ci/run-test.sh b/.gitlab-ci/run-test.sh
index 18038304f8..c8c26f0815 100755
--- a/.gitlab-ci/run-test.sh
+++ b/.gitlab-ci/run-test.sh
@@ -2,6 +2,8 @@
set -ex
+export PAGER=cat
+
IS_FEDORA=0
IS_CENTOS=0
IS_ALPINE=0
diff --git a/Makefile.am b/Makefile.am
index 60a171f528..a9f028dcf9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1691,7 +1691,6 @@ libnm_lib_h_pub_real = \
src/libnm-client-public/nm-object.h \
src/libnm-client-public/nm-remote-connection.h \
src/libnm-client-public/nm-secret-agent-old.h \
- src/libnm-client-public/nm-types.h \
src/libnm-client-public/nm-vpn-connection.h \
src/libnm-client-public/nm-vpn-editor.h \
src/libnm-client-public/nm-vpn-plugin-old.h \
@@ -2329,12 +2328,8 @@ src_libnm_systemd_core_libnm_systemd_core_la_libadd = \
src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
src/libnm-systemd-core/nm-default-systemd-core.h \
- src/libnm-systemd-core/nm-sd-utils-core.c \
- src/libnm-systemd-core/nm-sd-utils-core.h \
src/libnm-systemd-core/nm-sd.c \
src/libnm-systemd-core/nm-sd.h \
- src/libnm-systemd-core/nm-sd-utils-dhcp.h \
- src/libnm-systemd-core/nm-sd-utils-dhcp.c \
src/libnm-systemd-core/sd-adapt-core/condition.h \
src/libnm-systemd-core/sd-adapt-core/conf-parser.h \
src/libnm-systemd-core/sd-adapt-core/device-util.h \
@@ -2345,16 +2340,8 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
src/libnm-systemd-core/sd-adapt-core/sd-daemon.h \
src/libnm-systemd-core/sd-adapt-core/sd-device.h \
src/libnm-systemd-core/sd-adapt-core/udev-util.h \
- src/libnm-systemd-core/src/libsystemd-network/arp-util.c \
- src/libnm-systemd-core/src/libsystemd-network/arp-util.h \
src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c \
src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h \
- src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h \
- src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h \
- src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c \
- src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c \
- src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c \
- src/libnm-systemd-core/src/libsystemd-network/dhcp-protocol.h \
src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h \
src/libnm-systemd-core/src/libsystemd-network/dhcp6-lease-internal.h \
src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c \
@@ -2369,10 +2356,6 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
src/libnm-systemd-core/src/libsystemd-network/lldp-rx-internal.h \
src/libnm-systemd-core/src/libsystemd-network/network-common.c \
src/libnm-systemd-core/src/libsystemd-network/network-common.h \
- src/libnm-systemd-core/src/libsystemd-network/network-internal.c \
- src/libnm-systemd-core/src/libsystemd-network/network-internal.h \
- src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c \
- src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c \
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c \
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c \
src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c \
@@ -2384,9 +2367,6 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h \
src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c \
src/libnm-systemd-core/src/systemd/_sd-common.h \
- src/libnm-systemd-core/src/systemd/sd-dhcp-client.h \
- src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h \
- src/libnm-systemd-core/src/systemd/sd-dhcp-option.h \
src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h \
src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h \
src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h \
@@ -2547,8 +2527,6 @@ src_core_libNetworkManager_la_SOURCES = \
src/core/dns/nm-dns-dnsmasq.h \
src/core/dns/nm-dns-systemd-resolved.c \
src/core/dns/nm-dns-systemd-resolved.h \
- src/core/dns/nm-dns-unbound.c \
- src/core/dns/nm-dns-unbound.h \
\
src/core/dnsmasq/nm-dnsmasq-manager.c \
src/core/dnsmasq/nm-dnsmasq-manager.h \
@@ -5337,6 +5315,7 @@ EXTRA_DIST += \
src/tests/client/test-client.check-on-disk/test_002.expected \
src/tests/client/test-client.check-on-disk/test_003.expected \
src/tests/client/test-client.check-on-disk/test_004.expected \
+ src/tests/client/test-client.check-on-disk/test_offline.expected \
\
src/tests/client/meson.build \
$(NULL)
diff --git a/NEWS b/NEWS
index 8aae2324dc..b01faa063c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,23 @@
=============================================
+NetworkManager-1.40
+Overview of changes since NetworkManager-1.38
+=============================================
+
+This is a snapshot of NetworkManager development. The API is
+subject to change and not guaranteed to be compatible with
+the later release.
+USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
+
+* Drop unused, internal systemd DHCPv4 client. This is long
+ replaced by nettools' n-dhcp4 implementation.
+* The nmcli command now supports --offline argument with "add" and
+ "modify" commands, allowing operation on keyfile-formatted connection
+ profiles without the service running (e.g. during system provisioning).
+* The device state file /run/NetworkManager/devices/$ifindex now has
+ new sections [dhcp4] and [dhcp6] containing the DHCP options for the
+ current lease.
+
+=============================================
NetworkManager-1.38
Overview of changes since NetworkManager-1.36
=============================================
diff --git a/config.h.meson b/config.h.meson
index 7d1feb53ad..7337165082 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -13,9 +13,6 @@
/* Define to path of dnsmasq binary */
#mesondefine DNSMASQ_PATH
-/* Define to path of unbound dnssec-trigger-script */
-#mesondefine DNSSEC_TRIGGER_PATH
-
/* Gettext package */
#mesondefine GETTEXT_PACKAGE
diff --git a/configure.ac b/configure.ac
index 09c69720c3..8e00da68b0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,8 +7,8 @@ dnl - add corresponding NM_VERSION_x_y_z macros in
dnl "shared/nm-version-macros.h.in"
dnl - update number in meson.build
m4_define([nm_major_version], [1])
-m4_define([nm_minor_version], [38])
-m4_define([nm_micro_version], [0])
+m4_define([nm_minor_version], [39])
+m4_define([nm_micro_version], [4])
m4_define([nm_version],
[nm_major_version.nm_minor_version.nm_micro_version])
@@ -306,11 +306,12 @@ AC_ARG_WITH(udev-dir,
[Absolute path of the udev base directory. Set to 'no' not to install the udev rules]),
[], [with_udev_dir="yes"])
if test "$with_udev_dir" != 'no'; then
- if test "$with_udev_dir" != 'yes' && printf '%s' "$with_udev_dir" | grep -v -q '^/'; then
- AC_MSG_ERROR([--with-udev-dir must be an absolute path or 'yes' or 'no'. Instead it is '$with_udev_dir'])
- fi
- if test "$with_udev_dir" = 'yes'; then
- with_udev_dir="\$(prefix)/lib/udev"
+ if test "$with_udev_dir" = 'yes' -o "$with_udev_dir" = "" ; then
+ with_udev_dir="\${prefix}/lib/udev"
+ else
+ if printf '%s' "$with_udev_dir" | grep -v -q '^/'; then
+ AC_MSG_ERROR([--with-udev-dir must be an absolute path or 'yes' or 'no'. Instead it is '$with_udev_dir'])
+ fi
fi
UDEV_DIR="$with_udev_dir"
AC_SUBST(UDEV_DIR)
@@ -745,7 +746,6 @@ AC_SUBST(GLIB_MKENUMS)
AC_ARG_WITH(dbus-sys-dir,
AS_HELP_STRING([--with-dbus-sys-dir=DIR], [where D-BUS system.d directory is]))
-
if test -n "$with_dbus_sys_dir" ; then
DBUS_SYS_DIR="$with_dbus_sys_dir"
else
@@ -1006,18 +1006,6 @@ fi
AC_DEFINE_UNQUOTED(DNSMASQ_PATH, "$DNSMASQ_PATH", [Define to path of dnsmasq binary])
AC_SUBST(DNSMASQ_PATH)
-# dnssec-trigger-script path
-AC_ARG_WITH(dnssec_trigger,
- AS_HELP_STRING([--with-dnssec-trigger=/path/to/dnssec-trigger-script], [path to unbound dnssec-trigger-script]))
-if test "x${with_dnssec_trigger}" = x; then
- AC_PATH_PROG(DNSSEC_TRIGGER_PATH, dnssec-trigger-script, /usr/libexec/dnssec-trigger-script,
- /usr/local/libexec:/usr/local/lib:/usr/local/lib/dnssec-trigger:/usr/libexec:/usr/lib:/usr/lib/dnssec-trigger)
-else
- DNSSEC_TRIGGER_PATH="$with_dnssec_trigger"
-fi
-AC_DEFINE_UNQUOTED(DNSSEC_TRIGGER_PATH, "$DNSSEC_TRIGGER_PATH", [Define to path of unbound dnssec-trigger-script])
-AC_SUBST(DNSSEC_TRIGGER_PATH)
-
# system CA certificates path
AC_ARG_WITH(system-ca-path,
AS_HELP_STRING([--with-system-ca-path=/path/to/ssl/certs], [path to system CA certificates]))
@@ -1374,8 +1362,10 @@ echo " exec_prefix: $exec_prefix"
echo " sysconfdir: $sysconfdir"
echo " localstatedir: $localstatedir"
echo " runstatedir: $runstatedir"
+echo " datarootdir: $datarootdir"
echo " datadir: $datadir"
echo " systemdunitdir: $with_systemdsystemunitdir"
+echo " udev-dir: $with_udev_dir"
echo " nmbinary: $nmbinary"
echo " nmconfdir: $nmconfdir"
echo " nmlibdir: $nmlibdir"
@@ -1383,6 +1373,7 @@ echo " nmdatadir: $nmdatadir"
echo " nmstatedir: $nmstatedir"
echo " nmrundir: $nmrundir"
echo " system-ca-path: $with_system_ca_path"
+echo " dbus-sys-dir: $DBUS_SYS_DIR"
echo
echo "Platform:"
diff --git a/contrib/fedora/rpm/NetworkManager.spec b/contrib/fedora/rpm/NetworkManager.spec
index 50d5d31ae8..779b71ba2a 100644
--- a/contrib/fedora/rpm/NetworkManager.spec
+++ b/contrib/fedora/rpm/NetworkManager.spec
@@ -13,8 +13,8 @@
%global glib2_version %(pkg-config --modversion glib-2.0 2>/dev/null || echo bad)
%global epoch_version 1
-%global rpm_version __VERSION__
%global real_version __VERSION__
+%global rpm_version %{real_version}
%global release_version __RELEASE_VERSION__
%global snapshot __SNAPSHOT__
%global git_sha __COMMIT__
diff --git a/contrib/fedora/rpm/release.sh b/contrib/fedora/rpm/release.sh
index 9b2ba5ea8c..e653509869 100755
--- a/contrib/fedora/rpm/release.sh
+++ b/contrib/fedora/rpm/release.sh
@@ -548,9 +548,13 @@ done
do_command git push "$ORIGIN" "${BRANCHES[@]}" || die "failed to to push branches ${BRANCHES[@]} to $ORIGIN"
+FAIL=0
for r in "${RELEASE_FILES[@]}"; do
- do_command ssh master.gnome.org ftpadmin install --unattended "$r" || die "ftpadmin install failed"
+ do_command ssh master.gnome.org ftpadmin install --unattended "$r" || FAIL=1
done
+if [ "$FAIL" = 1 ]; then
+ die "ftpadmin install failed. This was the last step. Invoke the command manually"
+fi
CLEANUP_CHECKOUT_BRANCH=
if [ "$DRY_RUN" = 0 ]; then
diff --git a/contrib/fedora/utils/makerepo.sh b/contrib/fedora/utils/makerepo.sh
index 7f471f75c6..47778b405b 100755
--- a/contrib/fedora/utils/makerepo.sh
+++ b/contrib/fedora/utils/makerepo.sh
@@ -70,7 +70,7 @@ git_remote_add_gnome() {
}
git_remote_add_github() {
- git remote add "${2-origin}" "git://github.com/$1.git"
+ git remote add "${2-origin}" "https://github.com/$1.git"
git remote 'set-url' --push "${2-origin}" "git@github.com:$1.git"
}
@@ -319,16 +319,25 @@ MAKEREPO_GIT_IGNORE_LAST="makerepo.gitignore.last-$CURRENT_BRANCH"
get_local_mirror() {
local URL="$1"
+ local DIRNAME
+ local FULLNAME
if [[ -z "$URL" ]]; then
return
fi
- local DIRNAME="$(echo $URL.git | sed -e 's#^.*/\([^/]\+\)$#\1#' -e 's/\(.*\)\.git$/\1/')"
- local FULLNAME="$srcdir/.git/.makerepo-${DIRNAME}.git"
-
[[ -n "$NO_REMOTE" ]] && return
+ DIRNAME="${URL##*/}"
+ DIRNAME="${DIRNAME%.git}"
+ FULLNAME="$srcdir/.git/.makerepo-${DIRNAME}.git"
+
+ if [ ! -d "$FULLNAME" ] && [ -d "$FULLNAME.git" ]; then
+ # due to a bug, old versions of the script might have created "*.git.git/" directories.
+ # rename.
+ mv "$FULLNAME.git" "$FULLNAME"
+ fi
+
if [[ ! -d "$FULLNAME" ]]; then
if [[ -f "$FULLNAME" ]]; then
# create a file with name $FULLNAME, to suppress local mirroring
diff --git a/contrib/scripts/nm-in-container.d/data-nm-env-prepare.sh b/contrib/scripts/nm-in-container.d/data-nm-env-prepare.sh
index 61cee0371c..49c91d3ff8 100755
--- a/contrib/scripts/nm-in-container.d/data-nm-env-prepare.sh
+++ b/contrib/scripts/nm-in-container.d/data-nm-env-prepare.sh
@@ -11,6 +11,9 @@ do_cleanup() {
local IDX="$1"
local NAME_PREFIX="${2:-net}"
local PEER_PREFIX="${3:-d_}"
+ local NETNS_PREFIX="${4:-tt}"
+
+ logger --id "nm-env-prepare-$IDX" "cleanup start # $@"
pkill -F "/tmp/nm-dnsmasq-$PEER_PREFIX$IDX.pid" dnsmasq &>/dev/null || :
rm -rf "/tmp/nm-dnsmasq-$PEER_PREFIX$IDX.pid"
@@ -24,40 +27,60 @@ do_cleanup() {
rm -rf "/tmp/nm-radvd-$PEER_PREFIX$IDX.conf"
- ip link del "$PEER_PREFIX$IDX" &>/dev/null || :
+ ip -netns "$NETNS_PREFIX$IDX" link del "$PEER_PREFIX$IDX" &>/dev/null || :
+
+ ip netns del "$NETNS_PREFIX$IDX" &>/dev/null || :
+
+ logger --id "nm-env-prepare-$IDX" "cleanup complete # $@"
}
do_setup() {
local IDX="$1"
local NAME_PREFIX="${2:-net}"
local PEER_PREFIX="${3:-d_}"
+ local NETNS_PREFIX="${4:-tt}"
- do_cleanup "$IDX"
+ logger --id "nm-env-prepare-$IDX" "setup start # $@"
- ip link add "$NAME_PREFIX$IDX" type veth peer "$PEER_PREFIX$IDX"
- ip link set "$PEER_PREFIX$IDX" up
+ ip netns add "$NETNS_PREFIX$IDX"
+ ip -netns "$NETNS_PREFIX$IDX" link set lo up
- ip addr add "192.168.$((120 + IDX)).1/23" dev "$PEER_PREFIX$IDX"
- ip addr add "192:168:$((120 + IDX))::1/64" dev "$PEER_PREFIX$IDX"
+ ip -netns "$NETNS_PREFIX$IDX" link add "$NAME_PREFIX$IDX" type veth peer "$PEER_PREFIX$IDX"
+ ip -netns "$NETNS_PREFIX$IDX" link set "$PEER_PREFIX$IDX" up
+
+ ip -netns "$NETNS_PREFIX$IDX" addr add "192.168.$((120 + IDX)).1/23" dev "$PEER_PREFIX$IDX"
+ ip -netns "$NETNS_PREFIX$IDX" addr add "192:168:$((120 + IDX))::1/64" dev "$PEER_PREFIX$IDX"
# PPPoE inside the rootless container is not actually working, because
# /dev/ppp is not accessible. Still start it, so that we at least can
# test how far it goes...
echo "192.168.$((120 + $IDX)).180-200" > "/tmp/nm-pppoe-allip-$PEER_PREFIX$IDX"
- pppoe-server -X "/tmp/nm-pppoe-$PEER_PREFIX$IDX.pid" -S isp -C isp -L "192.168.$((120 + IDX)).1" -p "/tmp/nm-pppoe-allip-$PEER_PREFIX$IDX" -I "$PEER_PREFIX$IDX" &
-
- dnsmasq \
- --conf-file=/dev/null \
- --pid-file="/tmp/nm-dnsmasq-$PEER_PREFIX$IDX.pid" \
- --no-hosts \
- --keep-in-foreground \
- --bind-interfaces \
- --except-interface=lo \
- --clear-on-reload \
- --listen-address="192.168.$((120 + $IDX)).1" \
- --dhcp-range="192.168.$((120 + $IDX)).100,192.168.$((120 + $IDX)).150" \
- --no-ping \
- &
+ ip netns exec "$NETNS_PREFIX$IDX" \
+ pppoe-server \
+ -X "/tmp/nm-pppoe-$PEER_PREFIX$IDX.pid" \
+ -S isp \
+ -C isp \
+ -L "192.168.$((120 + IDX)).1" \
+ -p "/tmp/nm-pppoe-allip-$PEER_PREFIX$IDX" \
+ -I "$PEER_PREFIX$IDX" \
+ &
+
+ ip netns exec "$NETNS_PREFIX$IDX" \
+ dnsmasq \
+ --conf-file=/dev/null \
+ --pid-file="/tmp/nm-dnsmasq-$PEER_PREFIX$IDX.pid" \
+ --no-hosts \
+ --keep-in-foreground \
+ --bind-interfaces \
+ --log-debug \
+ --log-queries \
+ --log-dhcp \
+ --except-interface=lo \
+ --clear-on-reload \
+ --listen-address="192.168.$((120 + $IDX)).1" \
+ --dhcp-range="192.168.$((120 + $IDX)).100,192.168.$((120 + $IDX)).150" \
+ --no-ping \
+ &
cat <<EOF > "/tmp/nm-radvd-$PEER_PREFIX$IDX.conf"
interface $PEER_PREFIX$IDX
@@ -70,10 +93,17 @@ interface $PEER_PREFIX$IDX
};
EOF
- radvd \
- --config "/tmp/nm-radvd-$PEER_PREFIX$IDX.conf" \
- --pidfile "/tmp/nm-radvd-$PEER_PREFIX$IDX.pid" \
- &
+ ip netns exec "$NETNS_PREFIX$IDX" \
+ radvd \
+ --config "/tmp/nm-radvd-$PEER_PREFIX$IDX.conf" \
+ --pidfile "/tmp/nm-radvd-$PEER_PREFIX$IDX.pid" \
+ --logmethod syslog \
+ -d 5 \
+ &
+
+ ip -netns ""$NETNS_PREFIX$IDX"" link set "$NAME_PREFIX$IDX" netns $$
+
+ logger --id "nm-env-prepare-$IDX" "setup complete: netns=$NETNS_PREFIX$IDX, iface=$NAME_PREFIX$IDX, peer=$PEER_PREFIX$IDX # $@"
}
do_redo() {
@@ -81,8 +111,27 @@ do_redo() {
do_setup "$@"
}
+do_one_time_setup() {
+ if [ ! -d /tmp/sys2 ]; then
+ # `ip -netns t exec ...` will try to mount sysfs. But kernel rejects that in
+ # the container, unless a writable sysfs is already mounted. Due to --priviledged,
+ # we have /sys mounted rw, however, ip will first unmount /sys before trying to
+ # remount it. We thus need it mounted as rw one additional time.
+ #
+ # Let's do this setup step once, and never clean it up.
+ # https://github.com/containers/podman/issues/11887#issuecomment-938706628
+ mkdir /tmp/sys2
+ mount -t sysfs --make-private /tmp/sys2
+ fi
+}
+
###############################################################################
+# We do this one-time-setup always when the script runs, and never clean it
+# up.
+do_one_time_setup
+
+
IDX=1
NAME_PREFIX=net
PEER_PREFIX=
diff --git a/contrib/scripts/nm-in-container.sh b/contrib/scripts/nm-in-container.sh
index e4dda6d384..02a16e9da3 100755
--- a/contrib/scripts/nm-in-container.sh
+++ b/contrib/scripts/nm-in-container.sh
@@ -109,7 +109,54 @@ find NetworkManager bind mounted at $BASEDIR_NM
run \`nm-env-prepare.sh setup --idx 1\` to setup test interfaces
Configure NetworkManager with
- \$ ./configure --enable-maintainer-mode --enable-more-warnings=error --with-more-asserts="\${NM_BUILD_MORE_ASSERTS:-1000}" --with-nm-cloud-setup=yes --prefix=/opt/test --localstatedir=/var --sysconfdir=/etc --enable-gtk-doc --enable-introspection --with-ofono=yes --with-dhclient=yes --with-dhcpcanon=yes --with-dhcpcd=yes --enable-more-logging --enable-compile-warnings=yes --enable-address-sanitizer=no --enable-undefined-sanitizer=no --with-valgrind=yes --enable-concheck --enable-wimax --enable-ifcfg-rh=yes --enable-config-plugin-ibft=yes --enable-ifcfg-suse --enable-ifupdown=yes --enable-ifnet --enable-vala=yes --enable-polkit=yes --with-libnm-glib=yes --with-nmcli=yes --with-nmtui=yes --with-modem-manager-1 --with-suspend-resume=systemd --enable-teamdctl=yes --enable-ovs=yes --enable-tests="\${NM_BUILD_TESTS:-yes}" --with-netconfig=/bin/nowhere/netconfig --with-resolvconf=/bin/nowhere/resolvconf --with-crypto=nss --with-session-tracking=systemd --with-consolekit=yes --with-systemd-logind=yes --with-iwd=yes --enable-json-validation=yes --with-consolekit=yes --with-config-dns-rc-manager-default=auto --with-config-dhcp-default=internal "\${NM_CONFIGURE_OTPS[@]}"
+ \$ ./configure \
+ --enable-address-sanitizer=no \
+ --enable-compile-warnings=yes \
+ --enable-concheck \
+ --enable-config-plugin-ibft=yes \
+ --enable-gtk-doc \
+ --enable-ifcfg-rh=yes \
+ --enable-ifcfg-suse \
+ --enable-ifnet \
+ --enable-ifupdown=yes \
+ --enable-introspection \
+ --enable-json-validation=yes \
+ --enable-maintainer-mode \
+ --enable-more-logging \
+ --enable-more-warnings=error \
+ --enable-ovs=yes \
+ --enable-polkit=yes \
+ --enable-teamdctl=yes \
+ --enable-undefined-sanitizer=no \
+ --enable-vala=yes \
+ --enable-wimax \
+ --localstatedir=/var \
+ --prefix=/opt/test \
+ --sysconfdir=/etc \
+ --with-config-dhcp-default=internal \
+ --with-config-dns-rc-manager-default=auto \
+ --with-consolekit=yes \
+ --with-consolekit=yes \
+ --with-crypto=nss \
+ --with-dhclient=yes \
+ --with-dhcpcanon=yes \
+ --with-dhcpcd=yes \
+ --with-iwd=yes \
+ --with-libnm-glib=yes \
+ --with-modem-manager-1 \
+ --with-netconfig=/bin/nowhere/netconfig \
+ --with-nm-cloud-setup=yes \
+ --with-nmcli=yes \
+ --with-nmtui=yes \
+ --with-ofono=yes \
+ --with-resolvconf=/bin/nowhere/resolvconf \
+ --with-session-tracking=systemd \
+ --with-suspend-resume=systemd \
+ --with-systemd-logind=yes \
+ --with-valgrind=yes \
+ --enable-tests="\${NM_BUILD_TESTS:-yes}" \
+ --with-more-asserts="\${NM_BUILD_MORE_ASSERTS:-1000}" \
+ "\${NM_CONFIGURE_OTPS[@]}"
Test with:
\$ systemctl stop NetworkManager; /opt/test/sbin/NetworkManager --debug 2>&1 | tee -a /tmp/nm-log.txt
EOF
@@ -249,6 +296,8 @@ RUN dnf install -y \\
mlocate \\
mobile-broadband-provider-info-devel \\
newt-devel \\
+ nispor \\
+ nmstate \\
nss-devel \\
polkit-devel \\
ppp \\
diff --git a/examples/python/gi/checkpoint.py b/examples/python/gi/checkpoint.py
index b63b1c37a4..6f3194cdb1 100755
--- a/examples/python/gi/checkpoint.py
+++ b/examples/python/gi/checkpoint.py
@@ -71,11 +71,11 @@ def find_checkpoint(nmc, path):
def find_checkpoint_last(nmc):
- l = [c.get_path() for c in nmc.get_checkpoints()]
- if not l:
- return None
- l.sort(key=checkpoint_path_to_num)
- return l[-1]
+ return max(
+ nmc.get_checkpoints(),
+ key=lambda c: checkpoint_path_to_num(c.get_path()),
+ default=None,
+ )
def validate_path(path, nmc):
diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml
index cb6b40afa0..18b25d9370 100644
--- a/man/NetworkManager.conf.xml
+++ b/man/NetworkManager.conf.xml
@@ -345,19 +345,12 @@ no-auto-default=*
<para><literal>systemd-resolved</literal>: NetworkManager will
push the DNS configuration to systemd-resolved</para>
- <para><literal>unbound</literal>: NetworkManager will talk
- to unbound and dnssec-triggerd, using "Conditional Forwarding"
- with DNSSEC support. <filename>/etc/resolv.conf</filename>
- will be managed by dnssec-trigger daemon. This option is
- deprecated. Note that dnssec-trigger ships a NetworkManager dispatcher
- script so this DNS plugin is not necessary.</para>
-
<para><literal>none</literal>: NetworkManager will not
modify resolv.conf. This implies
<literal>rc-manager</literal>&nbsp;<literal>unmanaged</literal></para>
- <para>Note that the plugins <literal>dnsmasq</literal>, <literal>systemd-resolved</literal>
- and <literal>unbound</literal> are caching local nameservers.
+ <para>Note that the plugins <literal>dnsmasq</literal> and <literal>systemd-resolved</literal>
+ are caching local nameservers.
Hence, when NetworkManager writes <filename>&nmrundir;/resolv.conf</filename>
and <filename>/etc/resolv.conf</filename> (according to <literal>rc-manager</literal>
setting below), the name server there will be localhost only.
diff --git a/man/nmcli-examples.xml b/man/nmcli-examples.xml
index 5744ad12bb..0afa9797a3 100644
--- a/man/nmcli-examples.xml
+++ b/man/nmcli-examples.xml
@@ -614,6 +614,32 @@ Connection 'ethernet-4' (de89cdeb-a3e1-4d53-8fa0-c22546c775f4) successfully
<screen><prompt>$ </prompt><userinput>nmcli connection add type bluetooth con-name "My Bluetooth Hotspot" autoconnect no ifname btnap0 bluetooth.type nap ipv4.method shared ipv6.method shared</userinput></screen>
</example>
+ <example><title>Offline use</title>
+<screen><prompt>$ </prompt><userinput>nmcli --offline con add type ethernet '
+ conn.id eth0 \
+ conn.interface-name eth0 \
+ >/sysroot/etc/NetworkManager/system-connections/eth0.nmconnection</userinput></screen>
+ <para>
+ Creates a connection file in keyfile format without using the NetworkManager service.
+ This allows for use of familiar <command>nmcli</command> syntax in situations
+ where the service is not running, such as during system installation of image
+ provisioning and ensures the resulting file is correctly formatted.
+ </para>
+<screen><prompt>$ </prompt><userinput>nmcli --offline con modify type ethernet '
+ conn.id eth0-ipv6 \
+ ipv4.method disabled \
+ &lt;/sysroot/etc/NetworkManager/system-connections/eth0.nmconnection \
+ >/sysroot/etc/NetworkManager/system-connections/eth0-ipv6.nmconnection</userinput></screen>
+ <para>
+ Read and write a connection file without using the NetworkManager service, modifying
+ some properties along the way.
+ </para>
+ <para>
+ This allows templating of the connection profiles using familiar
+ <command>nmcli</command> syntax in situations where the service is not running.
+ </para>
+ </example>
+
</refsect1>
<refsect1>
diff --git a/man/nmcli.xml b/man/nmcli.xml
index d4f27b0b37..ba89b29112 100644
--- a/man/nmcli.xml
+++ b/man/nmcli.xml
@@ -316,6 +316,23 @@
<varlistentry>
<term><group choice='plain'>
+ <arg choice='plain'><option>--offline</option></arg>
+ </group></term>
+
+ <listitem>
+ <para>Work without a daemon. Makes <command>connection add</command> and
+ <command>connection modify</command> commands accept and produce connection
+ data via standard input/output. Ordinarily, nmcli would communicate with
+ the NetworkManager service.</para>
+
+ <para>The connection data format (keyfile) is described in
+ <citerefentry><refentrytitle>nm-settings-keyfile</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ manual.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><group choice='plain'>
<arg choice='plain'><option>-v</option></arg>
<arg choice='plain'><option>--version</option></arg>
</group></term>
@@ -928,7 +945,7 @@
<arg choice='plain'><option>uuid</option></arg>
<arg choice='plain'><option>path</option></arg>
</group>
- <arg choice='plain'><replaceable>ID</replaceable></arg>
+ <arg><replaceable>ID</replaceable></arg>
<arg rep='repeat' choice='plain'>
<group choice='req'>
<arg choice='plain'><replaceable>option</replaceable> <replaceable>value</replaceable></arg>
@@ -962,7 +979,14 @@
<para>The connection is identified by its name, UUID or D-Bus path. If
<replaceable>ID</replaceable> is ambiguous, a keyword <option>id</option>,
- <option>uuid</option> or <option>path</option> can be used.</para>
+ <option>uuid</option> or <option>path</option> can be used.
+ The <replaceable>ID</replaceable> is not used with the global
+ <option>--offline</option> option.</para>
+
+ <para>When the global <option>--offline</option> is used, the
+ command reads the connection from the standard input and prints the
+ modified connection to standard output instead of making the
+ the NetworkManager daemon act upon specified connection.</para>
</listitem>
</varlistentry>
@@ -1096,6 +1120,10 @@
</listitem>
</varlistentry>
</variablelist>
+
+ <para>When the global <option>--offline</option> is used, the
+ command prints the resulting connection to standard output instead of
+ actually adding the connection via the NetworkManager daemon.</para>
</listitem>
</varlistentry>
diff --git a/meson.build b/meson.build
index 7a7eb176ae..4058e05f88 100644
--- a/meson.build
+++ b/meson.build
@@ -6,7 +6,7 @@ project(
# - add corresponding NM_VERSION_x_y_z macros in
# "src/libnm-core-public/nm-version-macros.h.in"
# - update number in configure.ac
- version: '1.38.0',
+ version: '1.39.4',
license: 'GPL2+',
default_options: [
'buildtype=debugoptimized',
@@ -353,10 +353,14 @@ if enable_introspection
endif
udev_udevdir = get_option('udev_dir')
-install_udevdir = (udev_udevdir != 'no')
-
-if install_udevdir and udev_udevdir == ''
- udev_udevdir = dependency('udev').get_pkgconfig_variable('udevdir')
+if udev_udevdir == 'no'
+ install_udevdir = false
+else
+ install_udevdir = true
+ if (udev_udevdir == '' or udev_udevdir == 'yes')
+ udev_udevdir = join_paths(nm_prefix, 'lib/udev')
+ endif
+ assert(udev_udevdir.startswith('/'), 'udev_dir must be an absolute path, but is ' + udev_udevdir)
endif
systemd_systemdsystemunitdir = get_option('systemdsystemunitdir')
@@ -364,7 +368,7 @@ install_systemdunitdir = (systemd_systemdsystemunitdir != 'no')
if install_systemdunitdir and systemd_systemdsystemunitdir == ''
assert(systemd_dep.found(), 'systemd required but not found, please provide a valid systemd user unit dir or disable it')
- systemd_systemdsystemunitdir = systemd_dep.get_pkgconfig_variable('systemdsystemunitdir')
+ systemd_systemdsystemunitdir = systemd_dep.get_pkgconfig_variable('systemdsystemunitdir', define_variable: ['rootprefix', nm_prefix])
endif
enable_systemd_journal = get_option('systemd_journal')
@@ -551,7 +555,7 @@ endif
dbus_conf_dir = get_option('dbus_conf_dir')
if dbus_conf_dir == ''
assert(dbus_dep.found(), 'D-Bus required but not found, please provide a valid system bus config dir')
- dbus_conf_dir = join_paths(dbus_dep.get_pkgconfig_variable('datadir'), 'dbus-1', 'system.d')
+ dbus_conf_dir = join_paths(dbus_dep.get_pkgconfig_variable('datarootdir', define_variable: ['prefix', nm_prefix]), 'dbus-1', 'system.d')
endif
dbus_interfaces_dir = dbus_dep.get_pkgconfig_variable('interfaces_dir', define_variable: ['datadir', nm_datadir])
@@ -683,18 +687,11 @@ endforeach
# external misc tools paths
default_paths = ['/sbin', '/usr/sbin']
-dnssec_ts_paths = ['/usr/local/libexec',
- '/usr/local/lib',
- '/usr/local/lib/dnssec-trigger',
- '/usr/libexec',
- '/usr/lib',
- '/usr/lib/dnssec-trigger']
# 0: cmdline option, 1: paths, 2: fallback
-progs = [['iptables', default_paths, '/usr/sbin/iptables'],
- ['nft', default_paths, '/usr/sbin/nft'],
- ['dnsmasq', default_paths, ''],
- ['dnssec_trigger', dnssec_ts_paths, join_paths(nm_libexecdir, 'dnssec-trigger-script') ],
+progs = [['iptables', default_paths, '/usr/sbin/iptables'],
+ ['nft', default_paths, '/usr/sbin/nft'],
+ ['dnsmasq', default_paths, ''],
]
foreach prog : progs
@@ -1020,6 +1017,7 @@ output = '\nSystem paths:\n'
output += ' prefix: ' + nm_prefix + '\n'
output += ' exec_prefix: ' + nm_prefix + '\n'
output += ' systemdunitdir: ' + systemd_systemdsystemunitdir + '\n'
+output += ' udev_dir: ' + udev_udevdir + '\n'
output += ' nmbinary: ' + nm_pkgsbindir + '\n'
output += ' nmconfdir: ' + nm_pkgconfdir + '\n'
output += ' nmlibdir: ' + nm_pkglibdir + '\n'
@@ -1028,7 +1026,8 @@ output += ' nmstatedir: ' + nm_pkgstatedir + '\n'
output += ' nmrundir: ' + nm_pkgrundir + '\n'
output += ' nmvpndir: ' + nm_vpndir + '\n'
output += ' nmplugindir: ' + nm_plugindir + '\n'
-output += ' system-ca-path: ' + system_ca_path + '\n'
+output += ' system_ca_path: ' + system_ca_path + '\n'
+output += ' dbus_conf_dir: ' + dbus_conf_dir + '\n'
output += '\nPlatform:\n'
output += ' session tracking: ' + ','.join(session_trackers) + '\n'
output += ' suspend/resume: ' + suspend_resume + '\n'
diff --git a/meson_options.txt b/meson_options.txt
index 42f84711d0..cec0664186 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -7,7 +7,6 @@ option('kernel_firmware_dir', type: 'string', value: '/lib/firmware', descriptio
option('iptables', type: 'string', value: '', description: 'path to iptables')
option('nft', type: 'string', value: '', description: 'path to nft')
option('dnsmasq', type: 'string', value: '', description: 'path to dnsmasq')
-option('dnssec_trigger', type: 'string', value: '', description: 'path to unbound dnssec-trigger-script')
# platform
option('dist_version', type: 'string', value: '', description: 'Define the NM\'s distribution version string')
diff --git a/po/uk.po b/po/uk.po
index 04bfd76314..b93d2f8a27 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -10,8 +10,8 @@ msgstr ""
"Project-Id-Version: NetworkManager\n"
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/NetworkManager/NetworkMan"
"ager/issues\n"
-"POT-Creation-Date: 2022-03-31 15:26+0000\n"
-"PO-Revision-Date: 2022-04-04 11:36+0300\n"
+"POT-Creation-Date: 2022-05-12 15:26+0000\n"
+"PO-Revision-Date: 2022-05-16 08:58+0300\n"
"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
"Language-Team: Ukrainian <kde-i18n-uk@kde.org>\n"
"Language: uk\n"
@@ -193,7 +193,7 @@ msgstr ""
#. * as "Wired Connection" or "VPN Connection". The %d is a number
#. * that is combined with the first argument to create a unique
#. * connection id.
-#: ../src/core/NetworkManagerUtils.c:120
+#: ../src/core/NetworkManagerUtils.c:119
#, c-format
msgctxt "connection id fallback"
msgid "%s %u"
@@ -261,7 +261,7 @@ msgstr "Š—'єŠ“Š½Š°Š½Š½Ń 6LOWPAN"
msgid "Bond connection"
msgstr "ŠŸŃ€ŠøŠ²'яŠ·Š°Š½Šµ Š·'єŠ“Š½Š°Š½Š½Ń"
-#: ../src/core/devices/nm-device-bridge.c:154
+#: ../src/core/devices/nm-device-bridge.c:161
msgid "Bridge connection"
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń Š¼Ń–стŠŗŠ°"
@@ -596,7 +596,7 @@ msgstr ""
msgid "Could not daemonize: %s [error %u]\n"
msgstr "ŠŠµ Š²Š“Š°Š»Š¾ŃŃ стŠ²Š¾Ń€ŠøтŠø фŠ¾Š½Š¾Š²Ńƒ сŠ»ŃƒŠ¶Š±Ńƒ: %s [ŠæŠ¾Š¼ŠøŠ»ŠŗŠ° %u]\n"
-#: ../src/core/nm-config.c:542
+#: ../src/core/nm-config.c:544
#: ../src/libnm-core-impl/nm-setting-ovs-bridge.c:187
#: ../src/libnmc-setting/nm-meta-setting-desc.c:2181
#: ../src/libnmc-setting/nm-meta-setting-desc.c:4242
@@ -604,93 +604,93 @@ msgstr "ŠŠµ Š²Š“Š°Š»Š¾ŃŃ стŠ²Š¾Ń€ŠøтŠø фŠ¾Š½Š¾Š²Ńƒ сŠ»ŃƒŠ¶Š±Ńƒ: %s [ŠæŠ¾
msgid "'%s' is not valid"
msgstr "Ā«%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼"
-#: ../src/core/nm-config.c:564
+#: ../src/core/nm-config.c:566
#, c-format
msgid "Bad '%s' option: "
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ¾Š²ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ»: "
-#: ../src/core/nm-config.c:581
+#: ../src/core/nm-config.c:583
msgid "Config file location"
msgstr "Š Š¾Š·Ń‚Š°ŃˆŃƒŠ²Š°Š½Š½Ń фŠ°Š¹Š»Š° Š½Š°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½ŃŒ"
-#: ../src/core/nm-config.c:588
+#: ../src/core/nm-config.c:590
msgid "Config directory location"
msgstr "Š Š¾Š·Ń‚Š°ŃˆŃƒŠ²Š°Š½Š½Ń ŠŗŠ°Ń‚Š°Š»Š¾Š³Ńƒ Š½Š°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½ŃŒ"
-#: ../src/core/nm-config.c:595
+#: ../src/core/nm-config.c:597
msgid "System config directory location"
msgstr "Š Š¾Š·Ń‚Š°ŃˆŃƒŠ²Š°Š½Š½Ń Š·Š°Š³Š°Š»ŃŒŠ½Š¾ŃŠøстŠµŠ¼Š½Š¾Š³Š¾ ŠŗŠ°Ń‚Š°Š»Š¾Š³Ńƒ Š½Š°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½ŃŒ"
-#: ../src/core/nm-config.c:602
+#: ../src/core/nm-config.c:604
msgid "Internal config file location"
msgstr "Š Š¾Š·Ń‚Š°ŃˆŃƒŠ²Š°Š½Š½Ń Š²Š½ŃƒŃ‚Ń€Ń–ŃˆŠ½ŃŒŠ¾Š³Š¾ фŠ°Š¹Š»Š° Š½Š°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½ŃŒ"
-#: ../src/core/nm-config.c:609
+#: ../src/core/nm-config.c:611
msgid "State file location"
msgstr "Š Š¾Š·Ń‚Š°ŃˆŃƒŠ²Š°Š½Š½Ń фŠ°Š¹Š»Š° стŠ°Š½Ńƒ"
-#: ../src/core/nm-config.c:616
+#: ../src/core/nm-config.c:618
msgid "State file for no-auto-default devices"
msgstr ""
"Š¤Š°Š¹Š» стŠ°Š½Ń–Š² Š“Š»Ń ŠæрŠøстрŠ¾Ń—Š² Š±ŠµŠ· Š°Š²Ń‚Š¾Š¼Š°Ń‚ŠøчŠ½Šøх тŠøŠæŠ¾Š²Šøх ŠæŠ°Ń€Š°Š¼ŠµŃ‚ріŠ² (no-auto-"
"default)"
-#: ../src/core/nm-config.c:623
+#: ../src/core/nm-config.c:625
msgid "List of plugins separated by ','"
msgstr "Š”ŠæŠøсŠ¾Šŗ Š“Š¾Š“Š°Ń‚ŠŗіŠ², Š²Ń–Š“Š¾ŠŗрŠµŠ¼Š»ŠµŠ½Šøх ŠŗŠ¾Š¼Š°Š¼Šø (Ā«,Ā»)"
-#: ../src/core/nm-config.c:630
+#: ../src/core/nm-config.c:632
msgid "Quit after initial configuration"
msgstr "Š’ŠøŠ¹Ń‚Šø ŠæісŠ»Ń ŠæŠ¾Ń‡Š°Ń‚ŠŗŠ¾Š²Š¾Š³Š¾ Š½Š°Š»Š°ŃˆŃ‚Š¾Š²ŃƒŠ²Š°Š½Š½Ń"
-#: ../src/core/nm-config.c:637
+#: ../src/core/nm-config.c:639
msgid "Don't become a daemon, and log to stderr"
msgstr ""
"ŠŠµ ŠæŠµŃ€ŠµŃ…Š¾Š“ŠøтŠø у стŠ°Š½ фŠ¾Š½Š¾Š²Š¾Ń— сŠ»ŃƒŠ¶Š±Šø і Š·Š°ŠæŠøсуŠ²Š°Ń‚Šø ŠæŠ¾Š²Ń–Š“Š¾Š¼Š»ŠµŠ½Š½Ń Š¶ŃƒŃ€Š½Š°Š»Ńƒ Š“Š¾ "
"stderr"
-#: ../src/core/nm-config.c:646
+#: ../src/core/nm-config.c:648
msgid "An http(s) address for checking internet connectivity"
msgstr "ŠŠ“рŠµŃŠ° http(s) Š“Š»Ń сŠæрŠ¾Š± ŠæŠµŃ€ŠµŠ²Ń–Ń€ŠŗŠø Š¼Š¾Š¶Š»ŠøŠ²Š¾ŃŃ‚Ń– Š²ŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½Š½Ń Š·'єŠ“Š½Š°Š½Š½Ń"
-#: ../src/core/nm-config.c:653
+#: ../src/core/nm-config.c:655
msgid "The interval between connectivity checks (in seconds)"
msgstr "Š†Š½Ń‚ŠµŃ€Š²Š°Š» Š¼Ń–Š¶ ŠæŠµŃ€ŠµŠ²Ń–Ń€ŠŗŠ°Š¼Šø Š¼Š¾Š¶Š»ŠøŠ²Š¾ŃŃ‚Ń– Š·'єŠ“Š½Š°Š½Š½Ń (у сŠµŠŗуŠ½Š“Š°Ń…)"
-#: ../src/core/nm-config.c:660
+#: ../src/core/nm-config.c:662
msgid "The expected start of the response"
msgstr "ŠžŃ‡Ń–ŠŗуŠ²Š°Š½ŠøŠ¹ ŠæŠ¾Ń‡Š°Ń‚Š¾Šŗ Š²Ń–Š“ŠæŠ¾Š²Ń–Š“і"
-#: ../src/core/nm-config.c:669
+#: ../src/core/nm-config.c:671
msgid "NetworkManager options"
msgstr "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Šø NetworkManager"
-#: ../src/core/nm-config.c:670
+#: ../src/core/nm-config.c:672
msgid "Show NetworkManager options"
msgstr "ŠŸŠ¾ŠŗŠ°Š·Š°Ń‚Šø ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Šø NetworkManager"
-#: ../src/core/nm-manager.c:6121
+#: ../src/core/nm-manager.c:6146
#: ../src/libnmc-setting/nm-meta-setting-desc.c:8243
msgid "VPN connection"
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń VPN"
#: ../src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c:5545
#: ../src/libnm-client-impl/nm-device.c:1779
-#: ../src/libnm-core-impl/nm-connection.c:3111
+#: ../src/libnm-core-impl/nm-connection.c:3172
#: ../src/nmtui/nm-editor-utils.c:196
msgid "Bond"
msgstr "ŠŸŃ€ŠøŠ²'яŠ·ŠŗŠ°"
#: ../src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c:5616
#: ../src/libnm-client-impl/nm-device.c:1781
-#: ../src/libnm-core-impl/nm-connection.c:3113
+#: ../src/libnm-core-impl/nm-connection.c:3174
#: ../src/nmtui/nm-editor-utils.c:214
msgid "Team"
msgstr "ŠšŠ¾Š¼Š°Š½Š“Š°"
#: ../src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c:5953
#: ../src/libnm-client-impl/nm-device.c:1783
-#: ../src/libnm-core-impl/nm-connection.c:3115
+#: ../src/libnm-core-impl/nm-connection.c:3176
#: ../src/nmtui/nm-editor-utils.c:205
msgid "Bridge"
msgstr "ŠœŃ–стŠ¾Šŗ"
@@ -823,7 +823,7 @@ msgstr "Š—'єŠ“Š½Š°Š½Š½Ń Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ Š¼Š¾Š“ŠµŠ¼Š½ŠøŠ¼ Š·'єŠ“Š½Š
msgid "The device is lacking capabilities required by the connection."
msgstr "Š£ ŠæрŠøстрŠ¾ŃŽ Š½ŠµŠ¼Š°Ń” Š¼Š¾Š¶Š»ŠøŠ²Š¾ŃŃ‚ŠµŠ¹, ŠæŠ¾Ń‚ріŠ±Š½Šøх Š·'єŠ“Š½Š°Š½Š½ŃŽ."
-#: ../src/libnm-client-impl/nm-device-olpc-mesh.c:102
+#: ../src/libnm-client-impl/nm-device-olpc-mesh.c:103
msgid "The connection was not an OLPC Mesh connection."
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń Š½Šµ є Š·'єŠ“Š½Š°Š½Š½ŃŠ¼ OLPC Mesh."
@@ -936,13 +936,13 @@ msgid "Mobile Broadband"
msgstr "ŠœŠ¾Š±Ń–Š»ŃŒŠ½Š° рŠ°Š“іŠ¾Š¼ŠµŃ€ŠµŠ¶Š°"
#: ../src/libnm-client-impl/nm-device.c:1777
-#: ../src/libnm-core-impl/nm-connection.c:3119
+#: ../src/libnm-core-impl/nm-connection.c:3180
#: ../src/nmtui/nm-editor-utils.c:169
msgid "InfiniBand"
msgstr "InfiniBand"
#: ../src/libnm-client-impl/nm-device.c:1785
-#: ../src/libnm-core-impl/nm-connection.c:3117
+#: ../src/libnm-core-impl/nm-connection.c:3178
#: ../src/nmtui/nm-editor-utils.c:223 ../src/nmtui/nmt-page-vlan.c:57
msgid "VLAN"
msgstr "VLAN"
@@ -992,7 +992,7 @@ msgid "6LoWPAN"
msgstr "6LoWPAN"
#: ../src/libnm-client-impl/nm-device.c:1809
-#: ../src/libnm-core-impl/nm-connection.c:3125
+#: ../src/libnm-core-impl/nm-connection.c:3186
#: ../src/nmtui/nm-editor-utils.c:263 ../src/nmtui/nmt-page-wireguard.c:57
msgid "WireGuard"
msgstr "WireGuard"
@@ -1138,36 +1138,36 @@ msgstr "Š¼Ń–стŠøть UUID, яŠŗŠøŠ¹ ŠæŠ¾Ń‚Ń€ŠµŠ±ŃƒŃ” Š½Š¾Ń€Š¼Š°Š»Ń–Š·Š°Ń†Ń–Ń—"
msgid "has duplicate UUIDs"
msgstr "Š¼Ń–стŠøть Š“уŠ±Š»Ń–ŠŗŠ°Ń‚Šø UUID"
-#: ../src/libnm-core-impl/nm-connection.c:1745
+#: ../src/libnm-core-impl/nm-connection.c:1805
msgid "setting not found"
msgstr "ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Š½Šµ Š·Š½Š°Š¹Š“ŠµŠ½Š¾"
-#: ../src/libnm-core-impl/nm-connection.c:1799
-#: ../src/libnm-core-impl/nm-connection.c:1824
-#: ../src/libnm-core-impl/nm-connection.c:1849
+#: ../src/libnm-core-impl/nm-connection.c:1859
+#: ../src/libnm-core-impl/nm-connection.c:1884
+#: ../src/libnm-core-impl/nm-connection.c:1909
msgid "setting is required for non-slave connections"
msgstr "Š“Š»Ń Š½ŠµŠæіŠ“Š»ŠµŠ³Š»Šøх Š·'єŠ“Š½Š°Š½ŃŒ ŠæŠ¾Ń‚ріŠ±ŠµŠ½ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€"
-#: ../src/libnm-core-impl/nm-connection.c:1812
-#: ../src/libnm-core-impl/nm-connection.c:1837
-#: ../src/libnm-core-impl/nm-connection.c:1862
+#: ../src/libnm-core-impl/nm-connection.c:1872
+#: ../src/libnm-core-impl/nm-connection.c:1897
+#: ../src/libnm-core-impl/nm-connection.c:1922
msgid "setting not allowed in slave connection"
msgstr "ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾Ń€ŠøстŠ¾Š²ŃƒŠ²Š°Ń‚Šø у ŠæіŠ“Š»ŠµŠ³Š»Š¾Š¼Ńƒ Š·'єŠ“Š½Š°Š½Š½Ń–"
-#: ../src/libnm-core-impl/nm-connection.c:1971
+#: ../src/libnm-core-impl/nm-connection.c:2032
msgid "Unexpected failure to normalize the connection"
msgstr "ŠŠµŠ¾Ń‡Ń–ŠŗуŠ²Š°Š½Š° ŠæŠ¾Š¼ŠøŠ»ŠŗŠ° ŠæіŠ“ чŠ°Ń сŠæрŠ¾Š±Šø Š½Š¾Ń€Š¼Š°Š»Ń–Š·ŃƒŠ²Š°Ń‚Šø Š·'єŠ“Š½Š°Š½Š½Ń"
-#: ../src/libnm-core-impl/nm-connection.c:2032
+#: ../src/libnm-core-impl/nm-connection.c:2093
msgid "Unexpected failure to verify the connection"
msgstr "ŠŠµŠ¾Ń‡Ń–ŠŗуŠ²Š°Š½Š° ŠæŠ¾Š¼ŠøŠ»ŠŗŠ° ŠæіŠ“ чŠ°Ń сŠæрŠ¾Š±Šø ŠæŠµŃ€ŠµŠ²Ń–Ń€ŠøтŠø Š·'єŠ“Š½Š°Š½Š½Ń"
-#: ../src/libnm-core-impl/nm-connection.c:2069
+#: ../src/libnm-core-impl/nm-connection.c:2130
#, c-format
msgid "unexpected uuid %s instead of %s"
msgstr "Š½ŠµŠ¾Ń‡Ń–ŠŗуŠ²Š°Š½ŠøŠ¹ UUID %s Š·Š°Š¼Ń–ŃŃ‚ŃŒ %s"
-#: ../src/libnm-core-impl/nm-connection.c:2970
+#: ../src/libnm-core-impl/nm-connection.c:3031
#: ../src/libnm-core-impl/nm-setting-8021x.c:2607
#: ../src/libnm-core-impl/nm-setting-8021x.c:2644
#: ../src/libnm-core-impl/nm-setting-8021x.c:2662
@@ -1193,10 +1193,14 @@ msgstr "Š½ŠµŠ¾Ń‡Ń–ŠŗуŠ²Š°Š½ŠøŠ¹ UUID %s Š·Š°Š¼Ń–ŃŃ‚ŃŒ %s"
msgid "property is missing"
msgstr "Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń–"
-#: ../src/libnm-core-impl/nm-connection.c:3123
+#: ../src/libnm-core-impl/nm-connection.c:3184
msgid "IP Tunnel"
msgstr "IP-туŠ½ŠµŠ»ŃŒ"
+#: ../src/libnm-core-impl/nm-connection.c:3188
+msgid "TUN/TAP"
+msgstr "TUN/TAP"
+
#: ../src/libnm-core-impl/nm-dbus-utils.c:181
#, c-format
msgid "Method returned type '%s', but expected '%s'"
@@ -1212,239 +1216,239 @@ msgstr "Š—Š½Š°Ń‡ŠµŠ½Š½Ń Š½Šµ Š¼Š¾Š¶Šµ Š±ŃƒŃ‚Šø Š¾Š±Ń€Š¾Š±Š»ŠµŠ½Š¾ яŠŗ сŠæŠøс
msgid "value is not an integer in range [%lld, %lld]"
msgstr "Š·Š½Š°Ń‡ŠµŠ½Š½Ń Š½Šµ є ціŠ»ŠøŠ¼ чŠøсŠ»Š¾Š¼ у Š“іŠ°ŠæŠ°Š·Š¾Š½Ń– [%lld, %lld]"
-#: ../src/libnm-core-impl/nm-keyfile.c:332
+#: ../src/libnm-core-impl/nm-keyfile.c:331
msgid "ignoring missing number"
msgstr "іŠ³Š½Š¾Ń€ŃƒŃ”Š¼Š¾ ŠæрŠ¾ŠæущŠµŠ½Šµ чŠøсŠ»Š¾"
-#: ../src/libnm-core-impl/nm-keyfile.c:344
+#: ../src/libnm-core-impl/nm-keyfile.c:343
#, c-format
msgid "ignoring invalid number '%s'"
msgstr "іŠ³Š½Š¾Ń€ŃƒŃ”Š¼Š¾ Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ чŠøсŠ»Š¾ Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-keyfile.c:373
+#: ../src/libnm-core-impl/nm-keyfile.c:372
#, c-format
msgid "ignoring invalid %s address: %s"
msgstr "іŠ³Š½Š¾Ń€ŃƒŃ”Š¼Š¾ Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Ńƒ Š°Š“рŠµŃŃƒ %s: %s"
-#: ../src/libnm-core-impl/nm-keyfile.c:419
+#: ../src/libnm-core-impl/nm-keyfile.c:418
#, c-format
msgid "ignoring invalid gateway '%s' for %s route"
msgstr "іŠ³Š½Š¾Ń€ŃƒŃ”Š¼Š¾ Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ шŠ»ŃŽŠ· Ā«%sĀ» Š“Š»Ń Š¼Š°Ń€ŃˆŃ€ŃƒŃ‚Ńƒ %s"
-#: ../src/libnm-core-impl/nm-keyfile.c:441
+#: ../src/libnm-core-impl/nm-keyfile.c:440
#, c-format
msgid "ignoring invalid %s route: %s"
msgstr "іŠ³Š½Š¾Ń€ŃƒŃ”Š¼Š¾ Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ Š¼Š°Ń€ŃˆŃ€ŃƒŃ‚ %s: %s"
-#: ../src/libnm-core-impl/nm-keyfile.c:619
+#: ../src/libnm-core-impl/nm-keyfile.c:618
#, c-format
msgid "unexpected character '%c' for address %s: '%s' (position %td)"
msgstr "Š½ŠµŠ¾Ń‡Ń–ŠŗуŠ²Š°Š½ŠøŠ¹ сŠøŠ¼Š²Š¾Š» Ā«%cĀ» Š“Š»Ń Š°Š“рŠµŃŠø %s: Ā«%sĀ» (ŠæŠ¾Š·Šøція %td)"
-#: ../src/libnm-core-impl/nm-keyfile.c:635
+#: ../src/libnm-core-impl/nm-keyfile.c:634
#, c-format
msgid "unexpected character '%c' for %s: '%s' (position %td)"
msgstr "Š½ŠµŠ¾Ń‡Ń–ŠŗуŠ²Š°Š½ŠøŠ¹ сŠøŠ¼Š²Š¾Š» Ā«%cĀ» Š“Š»Ń %s: Ā«%sĀ» (ŠæŠ¾Š·Šøція %td)"
-#: ../src/libnm-core-impl/nm-keyfile.c:651
+#: ../src/libnm-core-impl/nm-keyfile.c:650
#, c-format
msgid "unexpected character '%c' in prefix length for %s: '%s' (position %td)"
msgstr "Š½ŠµŠ¾Ń‡Ń–ŠŗуŠ²Š°Š½ŠøŠ¹ сŠøŠ¼Š²Š¾Š» Ā«%cĀ» у ŠæрŠµŃ„Ń–Šŗсі Š“Š¾Š²Š¶ŠøŠ½Šø Š“Š»Ń %s: Ā«%sĀ» (ŠæŠ¾Š·Šøція %td)"
-#: ../src/libnm-core-impl/nm-keyfile.c:668
+#: ../src/libnm-core-impl/nm-keyfile.c:667
#, c-format
msgid "garbage at the end of value %s: '%s'"
msgstr "Š·Š°Š¹Š²Ń– Š“Š°Š½Ń– Š½Š°ŠæрŠøŠŗіŠ½Ń†Ń– Š·Š½Š°Ń‡ŠµŠ½Š½Ń %s: Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-keyfile.c:678
+#: ../src/libnm-core-impl/nm-keyfile.c:677
#, c-format
msgid "deprecated semicolon at the end of value %s: '%s'"
msgstr "Š·Š°ŃŃ‚Š°Ń€Ń–Š»Š° ŠŗрŠ°ŠæŠŗŠ° Š· ŠŗŠ¾Š¼Š¾ŃŽ Š½Š°ŠæрŠøŠŗіŠ½Ń†Ń– Š·Š½Š°Ń‡ŠµŠ½Š½Ń %s: Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-keyfile.c:697
+#: ../src/libnm-core-impl/nm-keyfile.c:696
#, c-format
msgid "invalid prefix length for %s '%s', defaulting to %d"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ ŠæрŠµŃ„Ń–Šŗс Š“Š¾Š²Š¶ŠøŠ½Šø Š“Š»Ń %s Ā«%sĀ», ŠæŠ¾Š²ŠµŃ€Ń‚Š°Ń”Š¼Š¾ŃŃ Š“Š¾ тŠøŠæŠ¾Š²Š¾Š³Š¾, %d"
-#: ../src/libnm-core-impl/nm-keyfile.c:709
+#: ../src/libnm-core-impl/nm-keyfile.c:708
#, c-format
msgid "missing prefix length for %s '%s', defaulting to %d"
msgstr "ŠæрŠ¾ŠæущŠµŠ½Š¾ ŠæрŠµŃ„Ń–Šŗс Š“Š¾Š²Š¶ŠøŠ½Šø Š“Š»Ń %s Ā«%sĀ», ŠæŠ¾Š²ŠµŃ€Ń‚Š°Ń”Š¼Š¾ŃŃ Š“Š¾ тŠøŠæŠ¾Š²Š¾Š³Š¾, %d"
-#: ../src/libnm-core-impl/nm-keyfile.c:1052
+#: ../src/libnm-core-impl/nm-keyfile.c:1051
#: ../src/libnm-core-impl/nm-setting-ovs-external-ids.c:320
#: ../src/libnm-core-impl/nm-setting-user.c:364
#, c-format
msgid "invalid value for \"%s\": %s"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń Š“Š»Ń Ā«%sĀ»: %s"
-#: ../src/libnm-core-impl/nm-keyfile.c:1130
+#: ../src/libnm-core-impl/nm-keyfile.c:1129
#, c-format
msgid "ignoring invalid DNS server IPv%c address '%s'"
msgstr "іŠ³Š½Š¾Ń€ŃƒŃ”Š¼Š¾ Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Ńƒ Š°Š“рŠµŃŃƒ IPv%c сŠµŃ€Š²ŠµŃ€Š° DNS Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-keyfile.c:1167
+#: ../src/libnm-core-impl/nm-keyfile.c:1166
#: ../src/libnmc-setting/nm-meta-setting-desc.c:1666
#, c-format
msgid "invalid option '%s', use one of [%s]"
msgstr ""
"Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ», сŠŗŠ¾Ń€ŠøстŠ°Š¹Ń‚ŠµŃŃ Š¾Š“Š½ŠøŠ¼ іŠ· тŠ°ŠŗŠøх ŠæŠ°Ń€Š°Š¼ŠµŃ‚ріŠ² [%s]"
-#: ../src/libnm-core-impl/nm-keyfile.c:1229
+#: ../src/libnm-core-impl/nm-keyfile.c:1228
msgid "ignoring invalid MAC address"
msgstr "іŠ³Š½Š¾Ń€ŃƒŃ”Š¼Š¾ Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Ńƒ MAC-Š°Š“рŠµŃŃƒ"
-#: ../src/libnm-core-impl/nm-keyfile.c:1305
+#: ../src/libnm-core-impl/nm-keyfile.c:1304
#, c-format
msgid "ignoring invalid bond option %s%s%s = %s%s%s: %s"
msgstr "іŠ³Š½Š¾Ń€ŃƒŃ”Š¼Š¾ Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ bond %s%s%s = %s%s%s: %s"
-#: ../src/libnm-core-impl/nm-keyfile.c:1495
+#: ../src/libnm-core-impl/nm-keyfile.c:1494
msgid "ignoring invalid SSID"
msgstr "іŠ³Š½Š¾Ń€ŃƒŃ”Š¼Š¾ Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ SSID"
-#: ../src/libnm-core-impl/nm-keyfile.c:1513
+#: ../src/libnm-core-impl/nm-keyfile.c:1512
msgid "ignoring invalid raw password"
msgstr "іŠ³Š½Š¾Ń€ŃƒŃ”Š¼Š¾ Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ Š½ŠµŠ¾Š±Ń€Š¾Š±Š»ŠµŠ½ŠøŠ¹ ŠæŠ°Ń€Š¾Š»ŃŒ"
-#: ../src/libnm-core-impl/nm-keyfile.c:1658
+#: ../src/libnm-core-impl/nm-keyfile.c:1657
msgid "invalid key/cert value"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠŗŠ»ŃŽŃ‡Š°/сŠµŃ€Ń‚ŠøфіŠŗŠ°Ń‚Š°"
-#: ../src/libnm-core-impl/nm-keyfile.c:1673
+#: ../src/libnm-core-impl/nm-keyfile.c:1672
#, c-format
msgid "invalid key/cert value path \"%s\""
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ шŠ»ŃŃ… Š“Š¾ ŠŗŠ»ŃŽŃ‡Š°/сŠµŃ€Ń‚ŠøфіŠŗŠ°Ń‚Š°, Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-keyfile.c:1698
-#: ../src/libnm-core-impl/nm-keyfile.c:1795
+#: ../src/libnm-core-impl/nm-keyfile.c:1697
+#: ../src/libnm-core-impl/nm-keyfile.c:1794
#, c-format
msgid "certificate or key file '%s' does not exist"
msgstr "фŠ°Š¹Š»Š° сŠµŃ€Ń‚ŠøфіŠŗŠ°Ń‚Š° Š°Š±Š¾ ŠŗŠ»ŃŽŃ‡Š° Ā«%sĀ» Š½Šµ ісŠ½ŃƒŃ”"
-#: ../src/libnm-core-impl/nm-keyfile.c:1711
+#: ../src/libnm-core-impl/nm-keyfile.c:1710
#, c-format
msgid "invalid PKCS#11 URI \"%s\""
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Š° Š°Š“рŠµŃŠ° PKCS#11 Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-keyfile.c:1757
+#: ../src/libnm-core-impl/nm-keyfile.c:1756
msgid "invalid key/cert value data:;base64, is not base64"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Ń– Š“Š°Š½Ń– Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠŗŠ»ŃŽŃ‡Š°/сŠµŃ€Ń‚ŠøфіŠŗŠ°Ń‚Š° data:;base64, Š½Šµ є base64"
-#: ../src/libnm-core-impl/nm-keyfile.c:1770
+#: ../src/libnm-core-impl/nm-keyfile.c:1769
msgid "invalid key/cert value data:;base64,file://"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠŗŠ»ŃŽŃ‡Š°/сŠµŃ€Ń‚ŠøфіŠŗŠ°Ń‚Š° data:;base64,file://"
-#: ../src/libnm-core-impl/nm-keyfile.c:1811
+#: ../src/libnm-core-impl/nm-keyfile.c:1810
msgid "invalid key/cert value is not a valid blob"
msgstr ""
"Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠŗŠ»ŃŽŃ‡Š°/сŠµŃ€Ń‚ŠøфіŠŗŠ°Ń‚Š°, Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«%sĀ» Š½Šµ є "
"ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ Š²ŠµŠ»ŠøŠŗŠøŠ¼ Š±Ń–Š½Š°Ń€Š½ŠøŠ¼ Š¾Š±'єŠŗтŠ¾Š¼"
-#: ../src/libnm-core-impl/nm-keyfile.c:1913
+#: ../src/libnm-core-impl/nm-keyfile.c:1912
#, c-format
msgid "invalid parity value '%s'"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠæŠ°Ń€Š½Š¾ŃŃ‚Ń–, Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-keyfile.c:1935
-#: ../src/libnm-core-impl/nm-keyfile.c:3427
+#: ../src/libnm-core-impl/nm-keyfile.c:1934
+#: ../src/libnm-core-impl/nm-keyfile.c:3426
#, c-format
msgid "invalid setting: %s"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€: %s"
-#: ../src/libnm-core-impl/nm-keyfile.c:1955
+#: ../src/libnm-core-impl/nm-keyfile.c:1954
#, c-format
msgid "ignoring invalid team configuration: %s"
msgstr "іŠ³Š½Š¾Ń€ŃƒŃ”Š¼Š¾ Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š½Š°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½Š½Ń ŠŗŠ¾Š¼Š°Š½Š“Šø: %s"
-#: ../src/libnm-core-impl/nm-keyfile.c:2038
+#: ../src/libnm-core-impl/nm-keyfile.c:2037
#, c-format
msgid "invalid qdisc: %s"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ qdisc: %s"
-#: ../src/libnm-core-impl/nm-keyfile.c:2088
+#: ../src/libnm-core-impl/nm-keyfile.c:2087
#, c-format
msgid "invalid tfilter: %s"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ tfilter: %s"
-#: ../src/libnm-core-impl/nm-keyfile.c:3252
+#: ../src/libnm-core-impl/nm-keyfile.c:3251
#, c-format
msgid "error loading setting value: %s"
msgstr "ŠæŠ¾Š¼ŠøŠ»ŠŗŠ° ŠæіŠ“ чŠ°Ń Š·Š°Š²Š°Š½Ń‚Š°Š¶ŠµŠ½Š½Ń Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š°: %s"
-#: ../src/libnm-core-impl/nm-keyfile.c:3283
-#: ../src/libnm-core-impl/nm-keyfile.c:3295
-#: ../src/libnm-core-impl/nm-keyfile.c:3314
-#: ../src/libnm-core-impl/nm-keyfile.c:3326
-#: ../src/libnm-core-impl/nm-keyfile.c:3338
-#: ../src/libnm-core-impl/nm-keyfile.c:3400
-#: ../src/libnm-core-impl/nm-keyfile.c:3412
+#: ../src/libnm-core-impl/nm-keyfile.c:3282
+#: ../src/libnm-core-impl/nm-keyfile.c:3294
+#: ../src/libnm-core-impl/nm-keyfile.c:3313
+#: ../src/libnm-core-impl/nm-keyfile.c:3325
+#: ../src/libnm-core-impl/nm-keyfile.c:3337
+#: ../src/libnm-core-impl/nm-keyfile.c:3399
+#: ../src/libnm-core-impl/nm-keyfile.c:3411
msgid "value cannot be interpreted as integer"
msgstr "Š·Š½Š°Ń‡ŠµŠ½Š½Ń Š½Šµ Š¼Š¾Š¶Šµ Š±ŃƒŃ‚Šø Š¾Š±Ń€Š¾Š±Š»ŠµŠ½Š¾ яŠŗ ціŠ»Šµ чŠøсŠ»Š¾"
-#: ../src/libnm-core-impl/nm-keyfile.c:3368
+#: ../src/libnm-core-impl/nm-keyfile.c:3367
#, c-format
msgid "ignoring invalid byte element '%u' (not between 0 and 255 inclusive)"
msgstr ""
"іŠ³Š½Š¾Ń€ŃƒŃ”Š¼Š¾ Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ Š±Š°Š¹Ń‚Š¾Š²ŠøŠ¹ ŠµŠ»ŠµŠ¼ŠµŠ½Ń‚ Ā«%uĀ» (Š½Šµ у Š“іŠ°ŠæŠ°Š·Š¾Š½Ń– Š²Ń–Š“ 0 Š“Š¾ 255, "
"Š²ŠŗŠ»ŃŽŃ‡Š½Š¾)"
-#: ../src/libnm-core-impl/nm-keyfile.c:3452
+#: ../src/libnm-core-impl/nm-keyfile.c:3451
#, c-format
msgid "invalid setting name '%s'"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Š° Š½Š°Š·Š²Š° ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š°, Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-keyfile.c:3499
+#: ../src/libnm-core-impl/nm-keyfile.c:3498
#, c-format
msgid "invalid key '%s.%s'"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ ŠŗŠ»ŃŽŃ‡ Ā«%s.%sĀ»"
-#: ../src/libnm-core-impl/nm-keyfile.c:3515
+#: ../src/libnm-core-impl/nm-keyfile.c:3514
#, c-format
msgid "key '%s.%s' is not boolean"
msgstr "ŠŗŠ»ŃŽŃ‡ Ā«%s.%sĀ» Š½Šµ є Š±ŃƒŠ»ŠµŠ²ŠøŠ¼ Š·Š½Š°Ń‡ŠµŠ½Š½ŃŠ¼"
-#: ../src/libnm-core-impl/nm-keyfile.c:3532
+#: ../src/libnm-core-impl/nm-keyfile.c:3531
#, c-format
msgid "key '%s.%s' is not a uint32"
msgstr "ŠŗŠ»ŃŽŃ‡ Ā«%s.%sĀ» Š½Šµ є Š·Š½Š°Ń‡ŠµŠ½Š½ŃŠ¼ uint32"
-#: ../src/libnm-core-impl/nm-keyfile.c:3589
+#: ../src/libnm-core-impl/nm-keyfile.c:3588
#, c-format
msgid "invalid peer public key in section '%s'"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ Š²Ń–Š“ŠŗрŠøтŠøŠ¹ ŠŗŠ»ŃŽŃ‡ Š²ŃƒŠ·Š»Š° у рŠ¾Š·Š“іŠ»Ń– Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-keyfile.c:3604
+#: ../src/libnm-core-impl/nm-keyfile.c:3603
#, c-format
msgid "key '%s.%s' is not a valid 256 bit key in base64 encoding"
msgstr "ŠŗŠ»ŃŽŃ‡ Ā«%s.%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ 256-Š±Ń–Ń‚Š¾Š²ŠøŠ¼ ŠŗŠ»ŃŽŃ‡ŠµŠ¼ у ŠŗŠ¾Š“уŠ²Š°Š½Š½Ń– base64"
-#: ../src/libnm-core-impl/nm-keyfile.c:3627
+#: ../src/libnm-core-impl/nm-keyfile.c:3626
#, c-format
msgid "key '%s.%s' is not a valid secret flag"
msgstr "ŠŗŠ»ŃŽŃ‡ Ā«%s.%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ ŠæрŠ°ŠæŠ¾Ń€Ń†ŠµŠ¼ рŠµŃ”стрŠ°Ń†Ń–Š¹Š½Šøх Š“Š°Š½Šøх"
-#: ../src/libnm-core-impl/nm-keyfile.c:3650
+#: ../src/libnm-core-impl/nm-keyfile.c:3649
#, c-format
msgid "key '%s.%s' is not a integer in range 0 to 2^32"
msgstr "ŠŗŠ»ŃŽŃ‡ Ā«%s.%sĀ» Š½Šµ є ціŠ»ŠøŠ¼Šø чŠøсŠ»Š¾Š¼ у Š“іŠ°ŠæŠ°Š·Š¾Š½Ń– Š²Ń–Š“ 0 Š“Š¾ 2^32"
-#: ../src/libnm-core-impl/nm-keyfile.c:3666
+#: ../src/libnm-core-impl/nm-keyfile.c:3665
#, c-format
msgid "key '%s.%s' is not a valid endpoint"
msgstr "ŠŗŠ»ŃŽŃ‡ Ā«%s.%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½Š¾ŃŽ ŠŗіŠ½Ń†ŠµŠ²Š¾ŃŽ тŠ¾Ń‡ŠŗŠ¾ŃŽ"
-#: ../src/libnm-core-impl/nm-keyfile.c:3692
+#: ../src/libnm-core-impl/nm-keyfile.c:3691
#, c-format
msgid "key '%s.%s' has invalid allowed-ips"
msgstr "Š“Š»Ń ŠŗŠ»ŃŽŃ‡Š° Ā«%s.%sĀ» Š²ŠŗŠ°Š·Š°Š½Š¾ Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń allowed-ips"
-#: ../src/libnm-core-impl/nm-keyfile.c:3707
+#: ../src/libnm-core-impl/nm-keyfile.c:3706
#, c-format
msgid "peer '%s' is invalid: %s"
msgstr "Š²ŃƒŠ·Š¾Š» Ā«%sĀ» є Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼: %s"
-#: ../src/libnm-core-impl/nm-keyfile.c:4235
+#: ../src/libnm-core-impl/nm-keyfile.c:4234
#, c-format
msgid "unsupported option \"%s.%s\" of variant type %s"
msgstr "Š½ŠµŠæіŠ“трŠøŠ¼ŃƒŠ²Š°Š½ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%s.%sĀ» тŠøŠæу Š²Š°Ń€Ń–Š°Š½Ń‚Š° %s"
@@ -1518,9 +1522,16 @@ msgstr ""
"ŠæіŠ“трŠøŠ¼ŠŗŠø ŠæŠ°Ń€Š¾Š»Ń–Š² Š½Šµ ŠæŠµŃ€ŠµŠ“Š±Š°Ń‡ŠµŠ½Š¾, яŠŗщŠ¾ сŠµŃ€Ń‚ŠøфіŠŗŠ°Ń‚ Š½Šµ Š¼Ń–стŠøться у ŠŗŠ»ŃŽŃ‡Ń– "
"PKCS#11"
+#. normalizable warnings from here on.
#: ../src/libnm-core-impl/nm-setting-8021x.c:2612
#: ../src/libnm-core-impl/nm-setting-8021x.c:2652
#: ../src/libnm-core-impl/nm-setting-8021x.c:2671
+#: ../src/libnm-core-impl/nm-setting-8021x.c:2838
+#: ../src/libnm-core-impl/nm-setting-8021x.c:2858
+#: ../src/libnm-core-impl/nm-setting-8021x.c:2878
+#: ../src/libnm-core-impl/nm-setting-8021x.c:2919
+#: ../src/libnm-core-impl/nm-setting-8021x.c:2939
+#: ../src/libnm-core-impl/nm-setting-8021x.c:2995
#: ../src/libnm-core-impl/nm-setting-adsl.c:181
#: ../src/libnm-core-impl/nm-setting-cdma.c:149
#: ../src/libnm-core-impl/nm-setting-cdma.c:159
@@ -1542,6 +1553,7 @@ msgstr ""
#: ../src/libnm-core-impl/nm-setting-wireless-security.c:972
#: ../src/libnm-core-impl/nm-setting-wireless-security.c:1000
#: ../src/libnm-core-impl/nm-setting.c:2396
+#, c-format
msgid "property is empty"
msgstr "Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ є ŠæŠ¾Ń€Š¾Š¶Š½ŃŒŠ¾ŃŽ"
@@ -1582,15 +1594,15 @@ msgstr "Š¼Š¾Š¶Š½Š° Š²Š¼ŠøŠŗŠ°Ń‚Šø Š»ŠøшŠµ Š“Š»Ń Š·'єŠ“Š½Š°Š½ŃŒ Ethernet"
#: ../src/libnm-core-impl/nm-setting-wireless.c:945
#: ../src/libnm-core-impl/nm-setting-wireless.c:958
#: ../src/libnm-core-impl/nm-setting-wpan.c:161
-#: ../src/libnm-core-impl/nm-utils.c:4152
+#: ../src/libnm-core-impl/nm-utils.c:4151
msgid "property is invalid"
msgstr "Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ є Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Š¾ŃŽ"
-#: ../src/libnm-core-impl/nm-setting-8021x.c:2831
-#: ../src/libnm-core-impl/nm-setting-8021x.c:2844
-#: ../src/libnm-core-impl/nm-setting-8021x.c:2857
-#: ../src/libnm-core-impl/nm-setting-8021x.c:2891
-#: ../src/libnm-core-impl/nm-setting-8021x.c:2904
+#: ../src/libnm-core-impl/nm-setting-8021x.c:2832
+#: ../src/libnm-core-impl/nm-setting-8021x.c:2852
+#: ../src/libnm-core-impl/nm-setting-8021x.c:2872
+#: ../src/libnm-core-impl/nm-setting-8021x.c:2913
+#: ../src/libnm-core-impl/nm-setting-8021x.c:2933
#: ../src/libnm-core-impl/nm-setting-adsl.c:193
#: ../src/libnm-core-impl/nm-setting-adsl.c:206
#: ../src/libnm-core-impl/nm-setting-bluetooth.c:145
@@ -1599,7 +1611,7 @@ msgstr "Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ є Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Š¾ŃŽ"
msgid "'%s' is not a valid value for the property"
msgstr "Ā«%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ Š·Š½Š°Ń‡ŠµŠ½Š½ŃŠ¼ Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń–"
-#: ../src/libnm-core-impl/nm-setting-8021x.c:2870
+#: ../src/libnm-core-impl/nm-setting-8021x.c:2891
msgid "invalid auth flags"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Ń– ŠæрŠ°ŠæŠ¾Ń€Ń†Ń– рŠ¾Š·ŠæіŠ·Š½Š°Š²Š°Š½Š½Ń"
@@ -1629,95 +1641,95 @@ msgid "A connection with a '%s' setting must have the slave-type set to '%s'"
msgstr ""
"Š”Š»Ń Š·'єŠ“Š½Š°Š½Š½Ń Š· ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š¾Š¼ Ā«%sĀ» Š¼Š°Ń” Š±ŃƒŃ‚Šø Š²ŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½Š¾ тŠøŠæ ŠæіŠ“Š»ŠµŠ³Š»Š¾ŃŃ‚Ń– Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-setting-bond.c:513
+#: ../src/libnm-core-impl/nm-setting-bond.c:504
#, c-format
msgid "'%s' option is empty"
msgstr "ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ» є ŠæŠ¾Ń€Š¾Š¶Š½Ń–Š¼"
-#: ../src/libnm-core-impl/nm-setting-bond.c:522
+#: ../src/libnm-core-impl/nm-setting-bond.c:513
#, c-format
msgid "'%s' is not a valid IPv4 address for '%s' option"
msgstr "Ā«%sĀ» Š½Šµ є ŠæрŠøŠæустŠøŠ¼Š¾ŃŽ Š°Š“рŠµŃŠ¾ŃŽ IPv4 Š“Š»Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-setting-bond.c:549
+#: ../src/libnm-core-impl/nm-setting-bond.c:540
#, c-format
msgid "missing option name"
msgstr "Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š½Š°Š·Š²Šø ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š°"
-#: ../src/libnm-core-impl/nm-setting-bond.c:554
+#: ../src/libnm-core-impl/nm-setting-bond.c:545
#, c-format
msgid "invalid option '%s'"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-setting-bond.c:590
+#: ../src/libnm-core-impl/nm-setting-bond.c:581
#, c-format
msgid "invalid value '%s' for option '%s'"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«%sĀ» Š“Š»Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-setting-bond.c:837
+#: ../src/libnm-core-impl/nm-setting-bond.c:828
#, c-format
msgid "mandatory option '%s' is missing"
msgstr "ŠæрŠ¾ŠæущŠµŠ½Š¾ Š¾Š±Š¾Š²'яŠ·ŠŗŠ¾Š²ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-setting-bond.c:847
+#: ../src/libnm-core-impl/nm-setting-bond.c:838
#, c-format
msgid "'%s' is not a valid value for '%s'"
msgstr "Ā«%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ Š·Š½Š°Ń‡ŠµŠ½Š½ŃŠ¼ Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-setting-bond.c:860
+#: ../src/libnm-core-impl/nm-setting-bond.c:851
#, c-format
msgid "'%s=%s' is incompatible with '%s > 0'"
msgstr "Ā«%s=%sĀ» є Š½ŠµŃŃƒŠ¼Ń–сŠ½ŠøŠ¼ Š· Ā«%s > 0Ā»"
-#: ../src/libnm-core-impl/nm-setting-bond.c:877
+#: ../src/libnm-core-impl/nm-setting-bond.c:868
#, c-format
msgid "'%s' is not valid for the '%s' option: %s"
msgstr "Ā«%sĀ» є Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ Š“Š»Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Ā«%sĀ»: %s"
-#: ../src/libnm-core-impl/nm-setting-bond.c:889
+#: ../src/libnm-core-impl/nm-setting-bond.c:880
#, c-format
msgid "'%s' option is only valid for '%s=%s'"
msgstr "ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ» Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾Ń€ŠøстŠ¾Š²ŃƒŠ²Š°Ń‚Šø, Š»ŠøшŠµ яŠŗщŠ¾ Ā«%s=%sĀ»"
-#: ../src/libnm-core-impl/nm-setting-bond.c:902
+#: ../src/libnm-core-impl/nm-setting-bond.c:893
#, c-format
msgid "'%s=%s' is not a valid configuration for '%s'"
msgstr "Ā«%s=%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ Š½Š°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½Š½ŃŠ¼ Š“Š»Ń Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-setting-bond.c:917
-#: ../src/libnm-core-impl/nm-setting-bond.c:928
-#: ../src/libnm-core-impl/nm-setting-bond.c:941
+#: ../src/libnm-core-impl/nm-setting-bond.c:908
+#: ../src/libnm-core-impl/nm-setting-bond.c:919
+#: ../src/libnm-core-impl/nm-setting-bond.c:932
#, c-format
msgid "'%s' option requires '%s' option to be enabled"
msgstr "Š²ŠøŠŗŠ¾Ń€ŠøстŠ°Š½Š½Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Ā«%sĀ» Š²ŠøŠ¼Š°Š³Š°Ń” Š²Š¼ŠøŠŗŠ°Š½Š½Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-setting-bond.c:958
+#: ../src/libnm-core-impl/nm-setting-bond.c:949
#, c-format
msgid "'%s' option needs to be a value multiple of '%s' value"
msgstr "Š·Š½Š°Ń‡ŠµŠ½Š½ŃŠ¼ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ» Š¼Š°Ń” Š±ŃƒŃ‚Šø Š·Š½Š°Ń‡ŠµŠ½Š½Ń, ŠŗрŠ°Ń‚Š½Šµ Š“Š¾ Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-setting-bond.c:975
-#: ../src/libnm-core-impl/nm-setting-bond.c:986
+#: ../src/libnm-core-impl/nm-setting-bond.c:966
+#: ../src/libnm-core-impl/nm-setting-bond.c:977
#, c-format
msgid "'%s' option requires '%s' option to be set"
msgstr "Š²ŠøŠŗŠ¾Ń€ŠøстŠ°Š½Š½Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Ā«%sĀ» Š²ŠøŠ¼Š°Š³Š°Ń” Š²ŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½Š½Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-setting-bond.c:999
+#: ../src/libnm-core-impl/nm-setting-bond.c:990
#, c-format
msgid "'%s' option is only valid with mode '%s'"
msgstr "ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ» є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ Š»ŠøшŠµ у рŠµŠ¶ŠøŠ¼Ń– Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-setting-bond.c:1012
+#: ../src/libnm-core-impl/nm-setting-bond.c:1003
#, c-format
msgid "'%s' and '%s' cannot have different values"
msgstr "Š—Š½Š°Ń‡ŠµŠ½Š½Ń Ā«%sĀ» і Ā«%sĀ» Š½Šµ Š¼Š¾Š¶ŃƒŃ‚ŃŒ Š±ŃƒŃ‚Šø ріŠ·Š½ŠøŠ¼Šø"
-#: ../src/libnm-core-impl/nm-setting-bond.c:1035
+#: ../src/libnm-core-impl/nm-setting-bond.c:1026
#, c-format
msgid "'%s' option should be string"
msgstr "ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ» Š¼Š°Ń” Š±ŃƒŃ‚Šø ряŠ“ŠŗŠ¾Š¼"
-#: ../src/libnm-core-impl/nm-setting-bond.c:1048
+#: ../src/libnm-core-impl/nm-setting-bond.c:1039
#, c-format
msgid "'%s' option is not valid with mode '%s'"
msgstr "ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ» є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ Š· рŠµŠ¶ŠøŠ¼Š¾Š¼ Ā«%sĀ»"
@@ -1764,6 +1776,11 @@ msgstr "Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š¾Š¼"
msgid "'%s' option must be a power of 2"
msgstr "Š—Š½Š°Ń‡ŠµŠ½Š½ŃŠ¼ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Ā«%sĀ» Š¼Š°Ń” Š±ŃƒŃ‚Šø стŠµŠæіŠ½ŃŒ 2"
+#: ../src/libnm-core-impl/nm-setting-bridge.c:1318
+#| msgid "vlan setting should have a ethernet setting as well"
+msgid "bridge connection should have a ethernet setting as well"
+msgstr "Š·'єŠ“Š½Š°Š½Š½Ń Š¼Ń–стŠŗŠ° Š¼Š°Ń” суŠæрŠ¾Š²Š¾Š“Š¶ŃƒŠ²Š°Ń‚Šøся ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š¾Š¼ ethernet"
+
#: ../src/libnm-core-impl/nm-setting-connection.c:1005
#, c-format
msgid "setting required for connection of type '%s'"
@@ -1945,7 +1962,11 @@ msgstr ""
"Š£ Š·Š°ŠæŠøсі Š·'єŠ“Š½Š°Š½Š½Ń Š·Š°ŠŗрŠøтŠ¾Š³Š¾ ŠŗŠ»ŃŽŃ‡Š° InfiniBand Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š½Š°Š·Š²Šø Š±Š°Ń‚ŃŒŠŗіŠ²ŃŃŒŠŗŠ¾Š³Š¾ "
"іŠ½Ń‚ŠµŃ€Ń„ŠµŠ¹ŃŃƒ"
-#: ../src/libnm-core-impl/nm-setting-infiniband.c:264
+#: ../src/libnm-core-impl/nm-setting-infiniband.c:248
+msgid "the values 0 and 0x8000 are not allowed"
+msgstr "Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾Ń€ŠøстŠ¾Š²ŃƒŠ²Š°Ń‚Šø Š·Š½Š°Ń‡ŠµŠ½Š½Ń 0 і 0x8000"
+
+#: ../src/libnm-core-impl/nm-setting-infiniband.c:274
#, c-format
msgid ""
"interface name of software infiniband device must be '%s' or unset (instead "
@@ -1954,7 +1975,19 @@ msgstr ""
"Š½Š°Š·Š²Š¾ŃŽ іŠ½Ń‚ŠµŃ€Ń„ŠµŠ¹ŃŃƒ ŠæрŠ¾Š³Ń€Š°Š¼Š½Š¾Š³Š¾ ŠæрŠøстрŠ¾ŃŽ infiniband Š¼Š°Ń” Š±ŃƒŃ‚Šø Ā«%sĀ» Š°Š±Š¾ Š½Š°Š·Š²Ńƒ "
"Š¼Š°Ń” Š±ŃƒŃ‚Šø Š½Šµ Š²ŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½Š¾ (Š·Š°Š¼Ń–ŃŃ‚ŃŒ Š½ŠµŃ— Š¼Š°Ń” Š±ŃƒŃ‚Šø Ā«%sĀ»)"
-#: ../src/libnm-core-impl/nm-setting-infiniband.c:292
+#: ../src/libnm-core-impl/nm-setting-infiniband.c:282
+#, c-format
+#| msgid ""
+#| "interface name of software infiniband device must be '%s' or unset "
+#| "(instead it is '%s')"
+msgid ""
+"interface name of software infiniband device with MAC address must be unset "
+"(instead it is '%s')"
+msgstr ""
+"Š½Š°Š·Š²Ńƒ іŠ½Ń‚ŠµŃ€Ń„ŠµŠ¹ŃŃƒ ŠæрŠ¾Š³Ń€Š°Š¼Š½Š¾Š³Š¾ ŠæрŠøстрŠ¾ŃŽ infiniband Š· MAC-Š°Š“рŠµŃŠ¾ŃŽ Š¼Š°Ń” Š±ŃƒŃ‚Šø Š½Šµ"
+" Š²ŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½Š¾ (Š·Š°Š¼Ń–ŃŃ‚ŃŒ Š½ŠµŃ— Š¼Š°Ń” Š±ŃƒŃ‚Šø Ā«%sĀ»)"
+
+#: ../src/libnm-core-impl/nm-setting-infiniband.c:310
#, c-format
msgid "mtu can be at most %u but it is %u"
msgstr "mtu Š½Šµ Š¼Š¾Š¶Šµ ŠæŠµŃ€ŠµŠ²ŠøщуŠ²Š°Ń‚Šø %u, Š°Š»Šµ Š¼Š°Ń”Š¼Š¾ %u"
@@ -3132,230 +3165,230 @@ msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ тŠøŠæ D-Bus Ā«%sĀ»"
msgid "invalid link-watchers: %s"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń link-watchers: %s"
-#: ../src/libnm-core-impl/nm-utils.c:2256
+#: ../src/libnm-core-impl/nm-utils.c:2255
#, c-format
msgid "'%s' is not a valid handle."
msgstr "Ā«%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ Š“ŠµŃŠŗрŠøŠæтŠ¾Ń€Š¾Š¼."
-#: ../src/libnm-core-impl/nm-utils.c:2404
+#: ../src/libnm-core-impl/nm-utils.c:2403
#, c-format
msgid "'%s' unexpected: parent already specified."
msgstr "ŠŠµŠ¾Ń‡Ń–ŠŗуŠ²Š°Š½Šµ Ā«%sĀ»: Š±Š°Ń‚ŃŒŠŗіŠ²ŃŃŒŠŗŠøŠ¹ Š·Š°ŠæŠøс Š²Š¶Šµ Š²ŠŗŠ°Š·Š°Š½Š¾."
-#: ../src/libnm-core-impl/nm-utils.c:2422
+#: ../src/libnm-core-impl/nm-utils.c:2421
#, c-format
msgid "invalid handle: '%s'"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ Š“ŠµŃŠŗрŠøŠæтŠ¾Ń€: Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-utils.c:2444
+#: ../src/libnm-core-impl/nm-utils.c:2443
msgid "parent not specified."
msgstr "Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š±Š°Ń‚ŃŒŠŗіŠ²ŃŃŒŠŗŠøŠ¹ Š·Š°ŠæŠøс."
-#: ../src/libnm-core-impl/nm-utils.c:2508
+#: ../src/libnm-core-impl/nm-utils.c:2507
#, c-format
msgid "unsupported qdisc option: '%s'."
msgstr "Š½ŠµŠæіŠ“трŠøŠ¼ŃƒŠ²Š°Š½ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ qdisc: Ā«%sĀ»."
-#: ../src/libnm-core-impl/nm-utils.c:2638
+#: ../src/libnm-core-impl/nm-utils.c:2637
msgid "action name missing."
msgstr "Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š½Š°Š·Š²Šø Š“ії."
-#: ../src/libnm-core-impl/nm-utils.c:2663
+#: ../src/libnm-core-impl/nm-utils.c:2662
#, c-format
msgid "unsupported action option: '%s'."
msgstr "Š½ŠµŠæіŠ“трŠøŠ¼ŃƒŠ²Š°Š½ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Š“ії: Ā«%sĀ»."
-#: ../src/libnm-core-impl/nm-utils.c:2800
+#: ../src/libnm-core-impl/nm-utils.c:2799
msgid "invalid action: "
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Š° Š“ія: "
-#: ../src/libnm-core-impl/nm-utils.c:2804
+#: ../src/libnm-core-impl/nm-utils.c:2803
#, c-format
msgid "unsupported tfilter option: '%s'."
msgstr "Š½ŠµŠæіŠ“трŠøŠ¼ŃƒŠ²Š°Š½ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ tfilter: Ā«%sĀ»."
-#: ../src/libnm-core-impl/nm-utils.c:3104
+#: ../src/libnm-core-impl/nm-utils.c:3103
#, c-format
msgid "failed stat file %s: %s"
msgstr "Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š¾Ń‚Ń€ŠøŠ¼Š°Ń‚Šø стŠ°Ń‚ŠøстŠøчŠ½Ń– Š“Š°Š½Ń– щŠ¾Š“Š¾ фŠ°Š¹Š»Š° %s: %s"
-#: ../src/libnm-core-impl/nm-utils.c:3115
+#: ../src/libnm-core-impl/nm-utils.c:3114
#, c-format
msgid "not a file (%s)"
msgstr "Š½Šµ є фŠ°Š¹Š»Š¾Š¼ (%s)"
-#: ../src/libnm-core-impl/nm-utils.c:3126
+#: ../src/libnm-core-impl/nm-utils.c:3125
#, c-format
msgid "invalid file owner %d for %s"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ Š²Š»Š°ŃŠ½ŠøŠŗ фŠ°Š¹Š»Š°, %d, %s"
-#: ../src/libnm-core-impl/nm-utils.c:3138
+#: ../src/libnm-core-impl/nm-utils.c:3137
#, c-format
msgid "file permissions for %s"
msgstr "фŠ°Š¹Š»Š¾Š²Ń– ŠæрŠ°Š²Š° Š“Š¾ŃŃ‚ŃƒŠæу Š“Š¾ %s"
-#: ../src/libnm-core-impl/nm-utils.c:3148
+#: ../src/libnm-core-impl/nm-utils.c:3147
#, c-format
msgid "reject %s"
msgstr "Š²Ń–Š“Š¼Š¾Š²ŠøтŠø %s"
-#: ../src/libnm-core-impl/nm-utils.c:3168
+#: ../src/libnm-core-impl/nm-utils.c:3167
#, c-format
msgid "path is not absolute (%s)"
msgstr "шŠ»ŃŃ… Š½Šµ є Š°Š±ŃŠ¾Š»ŃŽŃ‚Š½ŠøŠ¼ (%s)"
-#: ../src/libnm-core-impl/nm-utils.c:3183
+#: ../src/libnm-core-impl/nm-utils.c:3182
#, c-format
msgid "Plugin file does not exist (%s)"
msgstr "Š¤Š°Š¹Š»Š° Š“Š¾Š“Š°Ń‚ŠŗŠ° Š½Šµ ісŠ½ŃƒŃ” (%s)"
-#: ../src/libnm-core-impl/nm-utils.c:3192
+#: ../src/libnm-core-impl/nm-utils.c:3191
#, c-format
msgid "Plugin is not a valid file (%s)"
msgstr "Š”Š¾Š“Š°Ń‚Š¾Šŗ Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ фŠ°Š¹Š»Š¾Š¼ (%s)"
-#: ../src/libnm-core-impl/nm-utils.c:3203
+#: ../src/libnm-core-impl/nm-utils.c:3202
#, c-format
msgid "libtool archives are not supported (%s)"
msgstr "ŠŸŃ–Š“трŠøŠ¼ŠŗŠø Š°Ń€Ń…Ń–Š²Ń–Š² libtool Š½Šµ ŠæŠµŃ€ŠµŠ“Š±Š°Ń‡ŠµŠ½Š¾ (%s)"
-#: ../src/libnm-core-impl/nm-utils.c:3280
+#: ../src/libnm-core-impl/nm-utils.c:3279
#, c-format
msgid "Could not find \"%s\" binary"
msgstr "ŠŠµ Š²Š“Š°Š»Š¾ŃŃ Š·Š½Š°Š¹Ń‚Šø Š²ŠøŠŗŠ¾Š½ŃƒŠ²Š°Š½ŠøŠ¹ фŠ°Š¹Š» Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-utils.c:4103
+#: ../src/libnm-core-impl/nm-utils.c:4102
msgid "unknown secret flags"
msgstr "Š½ŠµŠ²Ń–Š“Š¾Š¼Ń– ŠæрŠ°ŠæŠ¾Ń€Ń†Ń– рŠµŃ”стрŠ°Ń†Ń–Š¹Š½Šøх Š“Š°Š½Šøх"
-#: ../src/libnm-core-impl/nm-utils.c:4113
+#: ../src/libnm-core-impl/nm-utils.c:4112
msgid "conflicting secret flags"
msgstr "ŠŗŠ¾Š½Ń„Š»Ń–Šŗт ŠæрŠ°ŠæŠ¾Ń€Ń†Ń–Š² рŠµŃ”стрŠ°Ń†Ń–Š¹Š½Šøх Š“Š°Š½Šøх"
-#: ../src/libnm-core-impl/nm-utils.c:4124
+#: ../src/libnm-core-impl/nm-utils.c:4123
msgid "secret flags must not be \"not-required\""
msgstr "ŠæрŠ°ŠæŠ¾Ń€Ń†Ń– рŠµŃ”стрŠ°Ń†Ń–Š¹Š½Šøх Š“Š°Š½Šøх Š½Šµ Š¼Š¾Š¶ŃƒŃ‚ŃŒ Š±ŃƒŃ‚Šø Ā«not-requiredĀ»"
-#: ../src/libnm-core-impl/nm-utils.c:4132
+#: ../src/libnm-core-impl/nm-utils.c:4131
msgid "unsupported secret flags"
msgstr "Š½ŠµŠæіŠ“трŠøŠ¼ŃƒŠ²Š°Š½Ń– ŠæрŠ°ŠæŠ¾Ń€Ń†Ń– рŠµŃ”стрŠ°Ń†Ń–Š¹Š½Šøх Š“Š°Š½Šøх"
-#: ../src/libnm-core-impl/nm-utils.c:4162
+#: ../src/libnm-core-impl/nm-utils.c:4161
msgid "can't be simultaneously disabled and enabled"
msgstr "Š½Šµ Š¼Š¾Š¶Šµ Š±ŃƒŃ‚Šø Š¾Š“Š½Š¾Ń‡Š°ŃŠ½Š¾ Š²ŠøŠ¼ŠŗŠ½ŠµŠ½Š¾ і уŠ²Ń–Š¼ŠŗŠ½ŠµŠ½Š¾"
-#: ../src/libnm-core-impl/nm-utils.c:4170
+#: ../src/libnm-core-impl/nm-utils.c:4169
msgid "WPS is required"
msgstr "ŠŸŠ¾Ń‚ріŠ±Š½Š° WPS"
-#: ../src/libnm-core-impl/nm-utils.c:4238
+#: ../src/libnm-core-impl/nm-utils.c:4237
#, c-format
msgid "not a valid ethernet MAC address for mask at position %lld"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Š° Š°Š“рŠµŃŠ° MAC ethernet Š“Š»Ń Š¼Š°ŃŠŗŠø у ŠæŠ¾Š·Šøції %lld"
-#: ../src/libnm-core-impl/nm-utils.c:4257
+#: ../src/libnm-core-impl/nm-utils.c:4256
#, c-format
msgid "not a valid ethernet MAC address #%u at position %lld"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Š° Š°Š“рŠµŃŠ° MAC ethernet #%u у ŠæŠ¾Š·Šøції %lld"
-#: ../src/libnm-core-impl/nm-utils.c:4889
+#: ../src/libnm-core-impl/nm-utils.c:4888
msgid "not valid utf-8"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Ń– Š“Š°Š½Ń– UTF-8"
-#: ../src/libnm-core-impl/nm-utils.c:4910
-#: ../src/libnm-core-impl/nm-utils.c:4963
+#: ../src/libnm-core-impl/nm-utils.c:4909
+#: ../src/libnm-core-impl/nm-utils.c:4962
msgid "is not a JSON object"
msgstr "Š½Šµ є Š¾Š±'єŠŗтŠ¾Š¼ JSON"
-#: ../src/libnm-core-impl/nm-utils.c:4939
+#: ../src/libnm-core-impl/nm-utils.c:4938
msgid "value is NULL"
msgstr "Š·Š½Š°Ń‡ŠµŠ½Š½ŃŠ¼ є NULL"
-#: ../src/libnm-core-impl/nm-utils.c:4939
+#: ../src/libnm-core-impl/nm-utils.c:4938
msgid "value is empty"
msgstr "ŠæŠ¾Ń€Š¾Š¶Š½Ń” Š·Š½Š°Ń‡ŠµŠ½Š½Ń"
-#: ../src/libnm-core-impl/nm-utils.c:4951
+#: ../src/libnm-core-impl/nm-utils.c:4950
#, c-format
msgid "invalid JSON at position %d (%s)"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ ŠŗŠ¾Š“ JSON Š½Š° ŠæŠ¾Š·Šøції %d (%s)"
-#: ../src/libnm-core-impl/nm-utils.c:5079
-#: ../src/libnm-core-impl/nm-utils.c:5099
+#: ../src/libnm-core-impl/nm-utils.c:5078
+#: ../src/libnm-core-impl/nm-utils.c:5098
msgid "unterminated escape sequence"
msgstr "Š½ŠµŠ·Š°Š²ŠµŃ€ŃˆŠµŠ½Š° ŠµŠŗрŠ°Š½Š¾Š²Š°Š½Š° ŠæŠ¾ŃŠ»Ń–Š“Š¾Š²Š½Ń–ŃŃ‚ŃŒ"
-#: ../src/libnm-core-impl/nm-utils.c:5125
+#: ../src/libnm-core-impl/nm-utils.c:5124
#, c-format
msgid "unknown attribute '%s'"
msgstr "Š½ŠµŠ²Ń–Š“Š¾Š¼ŠøŠ¹ Š°Ń‚Ń€ŠøŠ±ŃƒŃ‚ Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-utils.c:5143
+#: ../src/libnm-core-impl/nm-utils.c:5142
#, c-format
msgid "missing key-value separator '%c' after '%s'"
msgstr "ŠæрŠ¾ŠæущŠµŠ½Š¾ рŠ¾Š·Š“іŠ»ŃŒŠ½ŠøŠŗ ŠæŠ°Ń€ ŠŗŠ»ŃŽŃ‡-Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«%cĀ» ŠæісŠ»Ń Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-utils.c:5163
+#: ../src/libnm-core-impl/nm-utils.c:5162
#, c-format
msgid "invalid uint32 value '%s' for attribute '%s'"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń uint32 Ā«%sĀ» Š°Ń‚Ń€ŠøŠ±ŃƒŃ‚Š° Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-utils.c:5177
+#: ../src/libnm-core-impl/nm-utils.c:5176
#, c-format
msgid "invalid int32 value '%s' for attribute '%s'"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń int32 Ā«%sĀ» Š°Ń‚Ń€ŠøŠ±ŃƒŃ‚Š° Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-utils.c:5190
+#: ../src/libnm-core-impl/nm-utils.c:5189
#, c-format
msgid "invalid uint64 value '%s' for attribute '%s'"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń uint64 Ā«%sĀ» Š°Ń‚Ń€ŠøŠ±ŃƒŃ‚Š° Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-utils.c:5203
+#: ../src/libnm-core-impl/nm-utils.c:5202
#, c-format
msgid "invalid uint8 value '%s' for attribute '%s'"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń uint8 Ā«%sĀ» Š°Ń‚Ń€ŠøŠ±ŃƒŃ‚Š° Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-utils.c:5217
+#: ../src/libnm-core-impl/nm-utils.c:5216
#, c-format
msgid "invalid boolean value '%s' for attribute '%s'"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š±ŃƒŠ»ŠµŠ²Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«%sĀ» Š°Ń‚Ń€ŠøŠ±ŃƒŃ‚Š° Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-utils.c:5231
+#: ../src/libnm-core-impl/nm-utils.c:5230
#, c-format
msgid "unsupported attribute '%s' of type '%s'"
msgstr "Š½ŠµŠæіŠ“трŠøŠ¼ŃƒŠ²Š°Š½ŠøŠ¹ Š°Ń‚Ń€ŠøŠ±ŃƒŃ‚ Ā«%sĀ» тŠøŠæу Ā«%sĀ»"
-#: ../src/libnm-core-impl/nm-utils.c:5532
+#: ../src/libnm-core-impl/nm-utils.c:5531
#, c-format
msgid "Bridge VLANs %d and %d are not sorted by ascending vid"
msgstr "VLAN Š¼Ń–стŠŗŠ° %d і %d Š½Šµ уŠæŠ¾Ń€ŃŠ“ŠŗŠ¾Š²Š°Š½Š¾ Š·Š° Š·Ń€Š¾ŃŃ‚Š°Š½Š½ŃŠ¼ vid"
-#: ../src/libnm-core-impl/nm-utils.c:5556
+#: ../src/libnm-core-impl/nm-utils.c:5555
#, c-format
msgid "duplicate bridge VLAN vid %u"
msgstr "Š“уŠ±Š»Ń–ŠŗŠ°Ń‚ Š¼Ń–стŠŗŠ° vid VLAN %u"
-#: ../src/libnm-core-impl/nm-utils.c:5568
+#: ../src/libnm-core-impl/nm-utils.c:5567
msgid "only one VLAN can be the PVID"
msgstr "Š»ŠøшŠµ Š¾Š“Š½Š° Š· VLAN Š¼Š¾Š¶Šµ Š±ŃƒŃ‚Šø PVID"
-#: ../src/libnm-core-impl/nm-utils.c:5613
+#: ../src/libnm-core-impl/nm-utils.c:5612
#, c-format
msgid "unknown flags 0x%x"
msgstr "Š½ŠµŠ²Ń–Š“Š¾Š¼Ń– ŠæрŠ°ŠæŠ¾Ń€Ń†Ń– 0x%x"
-#: ../src/libnm-core-impl/nm-utils.c:5625
+#: ../src/libnm-core-impl/nm-utils.c:5624
msgid ""
"'fqdn-no-update' and 'fqdn-serv-update' flags cannot be set at the same time"
msgstr ""
"Š½Šµ Š¼Š¾Š¶Š½Š° Š¾Š“Š½Š¾Ń‡Š°ŃŠ½Š¾ Š²ŃŃ‚Š°Š½Š¾Š²Š»ŃŽŠ²Š°Ń‚Šø ŠæрŠ°ŠæŠ¾Ń€Ń†Ń– Ā«fqdn-no-updateĀ» і Ā«fqdn-serv-"
"updateĀ»"
-#: ../src/libnm-core-impl/nm-utils.c:5636
+#: ../src/libnm-core-impl/nm-utils.c:5635
msgid "'fqdn-clear-flags' flag is incompatible with other FQDN flags"
msgstr "ŠæрŠ°ŠæŠ¾Ń€ŠµŃ†ŃŒ Ā«fqdn-clear-flagsĀ» є Š½ŠµŃŃƒŠ¼Ń–сŠ½ŠøŠ¼ іŠ· іŠ½ŃˆŠøŠ¼Šø ŠæрŠ°ŠæŠ¾Ń€Ń†ŃŠ¼Šø FQDN"
-#: ../src/libnm-core-impl/nm-utils.c:5644
+#: ../src/libnm-core-impl/nm-utils.c:5643
msgid "DHCPv6 does not support the E (encoded) FQDN flag"
msgstr "у DHCPv6 Š½Šµ ŠæŠµŃ€ŠµŠ“Š±Š°Ń‡ŠµŠ½Š¾ ŠæіŠ“трŠøŠ¼ŠŗŠø ŠæрŠ°ŠæŠ¾Ń€Ń†Ń E (Š·Š°ŠŗŠ¾Š“Š¾Š²Š°Š½Š¾) FQDN"
@@ -3772,36 +3805,36 @@ msgstr "ŠŠµ Š²Š“Š°Š»Š¾ŃŃ рŠ¾Š·ŠæіŠ·Š½Š°Ń‚Šø сŠµŃ€Ń‚ŠøфіŠŗŠ°Ń‚"
msgid "not a valid private key"
msgstr "Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ Š·Š°ŠŗрŠøтŠøŠ¼ ŠŗŠ»ŃŽŃ‡ŠµŠ¼"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:2669
+#: ../src/libnm-glib-aux/nm-shared-utils.c:2667
#, c-format
msgid "object class '%s' has no property named '%s'"
msgstr "у ŠŗŠ»Š°ŃŃ– Š¾Š±'єŠŗтіŠ² Ā«%sĀ» Š½ŠµŠ¼Š°Ń” Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń– іŠ· Š½Š°Š·Š²Š¾ŃŽ Ā«%sĀ»"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:2678
+#: ../src/libnm-glib-aux/nm-shared-utils.c:2676
#, c-format
msgid "property '%s' of object class '%s' is not writable"
msgstr "Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ Ā«%sĀ» ŠŗŠ»Š°ŃŃƒ Š¾Š±'єŠŗтіŠ² Ā«%sĀ» є Š½ŠµŠæрŠøŠ“Š°Ń‚Š½Š¾ŃŽ Š“Š¾ Š·Š°ŠæŠøсу"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:2687
+#: ../src/libnm-glib-aux/nm-shared-utils.c:2685
#, c-format
msgid ""
"construct property \"%s\" for object '%s' can't be set after construction"
msgstr ""
"Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ construct Ā«%sĀ» Š¾Š±'єŠŗтŠ° Ā«%sĀ» Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŃŃ‚Š°Š½Š¾Š²Š»ŃŽŠ²Š°Ń‚Šø ŠæісŠ»Ń ŠæŠ¾Š±ŃƒŠ“Š¾Š²Šø"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:2698
+#: ../src/libnm-glib-aux/nm-shared-utils.c:2696
#, c-format
msgid "'%s::%s' is not a valid property name; '%s' is not a GObject subtype"
msgstr "Ā«%s::%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½Š¾ŃŽ Š½Š°Š·Š²Š¾ŃŽ Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń–; Ā«%sĀ» Š½Šµ є ŠæіŠ“тŠøŠæŠ¾Š¼ GObject"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:2711
+#: ../src/libnm-glib-aux/nm-shared-utils.c:2709
#, c-format
msgid "unable to set property '%s' of type '%s' from value of type '%s'"
msgstr ""
"Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š²ŃŃ‚Š°Š½Š¾Š²ŠøтŠø Š·Š½Š°Ń‡ŠµŠ½Š½Ń Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń– Ā«%sĀ» тŠøŠæу Ā«%sĀ» Š½Š° Š¾ŃŠ½Š¾Š²Ń– Š·Š½Š°Ń‡ŠµŠ½Š½Ń "
"тŠøŠæу Ā«%sĀ»"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:2723
+#: ../src/libnm-glib-aux/nm-shared-utils.c:2721
#, c-format
msgid ""
"value \"%s\" of type '%s' is invalid or out of range for property '%s' of "
@@ -3810,48 +3843,48 @@ msgstr ""
"Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«%sĀ» тŠøŠæу Ā«%sĀ» є Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ Š“Š»Ń Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń– Ā«%sĀ» тŠøŠæу Ā«%sĀ» Š°Š±Š¾ Š½Šµ "
"Š½Š°Š»ŠµŠ¶Šøть Š“Š¾ ŠæрŠøŠæустŠøŠ¼Š¾Š³Š¾ Š“іŠ°ŠæŠ°Š·Š¾Š½Ńƒ Š·Š½Š°Ń‡ŠµŠ½ŃŒ"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:5688
+#: ../src/libnm-glib-aux/nm-shared-utils.c:5687
msgid "interface name is missing"
msgstr "ŠæрŠ¾ŠæущŠµŠ½Š¾ Š½Š°Š·Š²Ńƒ іŠ½Ń‚ŠµŃ€Ń„ŠµŠ¹ŃŃƒ"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:5696
+#: ../src/libnm-glib-aux/nm-shared-utils.c:5695
msgid "interface name is too short"
msgstr "Š½Š°Š·Š²Š° іŠ½Ń‚ŠµŃ€Ń„ŠµŠ¹ŃŃƒ є Š½Š°Š“тŠ¾ ŠŗŠ¾Ń€Š¾Ń‚ŠŗŠ¾ŃŽ"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:5704
+#: ../src/libnm-glib-aux/nm-shared-utils.c:5703
msgid "interface name is reserved"
msgstr "тŠ°Šŗу Š½Š°Š·Š²Ńƒ іŠ½Ń‚ŠµŃ€Ń„ŠµŠ¹ŃŃƒ Š·Š°Ń€ŠµŠ·ŠµŃ€Š²Š¾Š²Š°Š½Š¾"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:5717
+#: ../src/libnm-glib-aux/nm-shared-utils.c:5716
msgid "interface name contains an invalid character"
msgstr "Š½Š°Š·Š²Š° іŠ½Ń‚ŠµŃ€Ń„ŠµŠ¹ŃŃƒ Š¼Ń–стŠøть Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ сŠøŠ¼Š²Š¾Š»"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:5725
+#: ../src/libnm-glib-aux/nm-shared-utils.c:5724
msgid "interface name is longer than 15 characters"
msgstr "Š½Š°Š·Š²Š° іŠ½Ń‚ŠµŃ€Ń„ŠµŠ¹ŃŃƒ є Š“Š¾Š²ŃˆŠ¾ŃŽ Š·Š° 15 сŠøŠ¼Š²Š¾Š»Ń–Š²"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:5750
+#: ../src/libnm-glib-aux/nm-shared-utils.c:5749
#, c-format
msgid "'%%' is not allowed in interface names"
msgstr "Ā«%%Ā» Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾Ń€ŠøстŠ¾Š²ŃƒŠ²Š°Ń‚Šø у Š½Š°Š·Š²Š°Ń… іŠ½Ń‚ŠµŃ€Ń„ŠµŠ¹ŃŃ–Š²"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:5762
+#: ../src/libnm-glib-aux/nm-shared-utils.c:5761
#, c-format
msgid "'%s' is not allowed as interface name"
msgstr "Ā«%sĀ» Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾Ń€ŠøстŠ¾Š²ŃƒŠ²Š°Ń‚Šø яŠŗ Š½Š°Š·Š²Ńƒ іŠ½Ń‚ŠµŃ€Ń„ŠµŠ¹ŃŃƒ"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:5784
+#: ../src/libnm-glib-aux/nm-shared-utils.c:5783
msgid ""
"interface name must be alphanumerical with no forward or backward slashes"
msgstr ""
"Š½Š°Š·Š²Š° іŠ½Ń‚ŠµŃ€Ń„ŠµŠ¹ŃŃƒ Š¼Š°Ń” сŠŗŠ»Š°Š“Š°Ń‚Šøся Š· Š»Ń–Ń‚ŠµŃ€ і цŠøфр Š±ŠµŠ· ŠæŠ¾Ń‡Š°Ń‚ŠŗŠ¾Š²Š¾Š³Š¾ і "
"Š·Š°Š²ŠµŃ€ŃˆŠ°Š»ŃŒŠ½Š¾Š³Š¾ сŠøŠ¼Š²Š¾Š»Ń–Š² ŠæŠ¾Ń…ŠøŠ»Š¾Ń— рŠøсŠŗŠø"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:5801
+#: ../src/libnm-glib-aux/nm-shared-utils.c:5800
msgid "interface name must not be empty"
msgstr "Š½Š°Š·Š²Š° іŠ½Ń‚ŠµŃ€Ń„ŠµŠ¹ŃŃƒ Š½Šµ Š¼Š¾Š¶Šµ Š±ŃƒŃ‚Šø ŠæŠ¾Ń€Š¾Š¶Š½ŃŒŠ¾ŃŽ"
-#: ../src/libnm-glib-aux/nm-shared-utils.c:5809
+#: ../src/libnm-glib-aux/nm-shared-utils.c:5808
msgid "interface name must be UTF-8 encoded"
msgstr "Š½Š°Š·Š²Š° іŠ½Ń‚ŠµŃ€Ń„ŠµŠ¹ŃŃƒ Š¼Š°Ń” Š±ŃƒŃ‚Šø Š½Š°Š±Š¾Ń€Š¾Š¼ сŠøŠ¼Š²Š¾Š»Ń–Š² у ŠŗŠ¾Š“уŠ²Š°Š½Š½Ń– UTF-8"
@@ -3894,8 +3927,8 @@ msgstr "Ā«%sĀ» є Š½ŠµŠ¾Š“Š½Š¾Š·Š½Š°Ń‡Š½ŠøŠ¼: %s"
msgid "missing name, try one of [%s]"
msgstr "ŠæрŠ¾ŠæущŠµŠ½Š¾ Š½Š°Š·Š²Ńƒ, сŠæрŠ¾Š±ŃƒŠ¹Ń‚Šµ Š¾Š“Š½Ńƒ Š· тŠ°ŠŗŠøх Š½Š°Š·Š²: [%s]"
-#: ../src/libnmc-base/nm-client-utils.c:248 ../src/nmcli/connections.c:3612
-#: ../src/nmcli/connections.c:3670
+#: ../src/libnmc-base/nm-client-utils.c:248 ../src/nmcli/connections.c:3734
+#: ../src/nmcli/connections.c:3792
#, c-format
msgid "'%s' not among [%s]"
msgstr "Ā«%sĀ» Š½ŠµŠ¼Š°Ń” сŠµŃ€ŠµŠ“ [%s]"
@@ -3907,8 +3940,8 @@ msgstr "Ā«%sĀ» Š½ŠµŠ¼Š°Ń” сŠµŃ€ŠµŠ“ [%s]"
#: ../src/libnmc-setting/nm-meta-setting-desc.c:1837
#: ../src/libnmc-setting/nm-meta-setting-desc.c:1868
#: ../src/libnmc-setting/nm-meta-setting-desc.c:2832
-#: ../src/libnmc-setting/nm-meta-setting-desc.c:2890 ../src/nmcli/common.c:1477
-#: ../src/nmcli/connections.c:77 ../src/nmcli/connections.c:87
+#: ../src/libnmc-setting/nm-meta-setting-desc.c:2890 ../src/nmcli/common.c:1625
+#: ../src/nmcli/connections.c:78 ../src/nmcli/connections.c:88
#: ../src/nmcli/devices.c:484 ../src/nmcli/devices.c:591
#: ../src/nmcli/devices.c:597 ../src/nmcli/general.c:30
#: ../src/nmcli/general.c:85 ../src/nmcli/general.c:91
@@ -3955,7 +3988,7 @@ msgstr "Š·'єŠ“Š½Š°Š½Š½Ń (Š²ŃŃ‚Š°Š½Š¾Š²Š»ŠµŠ½Š½Ń Š“руŠ³Š¾Ń€ŃŠ“Š½Šøх Š·'є
msgid "connected"
msgstr "Š·'єŠ“Š½Š°Š½Š¾"
-#: ../src/libnmc-base/nm-client-utils.c:303 ../src/nmcli/connections.c:80
+#: ../src/libnmc-base/nm-client-utils.c:303 ../src/nmcli/connections.c:81
msgid "deactivating"
msgstr "Š“ŠµŠ°ŠŗтŠøŠ²Š°Ń†Ń–я"
@@ -3984,8 +4017,8 @@ msgstr "Š“ŠµŠ°ŠŗтŠøŠ²Š°Ń†Ń–я (Š·Š·Š¾Š²Š½Ń–)"
#: ../src/libnmc-base/nm-client-utils.c:342
#: ../src/libnmc-setting/nm-meta-setting-desc.c:883
#: ../src/libnmc-setting/nm-meta-setting-desc.c:2824
-#: ../src/nmcli/connections.c:5381 ../src/nmcli/connections.c:7326
-#: ../src/nmcli/connections.c:7327 ../src/nmcli/devices.c:590
+#: ../src/nmcli/connections.c:5491 ../src/nmcli/connections.c:7446
+#: ../src/nmcli/connections.c:7447 ../src/nmcli/devices.c:590
#: ../src/nmcli/devices.c:596 ../src/nmcli/devices.c:1382
#: ../src/nmcli/general.c:92 ../src/nmcli/utils.h:313
msgid "yes"
@@ -3994,8 +4027,8 @@ msgstr "тŠ°Šŗ"
#: ../src/libnmc-base/nm-client-utils.c:343
#: ../src/libnmc-setting/nm-meta-setting-desc.c:883
#: ../src/libnmc-setting/nm-meta-setting-desc.c:2827
-#: ../src/nmcli/connections.c:5380 ../src/nmcli/connections.c:7326
-#: ../src/nmcli/connections.c:7327 ../src/nmcli/devices.c:590
+#: ../src/nmcli/connections.c:5490 ../src/nmcli/connections.c:7446
+#: ../src/nmcli/connections.c:7447 ../src/nmcli/devices.c:590
#: ../src/nmcli/devices.c:596 ../src/nmcli/devices.c:1382
#: ../src/nmcli/general.c:93 ../src/nmcli/utils.h:313
msgid "no"
@@ -4014,8 +4047,8 @@ msgid "No reason given"
msgstr "ŠŸŃ€ŠøчŠøŠ½Ńƒ Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾"
#. We should not really come here
-#: ../src/libnmc-base/nm-client-utils.c:354 ../src/nmcli/connections.c:3632
-#: ../src/nmcli/connections.c:3691
+#: ../src/libnmc-base/nm-client-utils.c:354 ../src/nmcli/connections.c:3754
+#: ../src/nmcli/connections.c:3813
#, c-format
msgid "Unknown error"
msgstr "ŠŠµŠ²Ń–Š“Š¾Š¼Š° ŠæŠ¾Š¼ŠøŠ»ŠŗŠ°"
@@ -4412,7 +4445,7 @@ msgstr "ŠšŠ¾Ń€ŠøстуŠ²Š°Ń‡"
#: ../src/libnmc-base/nm-vpn-helpers.c:143
#: ../src/libnmc-base/nm-vpn-helpers.c:147
#: ../src/libnmc-base/nm-vpn-helpers.c:153
-#: ../src/libnmc-base/nm-vpn-helpers.c:158 ../src/nmcli/devices.c:4662
+#: ../src/libnmc-base/nm-vpn-helpers.c:158 ../src/nmcli/devices.c:4668
#: ../src/nmtui/nmt-page-dsl.c:64 ../src/nmtui/nmt-page-wifi.c:271
#: ../src/nmtui/nmt-page-wifi.c:305 ../src/nmtui/nmt-page-wifi.c:344
msgid "Password"
@@ -9313,16 +9346,23 @@ msgstr ""
"Š½Š° тŠøŠ¼Ń‡Š°ŃŠ¾Š²Ń– Š°Š“рŠµŃŠø, яŠŗі Š½Š°Š»Š°ŃˆŃ‚Š¾Š²Š°Š½Š¾ Š·Š° Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾ŃŽ Š²Ń–Š“ŠæŠ¾Š²Ń–Š“Š½Š¾Ń— Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń–."
#: ../src/libnmc-setting/settings-docs.h.in:258
+#| msgid ""
+#| "A list of IPv6 addresses and their prefix length. Multiple addresses can "
+#| "be separated by comma. For example \"2001:db8:85a3::8a2e:370:7334/64, "
+#| "2001:db8:85a3::5/64\". The addresses are listed in increasing priority, "
+#| "meaning the last address will be the primary address."
msgid ""
"A list of IPv6 addresses and their prefix length. Multiple addresses can be "
"separated by comma. For example \"2001:db8:85a3::8a2e:370:7334/64, 2001:"
-"db8:85a3::5/64\". The addresses are listed in increasing priority, meaning "
-"the last address will be the primary address."
+"db8:85a3::5/64\". The addresses are listed in decreasing priority, meaning "
+"the first address will be the primary address. This can make a difference "
+"with IPv6 source address selection (RFC 6724, section 5)."
msgstr ""
-"Š”ŠæŠøсŠ¾Šŗ Š°Š“рŠµŃ IPv46тŠ° їхŠ½Ń–Ń… Š“Š¾Š²Š¶ŠøŠ½ ŠæрŠµŃ„Ń–ŠŗсŠ°. Š”ŠµŠŗіŠ»ŃŒŠŗŠ° Š°Š“рŠµŃ Š¼Š¾Š¶Š½Š° "
+"Š”ŠæŠøсŠ¾Šŗ Š°Š“рŠµŃ IPv6 тŠ° їхŠ½Ń–Ń… Š“Š¾Š²Š¶ŠøŠ½ ŠæрŠµŃ„Ń–ŠŗсŠ°. Š”ŠµŠŗіŠ»ŃŒŠŗŠ° Š°Š“рŠµŃ Š¼Š¾Š¶Š½Š° "
"Š²Ń–Š“Š¾ŠŗрŠµŠ¼Š»ŃŽŠ²Š°Ń‚Šø ŠŗŠ¾Š¼Š°Š¼Šø. ŠŸŃ€ŠøŠŗŠ»Š°Š“: \"2001:db8:85a3::8a2e:370:7334/64, 2001:"
-"db8:85a3::5/64\". Š”ŠæŠøсŠ¾Šŗ Š°Š“рŠµŃ сŠŗŠ»Š°Š“Š°Ń”Ń‚ŃŒŃŃ Š·Š° Š·Š±Ń–Š»ŃŒŃˆŠµŠ½Š½ŃŠ¼ ŠæріŠ¾Ń€ŠøтŠµŃ‚Š½Š¾ŃŃ‚Ń–, "
-"тŠ¾Š±Ń‚Š¾ Š¾ŃŃ‚Š°Š½Š½Ń Š°Š“рŠµŃŠ° Š±ŃƒŠ“Šµ Š¾ŃŠ½Š¾Š²Š½Š¾ŃŽ."
+"db8:85a3::5/64\". Š”ŠæŠøсŠ¾Šŗ Š°Š“рŠµŃ сŠŗŠ»Š°Š“Š°Ń”Ń‚ŃŒŃŃ Š·Š° Š·Š¼ŠµŠ½ŃˆŠµŠ½Š½ŃŠ¼ ŠæріŠ¾Ń€ŠøтŠµŃ‚Š½Š¾ŃŃ‚Ń–, "
+"тŠ¾Š±Ń‚Š¾ ŠæŠµŃ€ŃˆŠ° Š°Š“рŠµŃŠ° Š±ŃƒŠ“Šµ Š¾ŃŠ½Š¾Š²Š½Š¾ŃŽ. Š¦Šµ Š¼Š¾Š¶Šµ Š²ŠæŠ»ŠøŠ½ŃƒŃ‚Šø Š½Š° Š²ŠøŠ±Ń–Ń€ ŠæŠ¾Ń‡Š°Ń‚ŠŗŠ¾Š²Š¾Ń— Š°Š“рŠµŃŠø"
+" ŠæрŠø Š²ŠøŠŗŠ¾Ń€ŠøстŠ°Š½Š½Ń– IPv6 (RFC 6724, рŠ¾Š·Š“іŠ» 5)."
#: ../src/libnmc-setting/settings-docs.h.in:260
msgid ""
@@ -10810,28 +10850,28 @@ msgstr "nmcli усŠæішŠ½Š¾ Š·Š°Ń€ŠµŃ”стрŠ¾Š²Š°Š½Š¾ яŠŗ Š°Š³ŠµŠ½Ń‚ polkit.\
msgid "Error: polkit agent initialization failed: %s"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ іŠ½Ń–ціŠ°Š»Ń–Š·ŃƒŠ²Š°Ń‚Šø Š°Š³ŠµŠ½Ń‚ polkit: %s"
-#: ../src/nmcli/common.c:360 ../src/nmcli/common.c:361
-#: ../src/nmcli/common.c:391 ../src/nmcli/common.c:392
-#: ../src/nmcli/connections.c:1621
+#: ../src/nmcli/common.c:362 ../src/nmcli/common.c:363
+#: ../src/nmcli/common.c:393 ../src/nmcli/common.c:394
+#: ../src/nmcli/connections.c:1737
msgid "GROUP"
msgstr "Š“Š Š£ŠŸŠ"
-#: ../src/nmcli/common.c:639
+#: ../src/nmcli/common.c:642
#, c-format
msgid "Error: openconnect failed: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š²ŠøŠŗŠ¾Š½Š°Ń‚Šø openconnect: %s\n"
-#: ../src/nmcli/common.c:646
+#: ../src/nmcli/common.c:649
#, c-format
msgid "Error: openconnect failed with status %d\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š²ŠøŠŗŠ¾Š½Š°Š½Š½Ń openconnect Š·Š°Š²ŠµŃ€ŃˆŠøŠ»Š¾ŃŃ Š½ŠµŠ²Š“Š°Š»Š¾ Š·Ń– стŠ°Š½Š¾Š¼ %d\n"
-#: ../src/nmcli/common.c:648
+#: ../src/nmcli/common.c:651
#, c-format
msgid "Error: openconnect failed with signal %d\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š²ŠøŠŗŠ¾Š½Š°Š½Š½Ń openconnect Š·Š°Š²ŠµŃ€ŃˆŠøŠ»Š¾ŃŃ Š½ŠµŠ²Š“Š°Š»Š¾ іŠ· сŠøŠ³Š½Š°Š»Š¾Š¼ %d\n"
-#: ../src/nmcli/common.c:740
+#: ../src/nmcli/common.c:743
#, c-format
msgid ""
"Warning: password for '%s' not given in 'passwd-file' and nmcli cannot ask "
@@ -10840,132 +10880,141 @@ msgstr ""
"ŠŸŠ¾ŠæŠµŃ€ŠµŠ“Š¶ŠµŠ½Š½Ń: у Ā«passwd-fileĀ» Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ ŠæŠ°Ń€Š¾Š»Ń Š“Š¾ Ā«%sĀ», Š° nmcli Š½Šµ Š¼Š¾Š¶Šµ "
"Š·Š°ŠæŠøтŠ°Ń‚Šø ŠæрŠ¾ ŠæŠ°Ń€Š¾Š»ŃŒ Š±ŠµŠ· ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Ā«--askĀ».\n"
-#: ../src/nmcli/common.c:1261
+#: ../src/nmcli/common.c:1264
#, c-format
msgid "Error: Could not create NMClient object: %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ стŠ²Š¾Ń€ŠøтŠø Š¾Š±'єŠŗт NMClient: %s."
-#: ../src/nmcli/common.c:1287
+#: ../src/nmcli/common.c:1395
+msgid "Error: command doesn't support --offline mode."
+msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: у ŠŗŠ¾Š¼Š°Š½Š“і Š½Šµ ŠæŠµŃ€ŠµŠ“Š±Š°Ń‡ŠµŠ½Š¾ ŠæіŠ“трŠøŠ¼ŠŗŠø рŠµŠ¶ŠøŠ¼Ńƒ --offline."
+
+#: ../src/nmcli/common.c:1435
msgid "Error: NetworkManager is not running."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: NetworkManager Š½Šµ ŠæрŠ°Ń†ŃŽŃ”."
-#: ../src/nmcli/common.c:1390
+#: ../src/nmcli/common.c:1538
#, c-format
msgid "Error: argument '%s' not understood. Try passing --help instead."
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ» є Š½ŠµŠ²Ń–Š“Š¾Š¼ŠøŠ¼. Š”ŠæрŠ¾Š±ŃƒŠ¹Ń‚Šµ сŠŗŠ¾Ń€ŠøстŠ°Ń‚Šøся ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š¾Š¼ --help."
-#: ../src/nmcli/common.c:1401
+#: ../src/nmcli/common.c:1549
msgid "Error: missing argument. Try passing --help."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæрŠ¾ŠæущŠµŠ½Š¾ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€. Š”ŠæрŠ¾Š±ŃƒŠ¹Ń‚Šµ сŠŗŠ¾Ń€ŠøстŠ°Ń‚Šøся ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š¾Š¼ --help."
-#: ../src/nmcli/common.c:1466
+#: ../src/nmcli/common.c:1614
msgid "access denied"
msgstr "Š“Š¾ŃŃ‚ŃƒŠæ Š·Š°Š±Š¾Ń€Š¾Š½ŠµŠ½Š¾"
-#: ../src/nmcli/common.c:1468
+#: ../src/nmcli/common.c:1616
msgid "NetworkManager is not running"
msgstr "NetworkManager Š½Šµ Š·Š°ŠæущŠµŠ½Š¾"
-#: ../src/nmcli/common.c:1478
+#: ../src/nmcli/common.c:1626
msgid "none"
msgstr "Š½ŠµŠ¼Š°Ń”"
-#: ../src/nmcli/common.c:1479
+#: ../src/nmcli/common.c:1627
msgid "portal"
msgstr "ŠæŠ¾Ń€Ń‚Š°Š»"
-#: ../src/nmcli/common.c:1480
+#: ../src/nmcli/common.c:1628
msgid "limited"
msgstr "Š¾Š±Š¼ŠµŠ¶ŠµŠ½Š°"
-#: ../src/nmcli/common.c:1481
+#: ../src/nmcli/common.c:1629
msgid "full"
msgstr "ŠæŠ¾Š²Š½Š°"
#. define some prompts for connection editor
-#: ../src/nmcli/connections.c:59
+#: ../src/nmcli/connections.c:60
msgid "Setting name? "
msgstr "ŠŠ°Š·Š²Š° ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š°? "
-#: ../src/nmcli/connections.c:60
+#: ../src/nmcli/connections.c:61
msgid "Property name? "
msgstr "ŠŠ°Š·Š²Š° Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń–? "
-#: ../src/nmcli/connections.c:61
+#: ../src/nmcli/connections.c:62
msgid "Enter connection type: "
msgstr "Š’ŠŗŠ°Š¶Ń–Ń‚ŃŒ тŠøŠæ Š·'єŠ“Š½Š°Š½Š½Ń: "
#. define some other prompts
-#: ../src/nmcli/connections.c:65
+#: ../src/nmcli/connections.c:66
msgid "Connection (name, UUID, or path): "
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń (Š½Š°Š·Š²Š°, UUID Š°Š±Š¾ шŠ»ŃŃ…):"
-#: ../src/nmcli/connections.c:66
+#: ../src/nmcli/connections.c:67
msgid "VPN connection (name, UUID, or path): "
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń VPN (Š½Š°Š·Š²Š°, UUID Š°Š±Š¾ шŠ»ŃŃ…):"
-#: ../src/nmcli/connections.c:67
+#: ../src/nmcli/connections.c:68
msgid "Connection(s) (name, UUID, or path): "
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń (Š½Š°Š·Š²Š°, UUID Š°Š±Š¾ шŠ»ŃŃ…):"
-#: ../src/nmcli/connections.c:68
+#: ../src/nmcli/connections.c:69
msgid "Connection(s) (name, UUID, path or apath): "
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń (Š½Š°Š·Š²Š°, UUID, шŠ»ŃŃ… Š°Š±Š¾ apath):"
-#: ../src/nmcli/connections.c:78
+#: ../src/nmcli/connections.c:79
msgid "activating"
msgstr "Š°ŠŗтŠøŠ²Š°Ń†Ń–я"
-#: ../src/nmcli/connections.c:79
+#: ../src/nmcli/connections.c:80
msgid "activated"
msgstr "Š°ŠŗтŠøŠ²Š¾Š²Š°Š½Š¾"
-#: ../src/nmcli/connections.c:81
+#: ../src/nmcli/connections.c:82
msgid "deactivated"
msgstr "Š²ŠøŠ¼ŠŗŠ½ŠµŠ½Š¾"
-#: ../src/nmcli/connections.c:88
+#: ../src/nmcli/connections.c:89
msgid "VPN connecting (prepare)"
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń VPN (ŠæрŠøŠ³Š¾Ń‚ŃƒŠ²Š°Š½Š½Ń)"
-#: ../src/nmcli/connections.c:90
+#: ../src/nmcli/connections.c:91
msgid "VPN connecting (need authentication)"
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń VPN (ŠæŠ¾Ń‚ріŠ±Š½Šµ рŠ¾Š·ŠæіŠ·Š½Š°Š²Š°Š½Š½Ń)"
-#: ../src/nmcli/connections.c:91
+#: ../src/nmcli/connections.c:92
msgid "VPN connecting"
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń VPN"
-#: ../src/nmcli/connections.c:93
+#: ../src/nmcli/connections.c:94
msgid "VPN connecting (getting IP configuration)"
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń VPN (Š¾Ń‚Ń€ŠøŠ¼Š°Š½Š½Ń Š½Š°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½ŃŒ IP)"
-#: ../src/nmcli/connections.c:94
+#: ../src/nmcli/connections.c:95
msgid "VPN connected"
msgstr "VPN Š·'єŠ“Š½Š°Š½Š¾"
-#: ../src/nmcli/connections.c:95
+#: ../src/nmcli/connections.c:96
msgid "VPN connection failed"
msgstr "ŠŠµŠ²Š“Š°Š»Š° сŠæрŠ¾Š±Š° Š·'єŠ“Š½Š°Š½Š½Ń VPN"
-#: ../src/nmcli/connections.c:96
+#: ../src/nmcli/connections.c:97
msgid "VPN disconnected"
msgstr "VPN рŠ¾Š·'єŠ“Š½Š°Š½Š¾"
-#: ../src/nmcli/connections.c:526
+#: ../src/nmcli/connections.c:172 ../src/nmcli/connections.c:232
+#, c-format
+msgid "Error: Error writting connection: %s"
+msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ¾Š¼ŠøŠ»ŠŗŠ° ŠæіŠ“ чŠ°Ń Š·Š°ŠæŠøсу Š·'єŠ“Š½Š°Š½Š½Ń: %s"
+
+#: ../src/nmcli/connections.c:652
msgid "WiMax is no longer supported"
msgstr "ŠŸŃ–Š“трŠøŠ¼Šŗу WiMax ŠæрŠøŠæŠøŠ½ŠµŠ½Š¾"
-#: ../src/nmcli/connections.c:532
+#: ../src/nmcli/connections.c:658
msgid "WEP encryption is known to be insecure"
msgstr "Š’Ń–Š“Š¾Š¼Š¾, щŠ¾ шŠøфруŠ²Š°Š½Š½Ń WEP Š½Šµ є Š±ŠµŠ·ŠæŠµŃ‡Š½ŠøŠ¼"
-#: ../src/nmcli/connections.c:614
+#: ../src/nmcli/connections.c:740
msgid "never"
msgstr "Š½Ń–ŠŗŠ¾Š»Šø"
-#: ../src/nmcli/connections.c:965
+#: ../src/nmcli/connections.c:1089
#, c-format
msgid ""
"Usage: nmcli connection { COMMAND | help }\n"
@@ -11043,7 +11092,7 @@ msgstr ""
" export [id | uuid | path] <іŠ“ŠµŠ½Ń‚ŠøфіŠŗŠ°Ń‚Š¾Ń€> [<фŠ°Š¹Š» рŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Ń–Š²>]\n"
"\n"
-#: ../src/nmcli/connections.c:991
+#: ../src/nmcli/connections.c:1115
#, c-format
msgid ""
"Usage: nmcli connection show { ARGUMENTS | help }\n"
@@ -11091,7 +11140,7 @@ msgstr ""
"ŠÆŠŗщŠ¾ Š²ŠŗŠ°Š·Š°Š½Š¾ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«--activeĀ», Š±Ń€Š°Ń‚ŠøŠ¼ŃƒŃ‚ŃŒŃŃ Š“Š¾ уŠ²Š°Š³Šø Š»ŠøшŠµ Š°ŠŗтŠøŠ²Š½Ń– ŠæрŠ¾Ń„Ń–Š»Ń–. "
"Š—Š°Š³Š°Š»ŃŒŠ½ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ --show-secrets ŠæŠ¾ŠŗŠ°Š¶Šµ тŠ°ŠŗŠ¾Š¶ ŠæŠ¾Š²'яŠ·Š°Š½Ń– ŠæŠ°Ń€Š¾Š»Ń–.\n"
-#: ../src/nmcli/connections.c:1012
+#: ../src/nmcli/connections.c:1136
#, c-format
msgid ""
"Usage: nmcli connection up { ARGUMENTS | help }\n"
@@ -11137,7 +11186,7 @@ msgstr ""
"passwd-file - фŠ°Š¹Š» Š· ŠæŠ°Ń€Š¾Š»ŃŠ¼Šø, ŠæŠ¾Ń‚ріŠ±Š½ŠøŠ¼Šø Š“Š»Ń Š°ŠŗтŠøŠ²Š°Ń†Ń–Ń— Š·'єŠ“Š½Š°Š½Š½Ń\n"
"\n"
-#: ../src/nmcli/connections.c:1035
+#: ../src/nmcli/connections.c:1159
#, c-format
msgid ""
"Usage: nmcli connection down { ARGUMENTS | help }\n"
@@ -11159,7 +11208,7 @@ msgstr ""
"Š½Š°Š·Š²Š¾ŃŽ, UUID Š°Š±Š¾ шŠ»ŃŃ…Š¾Š¼ D-Bus.\n"
"\n"
-#: ../src/nmcli/connections.c:1047
+#: ../src/nmcli/connections.c:1171
#, c-format
msgid ""
"Usage: nmcli connection add { ARGUMENTS | help }\n"
@@ -11487,7 +11536,7 @@ msgstr ""
" [ip6 <Š°Š“рŠµŃŠ° IPv6>] [gw6 <шŠ»ŃŽŠ· IPv6>]\n"
"\n"
-#: ../src/nmcli/connections.c:1177
+#: ../src/nmcli/connections.c:1301
#, c-format
msgid ""
"Usage: nmcli connection modify { ARGUMENTS | help }\n"
@@ -11544,7 +11593,7 @@ msgstr ""
"nmcli con mod em1-1 remove sriov\n"
"\n"
-#: ../src/nmcli/connections.c:1205
+#: ../src/nmcli/connections.c:1329
#, c-format
msgid ""
"Usage: nmcli connection clone { ARGUMENTS | help }\n"
@@ -11567,7 +11616,7 @@ msgstr ""
"іŠ“ŠµŠ½Ń‚ŠøфіŠŗŠ°Ń‚Š¾Ń€Š° (Š·Š°Š“Š°Ń”Ń‚ŃŒŃŃ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š¾Š¼ <Š½Š¾Š²Š° Š½Š°Š·Š²Š°>).\n"
"\n"
-#: ../src/nmcli/connections.c:1217
+#: ../src/nmcli/connections.c:1341
#, c-format
msgid ""
"Usage: nmcli connection edit { ARGUMENTS | help }\n"
@@ -11595,7 +11644,7 @@ msgstr ""
"Š”Š¾Š“Š°Ń‚Šø Š½Š¾Š²ŠøŠ¹ ŠæрŠ¾Ń„Ń–Š»ŃŒ Š·'єŠ“Š½Š°Š½Š½Ń Š·Š° Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾ŃŽ іŠ½Ń‚ŠµŃ€Š°ŠŗтŠøŠ²Š½Š¾Š³Š¾ рŠµŠ“Š°ŠŗтŠ¾Ń€Š°.\n"
"\n"
-#: ../src/nmcli/connections.c:1232
+#: ../src/nmcli/connections.c:1356
#, c-format
msgid ""
"Usage: nmcli connection delete { ARGUMENTS | help }\n"
@@ -11614,7 +11663,7 @@ msgstr ""
"ŠŸŃ€Š¾Ń„Ń–Š»Ń– Š¼Š¾Š¶Š½Š° Š²ŠŗŠ°Š·Š°Ń‚Šø Š·Š° Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾ŃŽ Š½Š°Š·Š², UUID Š°Š±Š¾ шŠ»ŃŃ…Ńƒ D-Bus.\n"
"\n"
-#: ../src/nmcli/connections.c:1243
+#: ../src/nmcli/connections.c:1367
#, c-format
msgid ""
"Usage: nmcli connection monitor { ARGUMENTS | help }\n"
@@ -11636,7 +11685,7 @@ msgstr ""
"Š”тŠµŠ¶Šøть Š·Š° усіŠ¼Š° ŠæрŠ¾Ń„Ń–Š»ŃŠ¼Šø Š·'єŠ“Š½Š°Š½ŃŒ, яŠŗщŠ¾ ŠŗŠ¾Š½ŠŗрŠµŃ‚Š½ŠøŠ¹ ŠæрŠ¾Ń„Ń–Š»ŃŒ Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾.\n"
"\n"
-#: ../src/nmcli/connections.c:1255
+#: ../src/nmcli/connections.c:1379
#, c-format
msgid ""
"Usage: nmcli connection reload { help }\n"
@@ -11649,7 +11698,7 @@ msgstr ""
"ŠŸŠµŃ€ŠµŠ·Š°Š²Š°Š½Ń‚Š°Š¶ŠøтŠø усіх фŠ°Š¹Š»Šø Š·'єŠ“Š½Š°Š½ŃŒ Š· Š“ŠøсŠŗŠ°.\n"
"\n"
-#: ../src/nmcli/connections.c:1263
+#: ../src/nmcli/connections.c:1387
#, c-format
msgid ""
"Usage: nmcli connection load { ARGUMENTS | help }\n"
@@ -11672,7 +11721,7 @@ msgstr ""
"тŠ¾Š³Š¾, щŠ¾Š± Š·Š°Š²Š°Š½Ń‚Š°Š¶ŠøтŠø Š“Š¾ NetworkManager Š½Š°Š¹ŃŠ²Ń–Š¶Ń–ŃˆŃ– Š½Š°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½Š½Ń.\n"
"\n"
-#: ../src/nmcli/connections.c:1276
+#: ../src/nmcli/connections.c:1400
#, c-format
msgid ""
"Usage: nmcli connection import { ARGUMENTS | help }\n"
@@ -11697,7 +11746,7 @@ msgstr ""
"іŠ¼ŠæŠ¾Ń€Ń‚ŃƒŃŽŃ‚ŃŒŃŃ Š“Š¾Š“Š°Ń‚ŠŗŠ°Š¼Šø VPN NetworkManager.\n"
"\n"
-#: ../src/nmcli/connections.c:1289
+#: ../src/nmcli/connections.c:1413
#, c-format
msgid ""
"Usage: nmcli connection export { ARGUMENTS | help }\n"
@@ -11717,7 +11766,7 @@ msgstr ""
"Š”Š°Š½Ń– сŠæряŠ¼Š¾Š²ŃƒŠ²Š°Ń‚ŠøŠ¼ŃƒŃ‚ŃŒŃŃ Š“Š¾ стŠ°Š½Š“Š°Ń€Ń‚Š½Š¾Š³Š¾ Š²ŠøŠ²ŠµŠ“ŠµŠ½Š½Ń Š°Š±Š¾ Š“Š¾ Š²ŠŗŠ°Š·Š°Š½Š¾Š³Š¾ фŠ°Š¹Š»Š°.\n"
"\n"
-#: ../src/nmcli/connections.c:1300
+#: ../src/nmcli/connections.c:1424
#, c-format
msgid ""
"Usage: nmcli connection migrate { ARGUMENTS | help }\n"
@@ -11736,329 +11785,329 @@ msgstr ""
"Š·Š¾ŠŗрŠµŠ¼Š° Ā«keyfileĀ» (тŠøŠæŠ¾Š²ŠøŠ¹) Š°Š±Š¾ Ā«ifcfg-rhĀ».\n"
"\n"
-#: ../src/nmcli/connections.c:1391
+#: ../src/nmcli/connections.c:1507
#, c-format
msgid "Error updating secrets for %s: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ° ŠæіŠ“ чŠ°Ń ŠæрŠ¾Š±Šø Š¾Š½Š¾Š²Š»ŠµŠ½Š½Ń ŠæŠ°Ń€Š¾Š»Ń–Š² Š“Š»Ń %s: %s\n"
-#: ../src/nmcli/connections.c:1442
+#: ../src/nmcli/connections.c:1558
msgid "Connection profile details"
msgstr "ŠŸŠ°Ń€Š°Š¼ŠµŃ‚Ń€Šø ŠæрŠ¾Ń„Ń–Š»ŃŽ Š·'єŠ“Š½Š°Š½Š½Ń"
-#: ../src/nmcli/connections.c:1460 ../src/nmcli/connections.c:1567
+#: ../src/nmcli/connections.c:1576 ../src/nmcli/connections.c:1683
#, c-format
msgid "Error: 'connection show': %s"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«connection showĀ»: %s"
-#: ../src/nmcli/connections.c:1549
+#: ../src/nmcli/connections.c:1665
msgid "Active connection details"
msgstr "ŠŠŗтŠøŠ²ŃƒŠ²Š°Ń‚Šø ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Šø Š·'єŠ“Š½Š°Š½Š½Ń"
-#: ../src/nmcli/connections.c:1678 ../src/nmcli/devices.c:1637
+#: ../src/nmcli/connections.c:1794 ../src/nmcli/devices.c:1637
#: ../src/nmcli/devices.c:1654 ../src/nmcli/devices.c:1672
#: ../src/nmcli/devices.c:1691 ../src/nmcli/devices.c:1755
#: ../src/nmcli/devices.c:1884
msgid "NAME"
msgstr "ŠŠŠ—Š’Š"
-#: ../src/nmcli/connections.c:1778
+#: ../src/nmcli/connections.c:1894
#, c-format
msgid "invalid field '%s'; allowed fields: %s and %s, or %s,%s"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ ŠæŠ¾Š»Šµ Ā«%sĀ»; Š“Š¾Š·Š²Š¾Š»ŠµŠ½Ń– ŠæŠ¾Š»Ń: %s і %s Š°Š±Š¾ %s,%s"
-#: ../src/nmcli/connections.c:1795 ../src/nmcli/connections.c:1806
+#: ../src/nmcli/connections.c:1911 ../src/nmcli/connections.c:1922
#, c-format
msgid "'%s' has to be alone"
msgstr "Ā«%sĀ» Š¼Š°Ń” Š±ŃƒŃ‚Šø єŠ“ŠøŠ½ŠøŠ¼"
-#: ../src/nmcli/connections.c:2061
+#: ../src/nmcli/connections.c:2178
#, c-format
msgid "incorrect string '%s' of '--order' option"
msgstr "ŠæŠ¾Š¼ŠøŠ»ŠŗŠ¾Š²ŠøŠ¹ ряŠ“Š¾Šŗ Ā«%sĀ» у ŠæŠ°Ń€Š°Š¼ŠµŃ‚рі Ā«--orderĀ»"
-#: ../src/nmcli/connections.c:2085
+#: ../src/nmcli/connections.c:2202
#, c-format
msgid "incorrect item '%s' in '--order' option"
msgstr "ŠæŠ¾Š¼ŠøŠ»ŠŗŠ¾Š²ŠøŠ¹ ŠæуŠ½Šŗт Ā«%sĀ» у ŠæŠ°Ń€Š°Š¼ŠµŃ‚рі Ā«--orderĀ»"
-#: ../src/nmcli/connections.c:2125
+#: ../src/nmcli/connections.c:2247
msgid "No connection specified"
msgstr "ŠŠµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š·'єŠ“Š½Š°Š½Š½Ń"
-#: ../src/nmcli/connections.c:2138
+#: ../src/nmcli/connections.c:2260
#, c-format
msgid "%s argument is missing"
msgstr "ŠæрŠ¾ŠæущŠµŠ½Š¾ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ %s"
-#: ../src/nmcli/connections.c:2159
+#: ../src/nmcli/connections.c:2281
#, c-format
msgid "unknown connection '%s'"
msgstr "Š½ŠµŠ²Ń–Š“Š¾Š¼Šµ Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ»"
-#: ../src/nmcli/connections.c:2188
+#: ../src/nmcli/connections.c:2310
msgid "'--order' argument is missing"
msgstr "ŠæрŠ¾ŠæущŠµŠ½Š¾ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ Ā«--orderĀ»"
-#: ../src/nmcli/connections.c:2252
+#: ../src/nmcli/connections.c:2374
msgid "NetworkManager active profiles"
msgstr "ŠŠŗтŠøŠ²Š½Ń– ŠæрŠ¾Ń„Ń–Š»Ń– NetworkManager"
-#: ../src/nmcli/connections.c:2253
+#: ../src/nmcli/connections.c:2375
msgid "NetworkManager connection profiles"
msgstr "ŠŸŃ€Š¾Ń„Ń–Š»Ń– Š·'єŠ“Š½Š°Š½ŃŒ NetworkManager"
-#: ../src/nmcli/connections.c:2309 ../src/nmcli/connections.c:3030
-#: ../src/nmcli/connections.c:3042 ../src/nmcli/connections.c:3054
-#: ../src/nmcli/connections.c:3290 ../src/nmcli/connections.c:9448
-#: ../src/nmcli/connections.c:9470 ../src/nmcli/devices.c:3317
-#: ../src/nmcli/devices.c:3330 ../src/nmcli/devices.c:3342
-#: ../src/nmcli/devices.c:3646 ../src/nmcli/devices.c:3657
-#: ../src/nmcli/devices.c:3676 ../src/nmcli/devices.c:3685
-#: ../src/nmcli/devices.c:3707 ../src/nmcli/devices.c:3718
-#: ../src/nmcli/devices.c:3739 ../src/nmcli/devices.c:4303
-#: ../src/nmcli/devices.c:4314 ../src/nmcli/devices.c:4323
-#: ../src/nmcli/devices.c:4337 ../src/nmcli/devices.c:4355
-#: ../src/nmcli/devices.c:4364 ../src/nmcli/devices.c:4520
-#: ../src/nmcli/devices.c:4531 ../src/nmcli/devices.c:4750
-#: ../src/nmcli/devices.c:4929
+#: ../src/nmcli/connections.c:2431 ../src/nmcli/connections.c:3152
+#: ../src/nmcli/connections.c:3164 ../src/nmcli/connections.c:3176
+#: ../src/nmcli/connections.c:3412 ../src/nmcli/connections.c:9579
+#: ../src/nmcli/connections.c:9601 ../src/nmcli/devices.c:3323
+#: ../src/nmcli/devices.c:3336 ../src/nmcli/devices.c:3348
+#: ../src/nmcli/devices.c:3652 ../src/nmcli/devices.c:3663
+#: ../src/nmcli/devices.c:3682 ../src/nmcli/devices.c:3691
+#: ../src/nmcli/devices.c:3713 ../src/nmcli/devices.c:3724
+#: ../src/nmcli/devices.c:3745 ../src/nmcli/devices.c:4309
+#: ../src/nmcli/devices.c:4320 ../src/nmcli/devices.c:4329
+#: ../src/nmcli/devices.c:4343 ../src/nmcli/devices.c:4361
+#: ../src/nmcli/devices.c:4370 ../src/nmcli/devices.c:4526
+#: ../src/nmcli/devices.c:4537 ../src/nmcli/devices.c:4756
+#: ../src/nmcli/devices.c:4935
#, c-format
msgid "Error: %s argument is missing."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæрŠ¾ŠæущŠµŠ½Š¾ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ %s."
-#: ../src/nmcli/connections.c:2344
+#: ../src/nmcli/connections.c:2466
#, c-format
msgid "Error: %s - no such connection profile."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæрŠ¾Ń„Ń–Š»ŃŽ Š·'єŠ“Š½Š°Š½Š½Ń %s Š½Šµ ісŠ½ŃƒŃ”."
-#: ../src/nmcli/connections.c:2436 ../src/nmcli/connections.c:3016
-#: ../src/nmcli/connections.c:3090 ../src/nmcli/connections.c:8948
-#: ../src/nmcli/connections.c:9038 ../src/nmcli/connections.c:9577
-#: ../src/nmcli/devices.c:1984 ../src/nmcli/devices.c:2254
-#: ../src/nmcli/devices.c:2427 ../src/nmcli/devices.c:2551
-#: ../src/nmcli/devices.c:2738 ../src/nmcli/devices.c:3517
-#: ../src/nmcli/devices.c:4484 ../src/nmcli/devices.c:4936
+#: ../src/nmcli/connections.c:2558 ../src/nmcli/connections.c:3138
+#: ../src/nmcli/connections.c:3212 ../src/nmcli/connections.c:9085
+#: ../src/nmcli/connections.c:9169 ../src/nmcli/connections.c:9708
+#: ../src/nmcli/devices.c:1984 ../src/nmcli/devices.c:2260
+#: ../src/nmcli/devices.c:2433 ../src/nmcli/devices.c:2557
+#: ../src/nmcli/devices.c:2744 ../src/nmcli/devices.c:3523
+#: ../src/nmcli/devices.c:4490 ../src/nmcli/devices.c:4942
#: ../src/nmcli/general.c:1067
#, c-format
msgid "Error: %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: %s."
-#: ../src/nmcli/connections.c:2528 ../src/nmcli/devices.c:4703
+#: ../src/nmcli/connections.c:2650 ../src/nmcli/devices.c:4709
#, c-format
msgid "no active connection on device '%s'"
msgstr "Š½Š° ŠæрŠøстрŠ¾Ń— Ā«%sĀ» Š½ŠµŠ¼Š°Ń” Š°ŠŗтŠøŠ²Š½Šøх Š·'єŠ“Š½Š°Š½ŃŒ"
-#: ../src/nmcli/connections.c:2536
+#: ../src/nmcli/connections.c:2658
msgid "no active connection or device"
msgstr "Š½ŠµŠ¼Š°Ń” Š°ŠŗтŠøŠ²Š½Šøх Š·'єŠ“Š½Š°Š½ŃŒ Š°Š±Š¾ ŠæрŠøстрŠ¾Ń—Š²"
-#: ../src/nmcli/connections.c:2559
+#: ../src/nmcli/connections.c:2681
#, c-format
msgid "device '%s' not compatible with connection '%s': "
msgstr "ŠæрŠøстріŠ¹ Ā«%sĀ» Š½ŠµŃŃƒŠ¼Ń–сŠ½ŠøŠ¹ Š·Ń– Š·'єŠ“Š½Š°Š½Š½ŃŠ¼ Ā«%sĀ»: "
-#: ../src/nmcli/connections.c:2597
+#: ../src/nmcli/connections.c:2719
#, c-format
msgid "device '%s' not compatible with connection '%s'"
msgstr "ŠæрŠøстріŠ¹ Ā«%sĀ» Š½ŠµŃŃƒŠ¼Ń–сŠ½ŠøŠ¹ Š·Ń– Š·'єŠ“Š½Š°Š½Š½ŃŠ¼ Ā«%sĀ»"
-#: ../src/nmcli/connections.c:2604
+#: ../src/nmcli/connections.c:2726
#, c-format
msgid "device '%s' not found for connection '%s'"
msgstr "Š½Šµ Š·Š½Š°Š¹Š“ŠµŠ½Š¾ ŠæрŠøстрŠ¾ŃŽ Ā«%sĀ» Š“Š»Ń Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ»"
-#: ../src/nmcli/connections.c:2612
+#: ../src/nmcli/connections.c:2734
#, c-format
msgid "no device found for connection '%s'"
msgstr "Š½Šµ Š²ŠøяŠ²Š»ŠµŠ½Š¾ ŠæрŠøстрŠ¾ŃŽ Š“Š»Ń Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ»"
-#: ../src/nmcli/connections.c:2663
+#: ../src/nmcli/connections.c:2785
#, c-format
msgid "Hint: use '%s' to get more details."
msgstr "ŠŸŃ–Š“ŠŗŠ°Š·ŠŗŠ°: сŠŗŠ¾Ń€ŠøстŠ°Š¹Ń‚ŠµŃŃ Ā«%sĀ», щŠ¾Š± Š¾Š·Š½Š°Š¹Š¾Š¼ŠøтŠøся іŠ· ŠæŠ¾Š“рŠ¾Š±ŠøцяŠ¼Šø."
-#: ../src/nmcli/connections.c:2681
+#: ../src/nmcli/connections.c:2803
#, c-format
msgid "Connection successfully activated (%s) (D-Bus active path: %s)\n"
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń усŠæішŠ½Š¾ Š·Š°Š“іяŠ½Š¾ (%s) (Š°ŠŗтŠøŠ²Š½ŠøŠ¹ шŠ»ŃŃ… D-Bus: %s)\n"
-#: ../src/nmcli/connections.c:2685 ../src/nmcli/connections.c:2836
-#: ../src/nmcli/connections.c:7218
+#: ../src/nmcli/connections.c:2807 ../src/nmcli/connections.c:2958
+#: ../src/nmcli/connections.c:7338
#, c-format
msgid "Connection successfully activated (D-Bus active path: %s)\n"
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń усŠæішŠ½Š¾ Š·Š°Š“іяŠ½Š¾ (Š°ŠŗтŠøŠ²Š½ŠøŠ¹ шŠ»ŃŃ… D-Bus: %s)\n"
-#: ../src/nmcli/connections.c:2692 ../src/nmcli/connections.c:2815
+#: ../src/nmcli/connections.c:2814 ../src/nmcli/connections.c:2937
#, c-format
msgid "Error: Connection activation failed: %s"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š°ŠŗтŠøŠ²ŃƒŠ²Š°Ń‚Šø Š·'єŠ“Š½Š°Š½Š½Ń: %s"
-#: ../src/nmcli/connections.c:2728
+#: ../src/nmcli/connections.c:2850
#, c-format
msgid "Error: Timeout expired (%d seconds)"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠµŃ€ŠµŠ²ŠøщŠµŠ½Š¾ чŠ°Ń Š¾Ń‡Ń–ŠŗуŠ²Š°Š½Š½Ń (%d сŠµŠŗуŠ½Š“)."
-#: ../src/nmcli/connections.c:2910
+#: ../src/nmcli/connections.c:3032
#, c-format
msgid "unknown device '%s'."
msgstr "Š½ŠµŠ²Ń–Š“Š¾Š¼ŠøŠ¹ ŠæрŠøстріŠ¹, Ā«%sĀ»."
-#: ../src/nmcli/connections.c:2918
+#: ../src/nmcli/connections.c:3040
msgid "neither a valid connection nor device given"
msgstr "Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š½Ń– ŠŗŠ¾Ń€ŠµŠŗтŠ½Š¾Š³Š¾ Š·'єŠ“Š½Š°Š½Š½Ń, Š½Ń– ŠæрŠøстрŠ¾ŃŽ"
-#: ../src/nmcli/connections.c:2933
+#: ../src/nmcli/connections.c:3055
#, c-format
msgid "invalid passwd-file '%s' at line %zd: %s"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ фŠ°Š¹Š» passwd Ā«%sĀ» у ряŠ“Šŗу %zd: %s"
-#: ../src/nmcli/connections.c:2941
+#: ../src/nmcli/connections.c:3063
#, c-format
msgid "invalid passwd-file '%s': %s"
msgstr "Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ фŠ°Š¹Š» passwd Ā«%sĀ»: %s"
-#: ../src/nmcli/connections.c:3064 ../src/nmcli/connections.c:9481
+#: ../src/nmcli/connections.c:3186 ../src/nmcli/connections.c:9612
#: ../src/nmcli/devices.c:1941 ../src/nmcli/devices.c:1990
-#: ../src/nmcli/devices.c:2433 ../src/nmcli/devices.c:3377
-#: ../src/nmcli/devices.c:3755 ../src/nmcli/devices.c:4374
-#: ../src/nmcli/devices.c:4537 ../src/nmcli/devices.c:4758
-#: ../src/nmcli/devices.c:4941
+#: ../src/nmcli/devices.c:2439 ../src/nmcli/devices.c:3383
+#: ../src/nmcli/devices.c:3761 ../src/nmcli/devices.c:4380
+#: ../src/nmcli/devices.c:4543 ../src/nmcli/devices.c:4764
+#: ../src/nmcli/devices.c:4947
#, c-format
msgid "Error: invalid extra argument '%s'."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ Š“Š¾Š“Š°Ń‚ŠŗŠ¾Š²ŠøŠ¹ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚, Ā«%sĀ»."
-#: ../src/nmcli/connections.c:3098
+#: ../src/nmcli/connections.c:3220
msgid "preparing"
msgstr "ŠæрŠøŠ³Š¾Ń‚ŃƒŠ²Š°Š½Š½Ń"
-#: ../src/nmcli/connections.c:3206
+#: ../src/nmcli/connections.c:3328
#, c-format
msgid "Connection '%s' (%s) successfully deleted.\n"
msgstr "Š—Š°ŠæŠøс Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s) усŠæішŠ½Š¾ Š²ŠøŠ»ŃƒŃ‡ŠµŠ½Š¾.\n"
-#: ../src/nmcli/connections.c:3222
+#: ../src/nmcli/connections.c:3344
#, c-format
msgid "Connection '%s' successfully deactivated (D-Bus active path: %s)\n"
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ» усŠæішŠ½Š¾ Š²ŠøŠ¼ŠŗŠ½ŠµŠ½Š¾ (Š°ŠŗтŠøŠ²Š½ŠøŠ¹ шŠ»ŃŃ… D-Bus: %s)\n"
-#: ../src/nmcli/connections.c:3271 ../src/nmcli/connections.c:9134
-#: ../src/nmcli/connections.c:9169 ../src/nmcli/connections.c:9358
+#: ../src/nmcli/connections.c:3393 ../src/nmcli/connections.c:9265
+#: ../src/nmcli/connections.c:9300 ../src/nmcli/connections.c:9489
#, c-format
msgid "Error: No connection specified."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š·'єŠ“Š½Š°Š½Š½Ń."
-#: ../src/nmcli/connections.c:3303
+#: ../src/nmcli/connections.c:3425
#, c-format
msgid "Error: '%s' is not an active connection.\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«%sĀ» Š½Šµ є Š°ŠŗтŠøŠ²Š½ŠøŠ¼ Š·'єŠ“Š½Š°Š½Š½ŃŠ¼.\n"
-#: ../src/nmcli/connections.c:3304
+#: ../src/nmcli/connections.c:3426
#, c-format
msgid "Error: not all active connections found."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ усі Š°ŠŗтŠøŠ²Š½Ń– Š·'єŠ“Š½Š°Š½Š½Ń Š·Š½Š°Š¹Š“ŠµŠ½Š¾."
-#: ../src/nmcli/connections.c:3312
+#: ../src/nmcli/connections.c:3434
#, c-format
msgid "Error: no active connection provided."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š½Š°Š“Š°Š½Š¾ Š°ŠŗтŠøŠ²Š½Š¾Š³Š¾ Š·'єŠ“Š½Š°Š½Š½Ń."
-#: ../src/nmcli/connections.c:3344
+#: ../src/nmcli/connections.c:3466
#, c-format
msgid "Connection '%s' deactivation failed: %s\n"
msgstr "ŠŠµŠ²Š“Š°Š»Š° сŠæрŠ¾Š±Š° Š²ŠøŠ¼ŠŗŠ½ŃƒŃ‚Šø Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ»: %s\n"
-#: ../src/nmcli/connections.c:3825
+#: ../src/nmcli/connections.c:3947
#, c-format
msgid "Warning: master='%s' doesn't refer to any existing profile.\n"
msgstr ""
"ŠŸŠ¾ŠæŠµŃ€ŠµŠ“Š¶ŠµŠ½Š½Ń: master='%s' Š½Šµ ŠæŠ¾ŃŠøŠ»Š°Ń”Ń‚ŃŒŃŃ Š½Ń– Š½Š° Š¾Š“ŠøŠ½ Š· Š½Š°ŃŠ²Š½Šøх ŠæрŠ¾Ń„Ń–Š»Ń–Š².\n"
-#: ../src/nmcli/connections.c:4200
+#: ../src/nmcli/connections.c:4322
#, c-format
msgid "Error: invalid property '%s': %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Š° Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ, Ā«%sĀ»: %s."
-#: ../src/nmcli/connections.c:4217
+#: ../src/nmcli/connections.c:4339
#, c-format
msgid "Error: failed to %s %s.%s: %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ %s %s.%s: %s."
-#: ../src/nmcli/connections.c:4298
+#: ../src/nmcli/connections.c:4420
#, c-format
msgid "Error: invalid slave type; %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ тŠøŠæ ŠæіŠ“Š»ŠµŠ³Š»Š¾Š³Š¾; %s."
-#: ../src/nmcli/connections.c:4309
+#: ../src/nmcli/connections.c:4431
#, c-format
msgid "Error: invalid connection type; %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ тŠøŠæ Š·'єŠ“Š½Š°Š½Š½Ń; %s."
-#: ../src/nmcli/connections.c:4400
+#: ../src/nmcli/connections.c:4522
#, c-format
msgid "Error: bad connection type: %s"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ¾Š¼ŠøŠ»ŠŗŠ¾Š²ŠøŠ¹ тŠøŠæ Š·'єŠ“Š½Š°Š½Š½Ń: %s"
-#: ../src/nmcli/connections.c:4486
+#: ../src/nmcli/connections.c:4608
msgid "Error: master is required"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: сŠ»Ń–Š“ Š²ŠŗŠ°Š·Š°Ń‚Šø Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Ā«masterĀ»"
-#: ../src/nmcli/connections.c:4587
+#: ../src/nmcli/connections.c:4709
#, c-format
msgid "Error: '%s' is not a valid monitoring mode; use '%s' or '%s'.\n"
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ рŠµŠ¶ŠøŠ¼Š¾Š¼ сŠæŠ¾ŃŃ‚ŠµŃ€ŠµŠ¶ŠµŠ½Š½Ń; сŠŗŠ¾Ń€ŠøстŠ°Š¹Ń‚ŠµŃŃ Ā«%sĀ» Š°Š±Š¾ "
"Ā«%sĀ».\n"
-#: ../src/nmcli/connections.c:4626
+#: ../src/nmcli/connections.c:4748
#, c-format
msgid "Error: 'bt-type': '%s' not valid; use [%s, %s, %s (%s), %s]."
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«bt-typeĀ»: Ā«%sĀ» є Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼; сŠŗŠ¾Ń€ŠøстŠ°Š¹Ń‚ŠµŃŃ Š·Š½Š°Ń‡ŠµŠ½Š½ŃŠ¼ Š· ŠæŠµŃ€ŠµŠ»Ń–Šŗу "
"[%s, %s, %s (%s), %s]."
-#: ../src/nmcli/connections.c:4973
+#: ../src/nmcli/connections.c:5095
#, c-format
msgid "Error: setting '%s' is mandatory and cannot be removed."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ» є Š¾Š±Š¾Š²'яŠ·ŠŗŠ¾Š²ŠøŠ¼, Š¹Š¾Š³Š¾ Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠ»ŃƒŃ‡Š°Ń‚Šø."
-#: ../src/nmcli/connections.c:4989
+#: ../src/nmcli/connections.c:5111
#, c-format
msgid "Error: value for '%s' is missing."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«%sĀ»."
-#: ../src/nmcli/connections.c:5040
+#: ../src/nmcli/connections.c:5162
msgid "Error: <setting>.<property> argument is missing."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæрŠ¾ŠæущŠµŠ½Š¾ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ <ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€>.<Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ>."
-#: ../src/nmcli/connections.c:5082
+#: ../src/nmcli/connections.c:5204
msgid "Error: missing setting."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæрŠ¾ŠæущŠµŠ½Š¾ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€."
-#: ../src/nmcli/connections.c:5096
+#: ../src/nmcli/connections.c:5218
#, c-format
msgid "Error: invalid setting argument '%s'."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š°, Ā«%sĀ»."
-#: ../src/nmcli/connections.c:5127
+#: ../src/nmcli/connections.c:5249
#, c-format
msgid "Error: invalid or not allowed setting '%s': %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ Š°Š±Š¾ Š·Š°Š±Š¾Ń€Š¾Š½ŠµŠ½ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€, Ā«%sĀ»: %s."
-#: ../src/nmcli/connections.c:5186 ../src/nmcli/connections.c:5207
+#: ../src/nmcli/connections.c:5308 ../src/nmcli/connections.c:5329
#, c-format
msgid "Error: '%s' is ambiguous (%s.%s or %s.%s)."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«%sĀ» є Š½ŠµŠ¾Š“Š½Š¾Š·Š½Š°Ń‡Š½ŠøŠ¼ (%s.%s Š°Š±Š¾ %s.%s)."
-#: ../src/nmcli/connections.c:5231
+#: ../src/nmcli/connections.c:5353
#, c-format
msgid "Error: invalid <setting>.<property> '%s'."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ <ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€>.<Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ>, Ā«%sĀ»."
-#: ../src/nmcli/connections.c:5265
+#: ../src/nmcli/connections.c:5387 ../src/nmcli/devices.c:2159
#, c-format
msgid "Warning: %s.\n"
msgstr "ŠŸŠ¾ŠæŠµŃ€ŠµŠ“Š¶ŠµŠ½Š½Ń: %s.\n"
-#: ../src/nmcli/connections.c:5284
+#: ../src/nmcli/connections.c:5403
#, c-format
msgid ""
"Warning: There is another connection with the name '%1$s'. Reference the "
@@ -12079,7 +12128,7 @@ msgstr[3] ""
"ŠŸŠ¾ŠæŠµŃ€ŠµŠ“Š¶ŠµŠ½Š½Ń: ісŠ½ŃƒŃ” іŠ½ŃˆŠµ Š·'єŠ“Š½Š°Š½Š½Ń Š· Š½Š°Š·Š²Š¾ŃŽ Ā«%1$sĀ». ŠŸŠ¾ŃŠøŠ»Š°Š¹Ń‚ŠµŃŃ Š½Š° Š·'єŠ“Š½Š°Š½Š½Ń "
"Š·Š° Š¹Š¾Š³Š¾ UUID, Ā«%2$sĀ»\n"
-#: ../src/nmcli/connections.c:5306 ../src/nmcli/connections.c:8986
+#: ../src/nmcli/connections.c:5425 ../src/nmcli/connections.c:9117
#, c-format
msgid "Error: Failed to add '%s' connection: %s"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š“Š¾Š“Š°Ń‚Šø Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ»: %s"
@@ -12093,12 +12142,12 @@ msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š“Š¾Š“Š°Ń‚Šø Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ
#. *
#. * This is true for many messages that the user might parse. But this one
#. * seems in particular interesting for a user to parse.
-#: ../src/nmcli/connections.c:5323
+#: ../src/nmcli/connections.c:5442
#, c-format
msgid "Connection '%s' (%s) successfully added.\n"
msgstr "Š—Š°ŠæŠøс Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s) усŠæішŠ½Š¾ Š“Š¾Š“Š°Š½Š¾.\n"
-#: ../src/nmcli/connections.c:5467
+#: ../src/nmcli/connections.c:5577
#, c-format
msgid ""
"You can specify this option more than once. Press <Enter> when you're done.\n"
@@ -12107,7 +12156,7 @@ msgstr ""
"Š·Š°Š²ŠµŃ€ŃˆŠøтŠµ.\n"
#. Ask for optional arguments.
-#: ../src/nmcli/connections.c:5567
+#: ../src/nmcli/connections.c:5677
#, c-format
msgid "There is %d optional setting for %s.\n"
msgid_plural "There are %d optional settings for %s.\n"
@@ -12116,7 +12165,7 @@ msgstr[1] "Š”Š»Ń Ā«%2$sĀ» ŠæŠµŃ€ŠµŠ“Š±Š°Ń‡ŠµŠ½Š¾ %1$d Š“Š¾Š“Š°Ń‚ŠŗŠ¾Š²ŠøŠ¹ ŠæŠ°
msgstr[2] "Š”Š»Ń Š·'єŠ“Š½Š°Š½ŃŒ тŠøŠæу Ā«%2$sĀ» ŠæŠµŃ€ŠµŠ“Š±Š°Ń‡ŠµŠ½Š¾ %1$d Š“Š¾Š“Š°Ń‚ŠŗŠ¾Š²Šøх Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚Ń–Š².\n"
msgstr[3] "Š”Š»Ń Š·'єŠ“Š½Š°Š½ŃŒ тŠøŠæу Ā«%2$sĀ» ŠæŠµŃ€ŠµŠ“Š±Š°Ń‡ŠµŠ½Š¾ %1$d Š“Š¾Š“Š°Ń‚ŠŗŠ¾Š²ŠøŠ¹ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚.\n"
-#: ../src/nmcli/connections.c:5574
+#: ../src/nmcli/connections.c:5684
#, c-format
msgid "Do you want to provide it? %s"
msgid_plural "Do you want to provide them? %s"
@@ -12125,22 +12174,22 @@ msgstr[1] "Š„Š¾Ń‡ŠµŃ‚Šµ Š²ŠŗŠ°Š·Š°Ń‚Šø їх? %s"
msgstr[2] "Š„Š¾Ń‡ŠµŃ‚Šµ Š²ŠŗŠ°Š·Š°Ń‚Šø їх? %s"
msgstr[3] "Š„Š¾Ń‡ŠµŃ‚Šµ Š²ŠŗŠ°Š·Š°Ń‚Šø Š¹Š¾Š³Š¾? %s"
-#: ../src/nmcli/connections.c:5701 ../src/nmcli/utils.c:280
+#: ../src/nmcli/connections.c:5825 ../src/nmcli/utils.c:280
#, c-format
msgid "Error: value for '%s' argument is required."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: сŠ»Ń–Š“ Š²ŠŗŠ°Š·Š°Ń‚Šø Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«%sĀ» Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚Ńƒ."
-#: ../src/nmcli/connections.c:5708
+#: ../src/nmcli/connections.c:5832
#, c-format
msgid "Error: 'save': %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«saveĀ»: %s."
-#: ../src/nmcli/connections.c:5793 ../src/nmcli/connections.c:5806
+#: ../src/nmcli/connections.c:5917 ../src/nmcli/connections.c:5930
#, c-format
msgid "Error: '%s' argument is required."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: сŠ»Ń–Š“ Š²ŠŗŠ°Š·Š°Ń‚Šø ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ»."
-#: ../src/nmcli/connections.c:6767
+#: ../src/nmcli/connections.c:6887
#, c-format
msgid "['%s' setting values]\n"
msgstr "['%s' Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š°]\n"
@@ -12148,7 +12197,7 @@ msgstr "['%s' Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š°]\n"
#. TRANSLATORS: do not translate command names and keywords before ::
#. * However, you should translate terms enclosed in <>.
#.
-#: ../src/nmcli/connections.c:6878
+#: ../src/nmcli/connections.c:6998
#, c-format
msgid ""
"---[ Main menu ]---\n"
@@ -12182,7 +12231,7 @@ msgstr ""
"nmcli <ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€-Š½Š°Š»Š°ŃˆŃ‚.> <Š·Š½Š°Ń‡.> :: Š½Š°Š»Š°ŃˆŃ‚Š¾Š²ŃƒŠ²Š°Š½Š½Ń nmcli\n"
"quit :: Š·Š°Š²ŠµŃ€ŃˆŠøтŠø рŠ¾Š±Š¾Ń‚Ńƒ nmcli\n"
-#: ../src/nmcli/connections.c:6905
+#: ../src/nmcli/connections.c:7025
#, c-format
msgid ""
"goto <setting>[.<prop>] | <prop> :: enter setting/property for editing\n"
@@ -12203,7 +12252,7 @@ msgstr ""
" nmcli connection> goto secondaries\n"
" nmcli> goto ipv4.addresses\n"
-#: ../src/nmcli/connections.c:6913
+#: ../src/nmcli/connections.c:7033
#, c-format
msgid ""
"remove <setting>[.<prop>] :: remove setting or reset property value\n"
@@ -12225,7 +12274,7 @@ msgstr ""
"ŠŸŃ€ŠøŠŗŠ»Š°Š“Šø: nmcli> remove wifi-sec\n"
" nmcli> remove eth.mtu\n"
-#: ../src/nmcli/connections.c:6920
+#: ../src/nmcli/connections.c:7040
#, c-format
msgid ""
"set [<setting>.<prop> <value>] :: set property value\n"
@@ -12241,7 +12290,7 @@ msgstr ""
"\n"
"ŠŸŃ€ŠøŠŗŠ»Š°Š“: nmcli> s con.id My connection\n"
-#: ../src/nmcli/connections.c:6925
+#: ../src/nmcli/connections.c:7045
#, c-format
msgid ""
"add [<setting>.<prop> <value>] :: add property value\n"
@@ -12256,7 +12305,7 @@ msgstr ""
"\n"
"ŠŸŃ€ŠøŠŗŠ»Š°Š“: nmcli> add ipv4.addresses 192.168.1.1/24\n"
-#: ../src/nmcli/connections.c:6930
+#: ../src/nmcli/connections.c:7050
#, c-format
msgid ""
"describe [<setting>.<prop>] :: describe property\n"
@@ -12269,7 +12318,7 @@ msgstr ""
"ŠŸŠ¾ŠŗŠ°Š·ŃƒŃ” Š¾ŠæŠøс Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń–. Š”ŠæŠøсŠ¾Šŗ усіх ŠæŠ°Ń€Š°Š¼ŠµŃ‚ріŠ² і Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚ŠµŠ¹ NM Š¼Š¾Š¶Š½Š° "
"Š·Š½Š°Š¹Ń‚Šø Š½Š° стŠ¾Ń€Ń–Š½Ń†Ń– Š“Š¾Š²Ń–Š“Š½ŠøŠŗŠ° (man) nm-settings(5).\n"
-#: ../src/nmcli/connections.c:6935
+#: ../src/nmcli/connections.c:7055
#, c-format
msgid ""
"print [all] :: print setting or connection values\n"
@@ -12284,7 +12333,7 @@ msgstr ""
"\n"
"ŠŸŃ€ŠøŠŗŠ»Š°Š“: nmcli ipv4> print all\n"
-#: ../src/nmcli/connections.c:6941
+#: ../src/nmcli/connections.c:7061
#, c-format
msgid ""
"verify [all | fix] :: verify setting or connection validity\n"
@@ -12309,7 +12358,7 @@ msgstr ""
" nmcli> verify fix\n"
" nmcli bond> verify\n"
-#: ../src/nmcli/connections.c:6951
+#: ../src/nmcli/connections.c:7071
#, c-format
msgid ""
"save [persistent|temporary] :: save the connection\n"
@@ -12336,7 +12385,7 @@ msgstr ""
"ŠæŠ¾Ń‚ріŠ±Š½Š¾\n"
"ŠæŠ¾Š²Š½Ń–стю Š²ŠøŠ»ŃƒŃ‡ŠøтŠø ŠæŠ¾ŃŃ‚Ń–Š¹Š½Šµ Š·'єŠ“Š½Š°Š½Š½Ń, Š²Š°Š¼ Š“Š¾Š²ŠµŠ“ŠµŃ‚ŃŒŃŃ Š²ŠøŠ»ŃƒŃ‡ŠøтŠø Š¹Š¾Š³Š¾ ŠæрŠ¾Ń„Ń–Š»ŃŒ.\n"
-#: ../src/nmcli/connections.c:6962
+#: ../src/nmcli/connections.c:7082
#, c-format
msgid ""
"activate [<ifname>] [/<ap>|<nsp>] :: activate the connection\n"
@@ -12357,7 +12406,7 @@ msgstr ""
"/<ap>|<nsp> - AP (Wi-Fi) Š°Š±Š¾ NSP (WiMAX) (Š“Š¾Š“Š°Š¹Ń‚Šµ Š½Š° ŠæŠ¾Ń‡Š°Ń‚Šŗу Ā«/Ā», яŠŗщŠ¾ Š½Šµ "
"Š²ŠŗŠ°Š·Š°Š½Š¾ <іŠ½Ń‚ŠµŃ€Ń„ŠµŠ¹Ń>)\n"
-#: ../src/nmcli/connections.c:6970 ../src/nmcli/connections.c:7129
+#: ../src/nmcli/connections.c:7090 ../src/nmcli/connections.c:7249
#, c-format
msgid ""
"back :: go to upper menu level\n"
@@ -12366,7 +12415,7 @@ msgstr ""
"back :: ŠæіŠ“Š½ŃŃ‚Šøся у Š¼ŠµŠ½ŃŽ Š½Š° Š¾Š“ŠøŠ½ ріŠ²ŠµŠ½ŃŒ\n"
"\n"
-#: ../src/nmcli/connections.c:6973
+#: ../src/nmcli/connections.c:7093
#, c-format
msgid ""
"help/? [<command>] :: help for the nmcli commands\n"
@@ -12375,7 +12424,7 @@ msgstr ""
"help/? [<ŠŗŠ¾Š¼Š°Š½Š“Š°>] :: Š“Š¾Š²Ń–Š“ŠŗŠ° Š· ŠŗŠ¾Š¼Š°Š½Š“Šø nmcli\n"
"\n"
-#: ../src/nmcli/connections.c:6976
+#: ../src/nmcli/connections.c:7096
#, c-format
msgid ""
"nmcli [<conf-option> <value>] :: nmcli configuration\n"
@@ -12402,7 +12451,7 @@ msgstr ""
" nmcli> nmcli save-confirmation no\n"
" nmcli> nmcli prompt-color 3\n"
-#: ../src/nmcli/connections.c:6998 ../src/nmcli/connections.c:7135
+#: ../src/nmcli/connections.c:7118 ../src/nmcli/connections.c:7255
#, c-format
msgid ""
"quit :: exit nmcli\n"
@@ -12416,8 +12465,8 @@ msgstr ""
"Š·Š°ŠæŠøс Š·'єŠ“Š½Š°Š½Š½Ń Š½Šµ Š±ŃƒŠ»Š¾ Š·Š±ŠµŃ€ŠµŠ¶ŠµŠ½Š¾, ŠŗŠ¾Ń€ŠøстуŠ²Š°Ń‡ŠµŠ²Ń– Š±ŃƒŠ“Šµ Š·Š°ŠæрŠ¾ŠæŠ¾Š½Š¾Š²Š°Š½Š¾ "
"ŠæіŠ“тŠ²ŠµŃ€Š“ŠøтŠø Š“ію Š· Š²ŠøхŠ¾Š“у Š· ŠæрŠ¾Š³Ń€Š°Š¼Šø.\n"
-#: ../src/nmcli/connections.c:7003 ../src/nmcli/connections.c:7140
-#: ../src/nmcli/connections.c:7528 ../src/nmcli/connections.c:8556
+#: ../src/nmcli/connections.c:7123 ../src/nmcli/connections.c:7260
+#: ../src/nmcli/connections.c:7648 ../src/nmcli/connections.c:8680
#, c-format
msgid "Unknown command: '%s'\n"
msgstr "ŠŠµŠ²Ń–Š“Š¾Š¼Š° ŠŗŠ¾Š¼Š°Š½Š“Š° Ā«%sĀ».\n"
@@ -12425,7 +12474,7 @@ msgstr "ŠŠµŠ²Ń–Š“Š¾Š¼Š° ŠŗŠ¾Š¼Š°Š½Š“Š° Ā«%sĀ».\n"
#. TRANSLATORS: do not translate command names and keywords before ::
#. * However, you should translate terms enclosed in <>.
#.
-#: ../src/nmcli/connections.c:7068
+#: ../src/nmcli/connections.c:7188
#, c-format
msgid ""
"---[ Property menu ]---\n"
@@ -12452,7 +12501,7 @@ msgstr ""
"help/? [<ŠŗŠ¾Š¼Š°Š½Š“Š°>] :: Š²ŠøŠ²ŠµŃŃ‚Šø цю Š“Š¾Š²Ń–Š“Šŗу Š°Š±Š¾ Š¾ŠæŠøс ŠŗŠ¾Š¼Š°Š½Š“Šø\n"
"quit :: Š²ŠøŠ¹Ń‚Šø Š· nmcli\n"
-#: ../src/nmcli/connections.c:7092
+#: ../src/nmcli/connections.c:7212
#, c-format
msgid ""
"set [<value>] :: set new value\n"
@@ -12464,7 +12513,7 @@ msgstr ""
"Š—Š° Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾ŃŽ цієї ŠŗŠ¾Š¼Š°Š½Š“Šø Š¼Š¾Š¶Š½Š° Š·Š¼Ń–Š½ŠøтŠø Š·Š½Š°Ń‡ŠµŠ½Š½Ń Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń– Š½Š° Š²ŠŗŠ°Š·Š°Š½Šµ "
"<Š·Š½Š°Ń‡ŠµŠ½Š½Ń>\n"
-#: ../src/nmcli/connections.c:7096
+#: ../src/nmcli/connections.c:7216
#, c-format
msgid ""
"add [<value>] :: append new value to the property\n"
@@ -12479,7 +12528,7 @@ msgstr ""
"яŠŗщŠ¾ Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ Š½Š°Š»ŠµŠ¶Šøть Š“Š¾ тŠøŠæу ŠŗŠ¾Š½Ń‚ŠµŠ¹Š½ŠµŃ€Ń–Š². ŠÆŠŗщŠ¾ Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ сŠŗŠ»Š°Š“Š°Ń”Ń‚ŃŒŃŃ "
"Š»ŠøшŠµ Š· Š¾Š“Š½Š¾Š³Š¾ Š·Š½Š°Ń‡ŠµŠ½Š½Ń, цŠµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń Š±ŃƒŠ“Šµ Š·Š°Š¼Ń–Š½ŠµŠ½Š¾ (тŠµ сŠ°Š¼Šµ, щŠ¾ і Ā«setĀ»).\n"
-#: ../src/nmcli/connections.c:7102
+#: ../src/nmcli/connections.c:7222
#, c-format
msgid ""
"change :: change current value\n"
@@ -12490,7 +12539,7 @@ msgstr ""
"\n"
"ŠŸŠ¾ŠŗŠ°Š·ŃƒŃ” ŠæŠ¾Ń‚Š¾Ń‡Š½Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń і Š½Š°Š“Š°Ń” Š·Š¼Š¾Š³Ńƒ Š¹Š¾Š³Š¾ рŠµŠ“Š°Š³ŃƒŠ²Š°Ń‚Šø.\n"
-#: ../src/nmcli/connections.c:7107
+#: ../src/nmcli/connections.c:7227
#, c-format
msgid ""
"remove [<value>|<index>|<option name>] :: delete the value\n"
@@ -12523,7 +12572,7 @@ msgstr ""
" nmcli bond.options> remove downdelay\n"
"\n"
-#: ../src/nmcli/connections.c:7118
+#: ../src/nmcli/connections.c:7238
#, c-format
msgid ""
"describe :: describe property\n"
@@ -12536,7 +12585,7 @@ msgstr ""
"ŠŸŠ¾ŠŗŠ°Š·ŃƒŃ” Š¾ŠæŠøс Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń–. Š”ŠæŠøсŠ¾Šŗ усіх ŠæŠ°Ń€Š°Š¼ŠµŃ‚ріŠ² і Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚ŠµŠ¹ NM Š¼Š¾Š¶Š½Š° "
"Š·Š½Š°Š¹Ń‚Šø Š½Š° стŠ¾Ń€Ń–Š½Ń†Ń– Š“Š¾Š²Ń–Š“Š½ŠøŠŗŠ° (man) nm-settings(5).\n"
-#: ../src/nmcli/connections.c:7123
+#: ../src/nmcli/connections.c:7243
#, c-format
msgid ""
"print [property|setting|connection] :: print property (setting, connection) "
@@ -12551,7 +12600,7 @@ msgstr ""
"Š’ŠøŠ²Š¾Š“Šøть Š·Š½Š°Ń‡ŠµŠ½Š½Ń Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń–. Š—Š° Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾ŃŽ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚Ńƒ ŠŗŠ¾Š¼Š°Š½Š“Šø Š²Šø Š¼Š¾Š¶ŠµŃ‚Šµ "
"Š²ŠøŠ²Š¾Š“ŠøтŠø Š·Š½Š°Ń‡ŠµŠ½Š½Ń усьŠ¾Š³Š¾ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Š°Š±Š¾ усьŠ¾Š³Š¾ Š·Š°ŠæŠøсу Š·'єŠ“Š½Š°Š½Š½Ń.\n"
-#: ../src/nmcli/connections.c:7132
+#: ../src/nmcli/connections.c:7252
#, c-format
msgid ""
"help/? [<command>] :: help for nmcli commands\n"
@@ -12560,24 +12609,24 @@ msgstr ""
"help/? [<ŠŗŠ¾Š¼Š°Š½Š“Š°>] :: Š“Š¾Š²Ń–Š“ŠŗŠ° Š· ŠŗŠ¾Š¼Š°Š½Š“Šø nmcli\n"
"\n"
-#: ../src/nmcli/connections.c:7224
+#: ../src/nmcli/connections.c:7344
#, c-format
msgid "Error: Connection activation failed.\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ²Š“Š°Š»Š° сŠæрŠ¾Š±Š° Š°ŠŗтŠøŠ²Š°Ń†Ń–Ń— Š·'єŠ“Š½Š°Š½Š½Ń.\n"
#. TRANSLATORS: status line in nmcli connection editor
-#: ../src/nmcli/connections.c:7322
+#: ../src/nmcli/connections.c:7442
#, c-format
msgid "[ Type: %s | Name: %s | UUID: %s | Dirty: %s | Temp: %s ]\n"
msgstr "[ Š¢ŠøŠæ: %s | ŠŠ°Š·Š²Š°: %s | UUID: %s | ŠŠµ Š·Š±ŠµŃ€ŠµŠ¶ŠµŠ½Š¾: %s | Š¢ŠøŠ¼Ń‡.: %s ]\n"
-#: ../src/nmcli/connections.c:7360
+#: ../src/nmcli/connections.c:7480
#, c-format
msgid "The connection is not saved. Do you really want to quit? %s"
msgstr ""
"Š—'єŠ“Š½Š°Š½Š½Ń Š½Šµ Š·Š±ŠµŃ€ŠµŠ¶ŠµŠ½Š¾. Š’Šø сŠæрŠ°Š²Š“і хŠ¾Ń‡ŠµŃ‚Šµ Š·Š°Š²ŠµŃ€ŃˆŠøтŠø рŠ¾Š±Š¾Ń‚Ńƒ ŠæрŠ¾Š³Ń€Š°Š¼Šø? %s"
-#: ../src/nmcli/connections.c:7404
+#: ../src/nmcli/connections.c:7524
#, c-format
msgid ""
"The connection profile has been removed from another client. You may type "
@@ -12586,60 +12635,60 @@ msgstr ""
"ŠŸŃ€Š¾Ń„Ń–Š»ŃŒ Š·'єŠ“Š½Š°Š½Š½Ń Š±ŃƒŠ»Š¾ Š²ŠøŠ»ŃƒŃ‡ŠµŠ½Š¾ Š· іŠ½ŃˆŠ¾Š³Š¾ ŠŗŠ»Ń–Ń”Š½Ń‚Š°. Š’Šø Š¼Š¾Š¶ŠµŃ‚Šµ Š²Š²ŠµŃŃ‚Šø Ā«saveĀ» у "
"Š³Š¾Š»Š¾Š²Š½Š¾Š¼Ńƒ Š¼ŠµŠ½ŃŽ, щŠ¾Š± Š²Ń–Š“Š½Š¾Š²ŠøтŠø Š¹Š¾Š³Š¾.\n"
-#: ../src/nmcli/connections.c:7436 ../src/nmcli/connections.c:7828
-#: ../src/nmcli/connections.c:7898
+#: ../src/nmcli/connections.c:7556 ../src/nmcli/connections.c:7948
+#: ../src/nmcli/connections.c:8018
#, c-format
msgid "Allowed values for '%s' property: %s\n"
msgstr "ŠœŠ¾Š¶Š»ŠøŠ²Ń– Š·Š½Š°Ń‡ŠµŠ½Š½Ń Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń– Ā«%sĀ»: %s\n"
-#: ../src/nmcli/connections.c:7438 ../src/nmcli/connections.c:7831
-#: ../src/nmcli/connections.c:7900
+#: ../src/nmcli/connections.c:7558 ../src/nmcli/connections.c:7951
+#: ../src/nmcli/connections.c:8020
#, c-format
msgid "Enter '%s' value: "
msgstr "Š’Š²ŠµŠ“іть Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«%sĀ»: "
-#: ../src/nmcli/connections.c:7451 ../src/nmcli/connections.c:7468
-#: ../src/nmcli/connections.c:7839 ../src/nmcli/connections.c:7911
+#: ../src/nmcli/connections.c:7571 ../src/nmcli/connections.c:7588
+#: ../src/nmcli/connections.c:7959 ../src/nmcli/connections.c:8031
#, c-format
msgid "Error: failed to set '%s' property: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š²ŃŃ‚Š°Š½Š¾Š²ŠøтŠø Š·Š½Š°Ń‡ŠµŠ½Š½Ń Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń– Ā«%sĀ»: %s\n"
-#: ../src/nmcli/connections.c:7460
+#: ../src/nmcli/connections.c:7580
#, c-format
msgid "Edit '%s' value: "
msgstr "Š ŠµŠ“Š°Š³ŃƒŠ²Š°Š½Š½Ń Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«%sĀ»: "
-#: ../src/nmcli/connections.c:7481 ../src/nmcli/settings.c:440
+#: ../src/nmcli/connections.c:7601 ../src/nmcli/settings.c:440
#, c-format
msgid "Error: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: %s\n"
-#: ../src/nmcli/connections.c:7500
+#: ../src/nmcli/connections.c:7620
#, c-format
msgid "Unknown command argument: '%s'\n"
msgstr "ŠŠµŠ²Ń–Š“Š¾Š¼ŠøŠ¹ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ ŠŗŠ¾Š¼Š°Š½Š“Šø: Ā«%sĀ»\n"
-#: ../src/nmcli/connections.c:7595
+#: ../src/nmcli/connections.c:7715
#, c-format
msgid "Available settings: %s\n"
msgstr "Š”Š¾ŃŃ‚ŃƒŠæŠ½Ń– ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Šø: %s\n"
-#: ../src/nmcli/connections.c:7606
+#: ../src/nmcli/connections.c:7726
#, c-format
msgid "Error: invalid setting name; %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Š° Š½Š°Š·Š²Š° ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š°; %s\n"
-#: ../src/nmcli/connections.c:7623
+#: ../src/nmcli/connections.c:7743
#, c-format
msgid "Available properties: %s\n"
msgstr "Š”Š¾ŃŃ‚ŃƒŠæŠ½Ń– Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń–: %s\n"
-#: ../src/nmcli/connections.c:7631
+#: ../src/nmcli/connections.c:7751
#, c-format
msgid "Error: property %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ %s\n"
-#: ../src/nmcli/connections.c:7676
+#: ../src/nmcli/connections.c:7796
#, c-format
msgid ""
"Saving the connection with 'autoconnect=yes'. That might result in an "
@@ -12650,12 +12699,12 @@ msgstr ""
"Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Š¼Š¾Š¶Šµ ŠæрŠøŠ·Š²ŠµŃŃ‚Šø Š“Š¾ Š½ŠµŠ³Š°Š¹Š½Š¾Š³Š¾ Š·Š°Š“іяŠ½Š½Ń Š·'єŠ“Š½Š°Š½Š½Ń.\n"
"Š„Š¾Ń‡ŠµŃ‚Šµ Š·Š±ŠµŃ€ŠµŠ³Ń‚Šø Š·Š°ŠæŠøс? %s"
-#: ../src/nmcli/connections.c:7762
+#: ../src/nmcli/connections.c:7882
#, c-format
msgid "You may edit the following settings: %s\n"
msgstr "ŠœŠ¾Š¶Š½Š° рŠµŠ“Š°Š³ŃƒŠ²Š°Ń‚Šø тŠ°Šŗі ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Šø: %s\n"
-#: ../src/nmcli/connections.c:7790
+#: ../src/nmcli/connections.c:7910
#, c-format
msgid ""
"The connection profile has been removed from another client. You may type "
@@ -12664,234 +12713,234 @@ msgstr ""
"ŠŸŃ€Š¾Ń„Ń–Š»ŃŒ Š·'єŠ“Š½Š°Š½Š½Ń Š±ŃƒŠ»Š¾ Š²ŠøŠ»ŃƒŃ‡ŠµŠ½Š¾ Š· іŠ½ŃˆŠ¾Š³Š¾ ŠŗŠ»Ń–Ń”Š½Ń‚Š°. Š’Šø Š¼Š¾Š¶ŠµŃ‚Šµ Š²Š²ŠµŃŃ‚Šø Ā«saveĀ», "
"щŠ¾Š± Š²Ń–Š“Š½Š¾Š²ŠøтŠø Š¹Š¾Š³Š¾.\n"
-#: ../src/nmcli/connections.c:7845 ../src/nmcli/connections.c:8127
-#: ../src/nmcli/connections.c:8160
+#: ../src/nmcli/connections.c:7965 ../src/nmcli/connections.c:8247
+#: ../src/nmcli/connections.c:8280
#, c-format
msgid "Error: no setting selected; valid are [%s]\n"
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠøŠ±Ń€Š°Š½Š¾ Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š°; ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼Šø Š·Š½Š°Ń‡ŠµŠ½Š½ŃŠ¼Šø є тŠ°Šŗі: [%s]\n"
-#: ../src/nmcli/connections.c:7846
+#: ../src/nmcli/connections.c:7966
#, c-format
msgid "use 'goto <setting>' first, or 'set <setting>.<property>'\n"
msgstr ""
"сŠæŠ¾Ń‡Š°Ń‚Šŗу сŠŗŠ¾Ń€ŠøстŠ°Š¹Ń‚ŠµŃŃ ŠŗŠ¾Š¼Š°Š½Š“Š¾ŃŽ Ā«goto <ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€>Ā» Š°Š±Š¾ ŠŗŠ¾Š¼Š°Š½Š“Š¾ŃŽ Ā«set "
"<ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€>.<Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ>Ā»\n"
-#: ../src/nmcli/connections.c:7866 ../src/nmcli/connections.c:8043
-#: ../src/nmcli/connections.c:8149
+#: ../src/nmcli/connections.c:7986 ../src/nmcli/connections.c:8163
+#: ../src/nmcli/connections.c:8269
#, c-format
msgid "Error: invalid setting argument '%s'; valid are [%s]\n"
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š°, Ā«%sĀ»; ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼Šø є тŠ°Šŗі ŠŸŠŠ ŠŠœŠ•Š¢Š Š˜: "
"[%s]\n"
-#: ../src/nmcli/connections.c:7876
+#: ../src/nmcli/connections.c:7996
#, c-format
msgid "Error: missing setting for '%s' property\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Š“Š»Ń Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń– Ā«%sĀ»\n"
-#: ../src/nmcli/connections.c:7883
+#: ../src/nmcli/connections.c:8003
#, c-format
msgid "Error: invalid property: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Š° Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ: %s\n"
-#: ../src/nmcli/connections.c:7944
+#: ../src/nmcli/connections.c:8064
#, c-format
msgid "Error: unknown setting '%s'\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ²Ń–Š“Š¾Š¼Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«%sĀ»\n"
-#: ../src/nmcli/connections.c:7970
+#: ../src/nmcli/connections.c:8090
#, c-format
msgid "You may edit the following properties: %s\n"
msgstr "ŠœŠ¾Š¶Š½Š° рŠµŠ“Š°Š³ŃƒŠ²Š°Ń‚Šø Š·Š½Š°Ń‡ŠµŠ½Š½Ń тŠ°ŠŗŠøх Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚ŠµŠ¹: %s\n"
-#: ../src/nmcli/connections.c:8016 ../src/nmcli/connections.c:8077
+#: ../src/nmcli/connections.c:8136 ../src/nmcli/connections.c:8197
#, c-format
msgid "Error: failed to remove value of '%s': %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š²ŠøŠ»ŃƒŃ‡ŠøтŠø Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«%sĀ»: %s\n"
-#: ../src/nmcli/connections.c:8022
+#: ../src/nmcli/connections.c:8142
#, c-format
msgid "Error: no argument given; valid are [%s]\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚Ńƒ; ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼Šø Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚Š°Š¼Šø є тŠ°Šŗі: [%s]\n"
-#: ../src/nmcli/connections.c:8041
+#: ../src/nmcli/connections.c:8161
#, c-format
msgid "Setting '%s' is not present in the connection.\n"
msgstr "Š£ Š·'єŠ“Š½Š°Š½Š½Ń Š½ŠµŠ¼Š°Ń” ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Ā«%sĀ».\n"
-#: ../src/nmcli/connections.c:8103
+#: ../src/nmcli/connections.c:8223
#, c-format
msgid "Error: %s properties, nor it is a setting name.\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń– %s і Š½Šµ є Š½Š°Š·Š²Š¾ŃŽ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š°.\n"
-#: ../src/nmcli/connections.c:8128 ../src/nmcli/connections.c:8161
+#: ../src/nmcli/connections.c:8248 ../src/nmcli/connections.c:8281
#, c-format
msgid "use 'goto <setting>' first, or 'describe <setting>.<property>'\n"
msgstr ""
"сŠŗŠ¾Ń€ŠøстŠ°Š¹Ń‚ŠµŃŃ сŠæŠ¾Ń‡Š°Ń‚Šŗу ŠŗŠ¾Š¼Š°Š½Š“Š¾ŃŽ Ā«goto <ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€> Š°Š±Š¾ ŠŗŠ¾Š¼Š°Š½Š“Š¾ŃŽ Ā«describe "
"<ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€>.<Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ>Ā»\n"
-#: ../src/nmcli/connections.c:8184
+#: ../src/nmcli/connections.c:8304
#, c-format
msgid "Error: invalid property: %s, neither a valid setting name.\n"
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Š° Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ: %s і Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½Š¾ŃŽ Š½Š°Š·Š²Š¾ŃŽ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š°.\n"
-#: ../src/nmcli/connections.c:8214
+#: ../src/nmcli/connections.c:8334
#, c-format
msgid "Error: unknown setting: '%s'\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ²Ń–Š“Š¾Š¼ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€: Ā«%sĀ»\n"
-#: ../src/nmcli/connections.c:8219
+#: ../src/nmcli/connections.c:8339
#, c-format
msgid "Error: '%s' setting not present in the connection\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: у Š·'єŠ“Š½Š°Š½Š½Ń Š½ŠµŠ¼Š°Ń” ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Ā«%sĀ».\n"
-#: ../src/nmcli/connections.c:8251
+#: ../src/nmcli/connections.c:8371
#, c-format
msgid "Error: invalid property: %s%s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Š° Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ: %s%s\n"
-#: ../src/nmcli/connections.c:8253
+#: ../src/nmcli/connections.c:8373
msgid ", neither a valid setting name"
msgstr ", і Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½Š¾ŃŽ Š½Š°Š·Š²Š¾ŃŽ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š°"
-#: ../src/nmcli/connections.c:8269
+#: ../src/nmcli/connections.c:8389
#, c-format
msgid "Invalid verify option: %s\n"
msgstr "ŠŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ verify: %s\n"
-#: ../src/nmcli/connections.c:8277
+#: ../src/nmcli/connections.c:8397
#, c-format
msgid "Verify setting '%s': %s\n"
msgstr "ŠŸŠµŃ€ŠµŠ²Ń–Ń€ŠŗŠ° ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° Ā«%sĀ»: %s\n"
-#: ../src/nmcli/connections.c:8292
+#: ../src/nmcli/connections.c:8412
#, c-format
msgid "Verify connection: %s\n"
msgstr "ŠŸŠµŃ€ŠµŠ²Ń–Ń€ŠŗŠ° Š·'єŠ“Š½Š°Š½Š½Ń: %s\n"
-#: ../src/nmcli/connections.c:8294
+#: ../src/nmcli/connections.c:8414
#, c-format
msgid "The error cannot be fixed automatically.\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»Šŗу Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠæрŠ°Š²ŠøтŠø у Š°Š²Ń‚Š¾Š¼Š°Ń‚ŠøчŠ½Š¾Š¼Ńƒ рŠµŠ¶ŠøŠ¼Ń–.\n"
-#: ../src/nmcli/connections.c:8314
+#: ../src/nmcli/connections.c:8434
#, c-format
msgid "Error: invalid argument '%s'\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ Ā«%sĀ»\n"
-#: ../src/nmcli/connections.c:8367
+#: ../src/nmcli/connections.c:8491
#, c-format
msgid "Error: Failed to save '%s' (%s) connection: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š“Š¾Š“Š°Ń‚Šø Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s): %s\n"
-#: ../src/nmcli/connections.c:8373
+#: ../src/nmcli/connections.c:8497
#, c-format
msgid "Error: Timeout saving '%s' (%s) connection\n"
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠµŃ€ŠµŠ²ŠøщŠµŠ½Š½Ń чŠ°ŃŃƒ Š¾Ń‡Ń–ŠŗуŠ²Š°Š½Š½Ń Š½Š° Š·Š±ŠµŃ€ŠµŠ¶ŠµŠ½Š½Ń Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s)\n"
-#: ../src/nmcli/connections.c:8377
+#: ../src/nmcli/connections.c:8501
#, c-format
msgid "Connection '%s' (%s) successfully saved.\n"
msgstr "Š—Š°ŠæŠøс Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s) усŠæішŠ½Š¾ Š·Š±ŠµŃ€ŠµŠ¶ŠµŠ½Š¾.\n"
-#: ../src/nmcli/connections.c:8378
+#: ../src/nmcli/connections.c:8502
#, c-format
msgid "Connection '%s' (%s) successfully updated.\n"
msgstr "Š—Š°ŠæŠøс Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s) усŠæішŠ½Š¾ Š¾Š½Š¾Š²Š»ŠµŠ½Š¾.\n"
-#: ../src/nmcli/connections.c:8412
+#: ../src/nmcli/connections.c:8536
#, c-format
msgid "Error: connection verification failed: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š·'єŠ“Š½Š°Š½Š½Ń Š½Šµ ŠæрŠ¾Š¹ŃˆŠ»Š¾ ŠæŠµŃ€ŠµŠ²Ń–Ń€ŠŗŠø: %s\n"
-#: ../src/nmcli/connections.c:8413
+#: ../src/nmcli/connections.c:8537
msgid "(unknown error)"
msgstr "(Š½ŠµŠ²Ń–Š“Š¾Š¼Š° ŠæŠ¾Š¼ŠøŠ»ŠŗŠ°)"
-#: ../src/nmcli/connections.c:8414
+#: ../src/nmcli/connections.c:8538
#, c-format
msgid "You may try running 'verify fix' to fix errors.\n"
msgstr "Š’Šø Š¼Š¾Š¶ŠµŃ‚Šµ сŠæрŠ¾Š±ŃƒŠ²Š°Ń‚Šø Š·Š°ŠæустŠøтŠø Ā«verify fixĀ» Š“Š»Ń Š²ŠøŠæрŠ°Š²Š»ŠµŠ½Š½Ń ŠæŠ¾Š¼ŠøŠ»Š¾Šŗ.\n"
#. TRANSLATORS: do not translate 'save', leave it as it is
-#: ../src/nmcli/connections.c:8437
+#: ../src/nmcli/connections.c:8561
#, c-format
msgid "Error: connection is not saved. Type 'save' first.\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š·'єŠ“Š½Š°Š½Š½Ń Š½Šµ Š·Š±ŠµŃ€ŠµŠ¶ŠµŠ½Š¾. Š”ŠæŠ¾Ń‡Š°Ń‚Šŗу Š²Š²ŠµŠ“іть Ā«saveĀ».\n"
-#: ../src/nmcli/connections.c:8441
+#: ../src/nmcli/connections.c:8565
#, c-format
msgid "Error: connection is not valid: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š·'єŠ“Š½Š°Š½Š½Ń: %s\n"
-#: ../src/nmcli/connections.c:8457
+#: ../src/nmcli/connections.c:8581
#, c-format
msgid "Error: Cannot activate connection: %s.\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š·Š°Š“іятŠø Š·'єŠ“Š½Š°Š½Š½Ń: %s.\n"
-#: ../src/nmcli/connections.c:8466
+#: ../src/nmcli/connections.c:8590
#, c-format
msgid "Error: Failed to activate '%s' (%s) connection: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š·Š°Š“іятŠø Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s): %s\n"
-#: ../src/nmcli/connections.c:8473
+#: ../src/nmcli/connections.c:8597
msgid "Monitoring connection activation (press any key to continue)\n"
msgstr ""
"Š”ŠæŠ¾ŃŃ‚ŠµŃ€Ń–Š³Š°Ń”Š¼Š¾ Š·Š° Š°ŠŗтŠøŠ²Š°Ń†Ń–єю Š·'єŠ“Š½Š°Š½Š½Ń (Š½Š°Ń‚ŠøсŠ½Ń–Ń‚ŃŒ Š±ŃƒŠ“ь-яŠŗу ŠŗŠ»Š°Š²Ń–ŃˆŃƒ, щŠ¾Š± "
"ŠæрŠ¾Š“Š¾Š²Š¶ŠøтŠø)\n"
-#: ../src/nmcli/connections.c:8508
+#: ../src/nmcli/connections.c:8632
#, c-format
msgid "Error: status-line: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ряŠ“Š¾Šŗ стŠ°Š½Ńƒ: %s\n"
-#: ../src/nmcli/connections.c:8516
+#: ../src/nmcli/connections.c:8640
#, c-format
msgid "Error: save-confirmation: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: save-confirmation: %s\n"
-#: ../src/nmcli/connections.c:8524
+#: ../src/nmcli/connections.c:8648
#, c-format
msgid "Error: show-secrets: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: show-secrets: %s\n"
-#: ../src/nmcli/connections.c:8532
+#: ../src/nmcli/connections.c:8656
#, c-format
msgid "Current nmcli configuration:\n"
msgstr "ŠŸŠ¾Ń‚Š¾Ń‡Š½Šµ Š½Š°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½Š½Ń nmcli:\n"
-#: ../src/nmcli/connections.c:8540
+#: ../src/nmcli/connections.c:8664
#, c-format
msgid "Invalid configuration option '%s'; allowed [%s]\n"
msgstr ""
"ŠŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Š½Š°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Š½Š½Ń, Ā«%sĀ»; Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾Ń€ŠøстŠ¾Š²ŃƒŠ²Š°Ń‚Šø Š»ŠøшŠµ тŠ°Šŗі: "
"[%s]\n"
-#: ../src/nmcli/connections.c:8772
+#: ../src/nmcli/connections.c:8896
#, c-format
msgid "Error: only one of 'id', 'filename', uuid, or 'path' can be provided."
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š¼Š¾Š¶Š½Š° Š²ŠŗŠ°Š·ŃƒŠ²Š°Ń‚Šø Š»ŠøшŠµ Š¾Š“ŠøŠ½ Š· ŠæŠ°Ń€Š°Š¼ŠµŃ‚ріŠ² Ā«idĀ», Ā«filenameĀ», uuid Š°Š±Š¾ "
"Ā«pathĀ»."
-#: ../src/nmcli/connections.c:8787 ../src/nmcli/connections.c:8956
+#: ../src/nmcli/connections.c:8911
#, c-format
msgid "Error: Unknown connection '%s'."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ²Ń–Š“Š¾Š¼Šµ Š·'єŠ“Š½Š°Š½Š½Ń, Ā«%sĀ»."
-#: ../src/nmcli/connections.c:8804
+#: ../src/nmcli/connections.c:8928
#, c-format
msgid "Warning: editing existing connection '%s'; 'type' argument is ignored\n"
msgstr ""
"ŠŸŠ¾ŠæŠµŃ€ŠµŠ“Š¶ŠµŠ½Š½Ń: рŠµŠ“Š°Š³ŃƒŠ²Š°Š½Š½Ń Š²Š¶Šµ стŠ²Š¾Ń€ŠµŠ½Š¾Š³Š¾ Š·Š°ŠæŠøсу Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ»; Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ "
"Ā«typeĀ» ŠæрŠ¾Ń–Š³Š½Š¾Ń€Š¾Š²Š°Š½Š¾\n"
-#: ../src/nmcli/connections.c:8808
+#: ../src/nmcli/connections.c:8932
#, c-format
msgid ""
"Warning: editing existing connection '%s'; 'con-name' argument is ignored\n"
@@ -12899,227 +12948,227 @@ msgstr ""
"ŠŸŠ¾ŠæŠµŃ€ŠµŠ“Š¶ŠµŠ½Š½Ń: рŠµŠ“Š°Š³ŃƒŠ²Š°Š½Š½Ń Š²Š¶Šµ стŠ²Š¾Ń€ŠµŠ½Š¾Š³Š¾ Š·Š°ŠæŠøсу Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ»; Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ "
"Ā«con-nameĀ» ŠæрŠ¾Ń–Š³Š½Š¾Ń€Š¾Š²Š°Š½Š¾\n"
-#: ../src/nmcli/connections.c:8835
+#: ../src/nmcli/connections.c:8959
#, c-format
msgid "Valid connection types: %s\n"
msgstr "ŠšŠ¾Ń€ŠµŠŗтŠ½Ń– тŠøŠæŠø Š·'єŠ“Š½Š°Š½ŃŒ: %s\n"
-#: ../src/nmcli/connections.c:8837
+#: ../src/nmcli/connections.c:8961
#, c-format
msgid "Error: invalid connection type; %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ тŠøŠæ Š·'єŠ“Š½Š°Š½Š½Ń; %s\n"
-#: ../src/nmcli/connections.c:8876
+#: ../src/nmcli/connections.c:9000
#, c-format
msgid "===| nmcli interactive connection editor |==="
msgstr "===| Š†Š½Ń‚ŠµŃ€Š°ŠŗтŠøŠ²Š½ŠøŠ¹ рŠµŠ“Š°ŠŗтŠ¾Ń€ Š·'єŠ“Š½Š°Š½ŃŒ nmcli |==="
-#: ../src/nmcli/connections.c:8879
+#: ../src/nmcli/connections.c:9003
#, c-format
msgid "Editing existing '%s' connection: '%s'"
msgstr "Š ŠµŠ“Š°Š³ŃƒŠ²Š°Š½Š½Ń Š½Š°ŃŠ²Š½Š¾Š³Š¾ Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ»: Ā«%sĀ»"
-#: ../src/nmcli/connections.c:8881
+#: ../src/nmcli/connections.c:9005
#, c-format
msgid "Adding a new '%s' connection"
msgstr "Š”Š¾Š“Š°Š²Š°Š½Š½Ń Š½Š¾Š²Š¾Š³Š¾ Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ»"
#. TRANSLATORS: do not translate 'help', leave it as it is
-#: ../src/nmcli/connections.c:8884
+#: ../src/nmcli/connections.c:9008
#, c-format
msgid "Type 'help' or '?' for available commands."
msgstr "Š’Š²ŠµŠ“іть Ā«helpĀ» Š°Š±Š¾ Ā«?Ā», щŠ¾Š± Š¾Š·Š½Š°Š¹Š¾Š¼ŠøтŠøся Š·Ń– сŠæŠøсŠŗŠ¾Š¼ Š“Š¾ŃŃ‚ŃƒŠæŠ½Šøх ŠŗŠ¾Š¼Š°Š½Š“."
#. TRANSLATORS: do not translate 'print', leave it as it is
-#: ../src/nmcli/connections.c:8887
+#: ../src/nmcli/connections.c:9011
#, c-format
msgid "Type 'print' to show all the connection properties."
msgstr "Š’Š²ŠµŠ“іть Ā«printĀ», щŠ¾Š± ŠæŠ¾Š±Š°Ń‡ŠøтŠø усі Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń– Š·'єŠ“Š½Š°Š½Š½Ń."
#. TRANSLATORS: do not translate 'describe', leave it as it is
-#: ../src/nmcli/connections.c:8890
+#: ../src/nmcli/connections.c:9014
#, c-format
msgid "Type 'describe [<setting>.<prop>]' for detailed property description."
msgstr ""
"Š©Š¾Š± Š¾Š·Š½Š°Š¹Š¾Š¼ŠøтŠøся Š· Š“Š¾ŠŗŠ»Š°Š“Š½ŠøŠ¼ Š¾ŠæŠøсŠ¾Š¼ Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń–, сŠŗŠ¾Ń€ŠøстŠ°Š¹Ń‚ŠµŃŃ ŠŗŠ¾Š¼Š°Š½Š“Š¾ŃŽ "
"Ā«describe [<ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€>.<Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ>]."
-#: ../src/nmcli/connections.c:8917
+#: ../src/nmcli/connections.c:9041
#, c-format
msgid "Error: Failed to modify connection '%s': %s"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š²Š½ŠµŃŃ‚Šø Š·Š¼Ń–Š½Šø Š“Š¾ Š·Š°ŠæŠøсу Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ»: %s"
-#: ../src/nmcli/connections.c:8925
+#: ../src/nmcli/connections.c:9049
#, c-format
msgid "Connection '%s' (%s) successfully modified.\n"
msgstr "Š—Š¼Ń–Š½Šø Š“Š¾ Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s) усŠæішŠ½Š¾ Š²Š½ŠµŃŠµŠ½Š¾.\n"
-#: ../src/nmcli/connections.c:8991
+#: ../src/nmcli/connections.c:9122
#, c-format
msgid "%s (%s) cloned as %s (%s).\n"
msgstr "%s (%s) ŠŗŠ»Š¾Š½Š¾Š²Š°Š½Š¾ яŠŗ %s (%s).\n"
-#: ../src/nmcli/connections.c:9049
+#: ../src/nmcli/connections.c:9180
msgid "New connection name: "
msgstr "ŠŠ¾Š²Š° Š½Š°Š·Š²Š° Š·'єŠ“Š½Š°Š½Š½Ń: "
-#: ../src/nmcli/connections.c:9051
+#: ../src/nmcli/connections.c:9182
#, c-format
msgid "Error: <new name> argument is missing."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ <Š½Š¾Š²Š° Š½Š°Š·Š²Š°>."
-#: ../src/nmcli/connections.c:9057 ../src/nmcli/connections.c:9588
+#: ../src/nmcli/connections.c:9188 ../src/nmcli/connections.c:9719
#, c-format
msgid "Error: unknown extra argument: '%s'."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ²Ń–Š“Š¾Š¼ŠøŠ¹ Š·Š°Š¹Š²ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€: Ā«%sĀ»."
-#: ../src/nmcli/connections.c:9091
+#: ../src/nmcli/connections.c:9222
#, c-format
msgid "Error: not all connections deleted."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š²ŠøŠ»ŃƒŃ‡ŠµŠ½Š¾ Š½Šµ усі Š·'єŠ“Š½Š°Š½Š½Ń."
-#: ../src/nmcli/connections.c:9092
+#: ../src/nmcli/connections.c:9223
#, c-format
msgid "Error: Connection deletion failed: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š²ŠøŠ»ŃƒŃ‡ŠøтŠø Š·'єŠ“Š½Š°Š½Š½Ń: %s\n"
-#: ../src/nmcli/connections.c:9147 ../src/nmcli/connections.c:9274
-#: ../src/nmcli/connections.c:9741
+#: ../src/nmcli/connections.c:9278 ../src/nmcli/connections.c:9405
+#: ../src/nmcli/connections.c:9872
#, c-format
msgid "Error: %s.\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: %s.\n"
-#: ../src/nmcli/connections.c:9148 ../src/nmcli/connections.c:9275
-#: ../src/nmcli/connections.c:9742
+#: ../src/nmcli/connections.c:9279 ../src/nmcli/connections.c:9406
+#: ../src/nmcli/connections.c:9873
#, c-format
msgid "Error: not all connections found."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š·Š½Š°Š¹Š“ŠµŠ½Š¾ Š½Šµ усі Š·'єŠ“Š½Š°Š½Š½Ń."
-#: ../src/nmcli/connections.c:9207
+#: ../src/nmcli/connections.c:9338
#, c-format
msgid "Error: cannot delete unknown connection(s): %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠ»ŃƒŃ‡Š°Ń‚Šø Š½ŠµŠ²Ń–Š“Š¾Š¼Ń– Š·'єŠ“Š½Š°Š½Š½Ń: %s."
-#: ../src/nmcli/connections.c:9215
+#: ../src/nmcli/connections.c:9346
#, c-format
msgid "%s: connection profile changed\n"
msgstr "%s: Š·Š¼Ń–Š½ŠµŠ½Š¾ ŠæрŠ¾Ń„Ń–Š»ŃŒ Š·'єŠ“Š½Š°Š½Š½Ń\n"
-#: ../src/nmcli/connections.c:9241
+#: ../src/nmcli/connections.c:9372
#, c-format
msgid "%s: connection profile created\n"
msgstr "%s: стŠ²Š¾Ń€ŠµŠ½Š¾ ŠæрŠ¾Ń„Ń–Š»ŃŒ Š·'єŠ“Š½Š°Š½Š½Ń\n"
-#: ../src/nmcli/connections.c:9250
+#: ../src/nmcli/connections.c:9381
#, c-format
msgid "%s: connection profile removed\n"
msgstr "%s: Š²ŠøŠ»ŃƒŃ‡ŠµŠ½Š¾ ŠæрŠ¾Ń„Ń–Š»ŃŒ Š·'єŠ“Š½Š°Š½Š½Ń\n"
-#: ../src/nmcli/connections.c:9318
+#: ../src/nmcli/connections.c:9449
#, c-format
msgid "Error: failed to reload connections: %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŠæŠµŃ€ŠµŠ·Š°Š²Š°Š½Ń‚Š°Š¶ŠøтŠø Š·'єŠ“Š½Š°Š½Š½Ń: %s."
-#: ../src/nmcli/connections.c:9390
+#: ../src/nmcli/connections.c:9521
#, c-format
msgid "Error: failed to load connection: %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š·Š°Š²Š°Š½Ń‚Š°Š¶ŠøтŠø Š·'єŠ“Š½Š°Š½Š½Ń: %s."
-#: ../src/nmcli/connections.c:9398
+#: ../src/nmcli/connections.c:9529
#, c-format
msgid "Could not load file '%s'\n"
msgstr "ŠŠµ Š²Š“Š°Š»Š¾ŃŃ Š·Š°Š²Š°Š½Ń‚Š°Š¶ŠøтŠø фŠ°Š¹Š» Ā«%sĀ»\n"
-#: ../src/nmcli/connections.c:9402
+#: ../src/nmcli/connections.c:9533
msgid "File to import: "
msgstr "Š¤Š°Š¹Š» Š“Š»Ń іŠ¼ŠæŠ¾Ń€Ń‚ŃƒŠ²Š°Š½Š½Ń: "
-#: ../src/nmcli/connections.c:9433
+#: ../src/nmcli/connections.c:9564
#, c-format
msgid "Error: No arguments provided."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š½Š°Š“Š°Š½Š¾ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚Ń–Š²."
-#: ../src/nmcli/connections.c:9464
+#: ../src/nmcli/connections.c:9595
#, c-format
msgid "Warning: 'type' already specified, ignoring extra one.\n"
msgstr ""
"ŠŸŠ¾ŠæŠµŃ€ŠµŠ“Š¶ŠµŠ½Š½Ń: Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«typeĀ» Š²Š¶Šµ Š·Š°Š“Š°Š½Š¾, Š·Š°Š¹Š²Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠæрŠ¾Ń–Š³Š½Š¾Ń€Š¾Š²Š°Š½Š¾.\n"
-#: ../src/nmcli/connections.c:9479
+#: ../src/nmcli/connections.c:9610
#, c-format
msgid "Warning: 'file' already specified, ignoring extra one.\n"
msgstr ""
"ŠŸŠ¾ŠæŠµŃ€ŠµŠ“Š¶ŠµŠ½Š½Ń: Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«fileĀ» Š²Š¶Šµ Š·Š°Š“Š°Š½Š¾, Š·Š°Š¹Š²Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠæрŠ¾Ń–Š³Š½Š¾Ń€Š¾Š²Š°Š½Š¾.\n"
-#: ../src/nmcli/connections.c:9493
+#: ../src/nmcli/connections.c:9624
#, c-format
msgid "Error: 'type' argument is required."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: сŠ»Ń–Š“ Š²ŠŗŠ°Š·Š°Ń‚Šø Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«typeĀ»."
-#: ../src/nmcli/connections.c:9498
+#: ../src/nmcli/connections.c:9629
#, c-format
msgid "Error: 'file' argument is required."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: сŠ»Ń–Š“ Š²ŠŗŠ°Š·Š°Ń‚Šø Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«fileĀ»."
-#: ../src/nmcli/connections.c:9508
+#: ../src/nmcli/connections.c:9639
#, c-format
msgid "Error: failed to find VPN plugin for %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š·Š½Š°Š¹Ń‚Šø Š“Š¾Š“Š°Ń‚Š¾Šŗ VPN Š“Š»Ń %s."
-#: ../src/nmcli/connections.c:9517 ../src/nmcli/connections.c:9609
+#: ../src/nmcli/connections.c:9648 ../src/nmcli/connections.c:9740
#, c-format
msgid "Error: failed to load VPN plugin: %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š·Š°Š²Š°Š½Ń‚Š°Š¶ŠøтŠø Š“Š¾Š“Š°Ń‚Š¾Šŗ VPN: %s."
-#: ../src/nmcli/connections.c:9528
+#: ../src/nmcli/connections.c:9659
#, c-format
msgid "Error: failed to import '%s': %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ іŠ¼ŠæŠ¾Ń€Ń‚ŃƒŠ²Š°Ń‚Šø Ā«%sĀ»: %s."
-#: ../src/nmcli/connections.c:9594
+#: ../src/nmcli/connections.c:9725
msgid "Output file name: "
msgstr "ŠŠ°Š·Š²Š° фŠ°Š¹Š»Š° рŠµŠ·ŃƒŠ»ŃŒŃ‚Š°Ń‚Ń–Š²: "
-#: ../src/nmcli/connections.c:9599
+#: ../src/nmcli/connections.c:9730
#, c-format
msgid "Error: the connection is not VPN."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š·'єŠ“Š½Š°Š½Š½Ń Š½Šµ Š½Š°Š»ŠµŠ¶Šøть Š“Š¾ тŠøŠæу VPN."
-#: ../src/nmcli/connections.c:9623
+#: ../src/nmcli/connections.c:9754
#, c-format
msgid "Error: failed to create temporary file %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ стŠ²Š¾Ń€ŠøтŠø тŠøŠ¼Ń‡Š°ŃŠ¾Š²ŠøŠ¹ фŠ°Š¹Š» %s."
-#: ../src/nmcli/connections.c:9633
+#: ../src/nmcli/connections.c:9764
#, c-format
msgid "Error: failed to export '%s': %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŠµŠŗсŠæŠ¾Ń€Ń‚ŃƒŠ²Š°Ń‚Šø Ā«%sĀ»: %s."
-#: ../src/nmcli/connections.c:9647
+#: ../src/nmcli/connections.c:9778
#, c-format
msgid "Error: failed to read temporary file '%s': %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŠæрŠ¾Ń‡ŠøтŠ°Ń‚Šø тŠøŠ¼Ń‡Š°ŃŠ¾Š²ŠøŠ¹ фŠ°Š¹Š» Ā«%sĀ»: %s."
-#: ../src/nmcli/connections.c:9671
+#: ../src/nmcli/connections.c:9802
#, c-format
msgid "Error: not all connections migrated."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠµŃ€ŠµŠ½ŠµŃŠµŠ½Š¾ Š½Šµ усі Š·'єŠ“Š½Š°Š½Š½Ń."
-#: ../src/nmcli/connections.c:9672
+#: ../src/nmcli/connections.c:9803
#, c-format
msgid "Error: Connection migration failed: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŠæŠµŃ€ŠµŠ½ŠµŃŃ‚Šø Š·'єŠ“Š½Š°Š½Š½Ń: %s\n"
-#: ../src/nmcli/connections.c:9676
+#: ../src/nmcli/connections.c:9807
#, c-format
msgid "Connection '%s' (%s) successfully migrated.\n"
msgstr "Š—Š°ŠæŠøс Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s) усŠæішŠ½Š¾ ŠæŠµŃ€ŠµŠ½ŠµŃŠµŠ½Š¾.\n"
-#: ../src/nmcli/connections.c:9708
+#: ../src/nmcli/connections.c:9839
msgid "'--plugin' argument is missing"
msgstr "ŠæрŠ¾ŠæущŠµŠ½Š¾ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ Š“Š¾ --plugin"
-#: ../src/nmcli/connections.c:9804
+#: ../src/nmcli/connections.c:9935
#, c-format
msgid "Error: cannot migrate unknown connection(s): %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŠæŠµŃ€ŠµŠ½ŠµŃŃ‚Šø Š½ŠµŠ²Ń–Š“Š¾Š¼Ń– Š·'єŠ“Š½Š°Š½Š½Ń: %s."
@@ -13673,148 +13722,148 @@ msgstr ""
msgid "Error: Connection activation failed: (%d) %s.\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š°ŠŗтŠøŠ²ŃƒŠ²Š°Ń‚Šø Š·'єŠ“Š½Š°Š½Š½Ń: (%d) %s.\n"
-#: ../src/nmcli/devices.c:2139
+#: ../src/nmcli/devices.c:2140
#, c-format
msgid "Error: Failed to setup a Wi-Fi hotspot: %s"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š½Š°Š»Š°ŃˆŃ‚ŃƒŠ²Š°Ń‚Šø тŠ¾Ń‡Šŗу Š“Š¾ŃŃ‚ŃƒŠæу Wi-Fi: %s"
-#: ../src/nmcli/devices.c:2143
+#: ../src/nmcli/devices.c:2144
#, c-format
msgid "Error: Failed to add/activate new connection: %s"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š“Š¾Š“Š°Ń‚Šø Š°Š±Š¾ Š·Š°Š“іятŠø Š½Š¾Š²Šµ Š·'єŠ“Š½Š°Š½Š½Ń: %s"
-#: ../src/nmcli/devices.c:2147
+#: ../src/nmcli/devices.c:2148
#, c-format
msgid "Error: Failed to activate connection: %s"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š·Š°Š“іятŠø Š·'єŠ“Š½Š°Š½Š½Ń: %s"
-#: ../src/nmcli/devices.c:2210
+#: ../src/nmcli/devices.c:2216
#, c-format
msgid "Error: Device activation failed: %s"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š°ŠŗтŠøŠ²ŃƒŠ²Š°Ń‚Šø ŠæрŠøстріŠ¹: %s"
-#: ../src/nmcli/devices.c:2260
+#: ../src/nmcli/devices.c:2266
#, c-format
msgid "Error: extra argument not allowed: '%s'."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ Š“Š¾Š“Š°Ń‚ŠŗŠ¾Š²ŠøŠ¹ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚, Ā«%sĀ»."
-#: ../src/nmcli/devices.c:2329 ../src/nmcli/devices.c:2342
-#: ../src/nmcli/devices.c:2601
+#: ../src/nmcli/devices.c:2335 ../src/nmcli/devices.c:2348
+#: ../src/nmcli/devices.c:2607
#, c-format
msgid "Device '%s' successfully disconnected.\n"
msgstr "ŠŸŃ€ŠøстріŠ¹ Ā«%sĀ» усŠæішŠ½Š¾ Š²Ń–Š“'єŠ“Š½Š°Š½Š¾.\n"
-#: ../src/nmcli/devices.c:2331 ../src/nmcli/devices.c:2671
+#: ../src/nmcli/devices.c:2337 ../src/nmcli/devices.c:2677
#, c-format
msgid "Device '%s' successfully removed.\n"
msgstr "ŠŸŃ€ŠøстріŠ¹ Ā«%sĀ» усŠæішŠ½Š¾ Š²ŠøŠ»ŃƒŃ‡ŠµŠ½Š¾.\n"
-#: ../src/nmcli/devices.c:2397 ../src/nmcli/devices.c:2477
+#: ../src/nmcli/devices.c:2403 ../src/nmcli/devices.c:2483
#, c-format
msgid "Error: Reapplying connection to device '%s' (%s) failed: %s"
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŠæŠ¾Š²Ń‚Š¾Ń€Š½Š¾ Š·Š°ŃŃ‚Š¾ŃŃƒŠ²Š°Ń‚Šø Š·'єŠ“Š½Š°Š½Š½Ń іŠ· ŠæрŠøстрŠ¾Ń”Š¼ Ā«%sĀ» (%s): %s"
-#: ../src/nmcli/devices.c:2407 ../src/nmcli/devices.c:2486
+#: ../src/nmcli/devices.c:2413 ../src/nmcli/devices.c:2492
#, c-format
msgid "Connection successfully reapplied to device '%s'.\n"
msgstr "Š—'єŠ“Š½Š°Š½Š½Ń усŠæішŠ½Š¾ ŠæŠ¾Š²Ń‚Š¾Ń€Š½Š¾ Š·Š°ŃŃ‚Š¾ŃŠ¾Š²Š°Š½Š¾ Š“Š¾ ŠæрŠøстрŠ¾ŃŽ Ā«%sĀ».\n"
-#: ../src/nmcli/devices.c:2508
+#: ../src/nmcli/devices.c:2514
#, c-format
msgid "Error: Reading applied connection from device '%s' (%s) failed: %s"
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: сŠæрŠ¾Š±Š° чŠøтŠ°Š½Š½Ń Š·Š°ŃŃ‚Š¾ŃŠ¾Š²Š°Š½Š¾Š³Š¾ Š·'єŠ“Š½Š°Š½Š½Ń Š· ŠæрŠøстрŠ¾ŃŽ Ā«%sĀ» (%s) Š·Š°Š·Š½Š°Š»Š° "
"Š½ŠµŠ²Š“Š°Ń‡Ń–: %s"
-#: ../src/nmcli/devices.c:2585
+#: ../src/nmcli/devices.c:2591
#, c-format
msgid "Error: not all devices disconnected."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ усі ŠæрŠøстрŠ¾Ń— Š²Ń–Š“'єŠ“Š½Š°Š½Š¾."
-#: ../src/nmcli/devices.c:2586
+#: ../src/nmcli/devices.c:2592
#, c-format
msgid "Error: Device '%s' (%s) disconnecting failed: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ²Š“Š°Š»Š° сŠæрŠ¾Š±Š° Š²Ń–Š“'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s): %s\n"
-#: ../src/nmcli/devices.c:2662
+#: ../src/nmcli/devices.c:2668
#, c-format
msgid "Error: not all devices deleted."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š²ŠøŠ»ŃƒŃ‡ŠµŠ½Š¾ Š½Šµ усі ŠæрŠøстрŠ¾Ń—."
-#: ../src/nmcli/devices.c:2663
+#: ../src/nmcli/devices.c:2669
#, c-format
msgid "Error: Device '%s' (%s) deletion failed: %s\n"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ¾Š¼ŠøŠ»ŠŗŠ° ŠæіŠ“ чŠ°Ń сŠæрŠ¾Š±Šø Š²ŠøŠ»ŃƒŃ‡ŠµŠ½Š½Ń ŠæрŠøстрŠ¾ŃŽ Ā«%sĀ» (%s): %s\n"
-#: ../src/nmcli/devices.c:2744
+#: ../src/nmcli/devices.c:2750
#, c-format
msgid "Error: No property specified."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń–."
-#: ../src/nmcli/devices.c:2761 ../src/nmcli/devices.c:2780
+#: ../src/nmcli/devices.c:2767 ../src/nmcli/devices.c:2786
#: ../src/nmcli/general.c:796 ../src/nmcli/general.c:818
#, c-format
msgid "Error: '%s' argument is missing."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæрŠ¾ŠæущŠµŠ½Š¾ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ %s."
-#: ../src/nmcli/devices.c:2769
+#: ../src/nmcli/devices.c:2775
#, c-format
msgid "Error: 'managed': %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«managedĀ»: %s."
-#: ../src/nmcli/devices.c:2788
+#: ../src/nmcli/devices.c:2794
#, c-format
msgid "Error: 'autoconnect': %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«autoconnectĀ»: %s."
-#: ../src/nmcli/devices.c:2795 ../src/nmcli/general.c:868
+#: ../src/nmcli/devices.c:2801 ../src/nmcli/general.c:868
#, c-format
msgid "Error: property '%s' is not known."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š²Š»Š°ŃŃ‚ŠøŠ²Ń–ŃŃ‚ŃŒ Ā«%sĀ» є Š½ŠµŠ²Ń–Š“Š¾Š¼Š¾ŃŽ."
-#: ../src/nmcli/devices.c:2842
+#: ../src/nmcli/devices.c:2848
#, c-format
msgid "%s: using connection '%s'\n"
msgstr "%s: Š²ŠøŠŗŠ¾Ń€ŠøстŠ¾Š²ŃƒŃ”Š¼Š¾ Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ»\n"
-#: ../src/nmcli/devices.c:2868
+#: ../src/nmcli/devices.c:2874
#, c-format
msgid "%s: device created\n"
msgstr "%s: стŠ²Š¾Ń€ŠµŠ½Š¾ Š·Š°ŠæŠøс ŠæрŠøстрŠ¾ŃŽ\n"
-#: ../src/nmcli/devices.c:2875
+#: ../src/nmcli/devices.c:2881
#, c-format
msgid "%s: device removed\n"
msgstr "%s: ŠæрŠøстріŠ¹ Š²ŠøŠ»ŃƒŃ‡ŠµŠ½Š¾\n"
-#: ../src/nmcli/devices.c:3051
+#: ../src/nmcli/devices.c:3057
msgid "Wi-Fi scan list"
msgstr "Š”ŠæŠøсŠ¾Šŗ сŠŗŠ°Š½ŃƒŠ²Š°Š½Š½Ń Wi-Fi"
-#: ../src/nmcli/devices.c:3168 ../src/nmcli/devices.c:3449
+#: ../src/nmcli/devices.c:3174 ../src/nmcli/devices.c:3455
#, c-format
msgid "Error: Access point with bssid '%s' not found."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š·Š½Š°Š¹Š“ŠµŠ½Š¾ тŠ¾Ń‡ŠŗŠø Š“Š¾ŃŃ‚ŃƒŠæу Š· bssid Ā«%sĀ»."
-#: ../src/nmcli/devices.c:3370
+#: ../src/nmcli/devices.c:3376
#, c-format
msgid "Error: 'device wifi': %s"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«device wifiĀ»: %s"
-#: ../src/nmcli/devices.c:3390
+#: ../src/nmcli/devices.c:3396
#, c-format
msgid "Error: invalid rescan argument: '%s' not among [auto, no, yes]"
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚ rescan: Ā«%sĀ» Š½Šµ Š½Š°Š»ŠµŠ¶Šøть Š“Š¾ Š½Š°Š±Š¾Ń€Ńƒ [auto, no, "
"yes]"
-#: ../src/nmcli/devices.c:3429
+#: ../src/nmcli/devices.c:3435
#, c-format
msgid "Error: Device '%s' not found."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š·Š½Š°Š¹Š“ŠµŠ½Š¾ ŠæрŠøстріŠ¹ Ā«%sĀ»."
-#: ../src/nmcli/devices.c:3433
+#: ../src/nmcli/devices.c:3439
#, c-format
msgid ""
"Error: Device '%s' was not recognized as a Wi-Fi device, check "
@@ -13823,28 +13872,28 @@ msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæрŠøстріŠ¹ Ā«%sĀ» Š½Šµ рŠ¾Š·ŠæіŠ·Š½Š°Š½Š¾ яŠŗ ŠæрŠøстріŠ¹ Wi-Fi, ŠæŠµŃ€ŠµŠ²Ń–ртŠµ, чŠø ŠæрŠ°Ń†ŃŽŃ” "
"Š“Š¾Š“Š°Ń‚Š¾Šŗ Wi-Fi NetworkManager."
-#: ../src/nmcli/devices.c:3438 ../src/nmcli/devices.c:3790
-#: ../src/nmcli/devices.c:4419 ../src/nmcli/devices.c:4554
-#: ../src/nmcli/devices.c:4689
+#: ../src/nmcli/devices.c:3444 ../src/nmcli/devices.c:3796
+#: ../src/nmcli/devices.c:4425 ../src/nmcli/devices.c:4560
+#: ../src/nmcli/devices.c:4695
#, c-format
msgid "Error: Device '%s' is not a Wi-Fi device."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæрŠøстріŠ¹ Ā«%sĀ» Š½Šµ є ŠæрŠøстрŠ¾Ń”Š¼ Wi-Fi."
-#: ../src/nmcli/devices.c:3618
+#: ../src/nmcli/devices.c:3624
msgid "SSID or BSSID: "
msgstr "SSID Š°Š±Š¾ BSSID: "
-#: ../src/nmcli/devices.c:3623
+#: ../src/nmcli/devices.c:3629
#, c-format
msgid "Error: SSID or BSSID are missing."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠøстŠ°Ń‡Š°Ń” SSID Š°Š±Š¾ BSSID."
-#: ../src/nmcli/devices.c:3667
+#: ../src/nmcli/devices.c:3673
#, c-format
msgid "Error: bssid argument value '%s' is not a valid BSSID."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° bssid, Ā«%sĀ», Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ BSSID."
-#: ../src/nmcli/devices.c:3698
+#: ../src/nmcli/devices.c:3704
#, c-format
msgid ""
"Error: wep-key-type argument value '%s' is invalid, use 'key' or 'phrase'."
@@ -13852,49 +13901,49 @@ msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š·Š½Š°Ń‡ŠµŠ½Š½Ń ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° wep-key-type, Ā«%sĀ», є Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼, сŠ»Ń–Š“ "
"Š²ŠøŠŗŠ¾Ń€ŠøстŠ¾Š²ŃƒŠ²Š°Ń‚Šø Ā«keyĀ» Š°Š±Š¾ Ā«phraseĀ»."
-#: ../src/nmcli/devices.c:3726 ../src/nmcli/devices.c:3747
+#: ../src/nmcli/devices.c:3732 ../src/nmcli/devices.c:3753
#, c-format
msgid "Error: %s: %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: %s: %s."
-#: ../src/nmcli/devices.c:3769
+#: ../src/nmcli/devices.c:3775
#, c-format
msgid "Error: BSSID to connect to (%s) differs from bssid argument (%s)."
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: BSSID Š“Š»Ń Š·'єŠ“Š½Š°Š½Š½Ń Š· (%s) Š²Ń–Š“ріŠ·Š½ŃŃ”Ń‚ŃŒŃŃ Š²Ń–Š“ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€Š° bssid (%s)."
-#: ../src/nmcli/devices.c:3777
+#: ../src/nmcli/devices.c:3783
#, c-format
msgid "Error: Parameter '%s' is neither SSID nor BSSID."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ» Š½Šµ Š“Š¾Ń€Ń–Š²Š½ŃŽŃ” Š½Ń– SSID, Š½Ń– BSSID."
-#: ../src/nmcli/devices.c:3793 ../src/nmcli/devices.c:4422
-#: ../src/nmcli/devices.c:4557 ../src/nmcli/devices.c:4789
+#: ../src/nmcli/devices.c:3799 ../src/nmcli/devices.c:4428
+#: ../src/nmcli/devices.c:4563 ../src/nmcli/devices.c:4795
#, c-format
msgid "Error: No Wi-Fi device found."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š·Š½Š°Š¹Š“ŠµŠ½Š¾ Š¶Š¾Š“Š½Š¾Š³Š¾ ŠæрŠøстрŠ¾ŃŽ Wi-Fi."
-#: ../src/nmcli/devices.c:3815
+#: ../src/nmcli/devices.c:3821
#, c-format
msgid "Error: Failed to scan hidden SSID: %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ¼Š¾Š¶Š»ŠøŠ²Š¾ Š²ŠøŠŗŠ¾Š½Š°Ń‚Šø сŠŗŠ°Š½ŃƒŠ²Š°Š½Š½Ń ŠæрŠøхŠ¾Š²Š°Š½Š¾Š³Š¾ SSID: %s."
-#: ../src/nmcli/devices.c:3847
+#: ../src/nmcli/devices.c:3853
#, c-format
msgid "Error: No network with SSID '%s' found."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š·Š½Š°Š¹Š“ŠµŠ½Š¾ Š¼ŠµŃ€ŠµŠ¶Ń– Š· SSID Ā«%sĀ»."
-#: ../src/nmcli/devices.c:3851
+#: ../src/nmcli/devices.c:3857
#, c-format
msgid "Error: No access point with BSSID '%s' found."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š·Š½Š°Š¹Š“ŠµŠ½Š¾ тŠ¾Ń‡ŠŗŠø Š“Š¾ŃŃ‚ŃƒŠæу Š· BSSID Ā«%sĀ»."
-#: ../src/nmcli/devices.c:3880
+#: ../src/nmcli/devices.c:3886
#, c-format
msgid "Error: Connection '%s' exists but properties don't match."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ісŠ½ŃƒŃ” Š·'єŠ“Š½Š°Š½Š½Ń Ā«%sĀ», Š°Š»Šµ Š¹Š¾Š³Š¾ Š²Š»Š°ŃŃ‚ŠøŠ²Š¾ŃŃ‚Ń– є Š½ŠµŠ²Ń–Š“ŠæŠ¾Š²Ń–Š“Š½ŠøŠ¼Šø."
-#: ../src/nmcli/devices.c:3929
+#: ../src/nmcli/devices.c:3935
#, c-format
msgid ""
"Warning: '%s' should be SSID for hidden APs; but it looks like a BSSID.\n"
@@ -13902,86 +13951,86 @@ msgstr ""
"ŠŸŠ¾ŠæŠµŃ€ŠµŠ“Š¶ŠµŠ½Š½Ń: Ā«%sĀ» Š¼Š°Ń” Š±ŃƒŃ‚Šø SSID Š“Š»Ń ŠæрŠøхŠ¾Š²Š°Š½Šøх тŠ¾Ń‡Š¾Šŗ Š“Š¾ŃŃ‚ŃƒŠæу; Š²Ń‚Ń–Š¼, "
"Š·Š“Š°Ń”Ń‚ŃŒŃŃ, Š¼Š°Ń”Š¼Š¾ BSSID.\n"
-#: ../src/nmcli/devices.c:3971
+#: ../src/nmcli/devices.c:3977
msgid "Password: "
msgstr "ŠŸŠ°Ń€Š¾Š»ŃŒ: "
-#: ../src/nmcli/devices.c:4109
+#: ../src/nmcli/devices.c:4115
#, c-format
msgid "'%s' is not valid WPA PSK"
msgstr "Ā«%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ PSK WPA"
-#: ../src/nmcli/devices.c:4130
+#: ../src/nmcli/devices.c:4136
#, c-format
msgid "'%s' is not valid WEP key (it should be 5 or 13 ASCII chars)"
msgstr ""
"Ā«%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ ŠŗŠ»ŃŽŃ‡ŠµŠ¼ WEP (ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¹ ŠŗŠ»ŃŽŃ‡ Š¼Š°Ń” сŠŗŠ»Š°Š“Š°Ń‚Šøся Š· 5 Š°Š±Š¾ 13 "
"сŠøŠ¼Š²Š¾Š»Ń–Š² ASCII)"
-#: ../src/nmcli/devices.c:4149
+#: ../src/nmcli/devices.c:4155
#, c-format
msgid "Hotspot password: %s\n"
msgstr "ŠŸŠ°Ń€Š¾Š»ŃŒ Š“Š¾ тŠ¾Ń‡ŠŗŠø Š“Š¾ŃŃ‚ŃƒŠæу: %s\n"
-#: ../src/nmcli/devices.c:4328
+#: ../src/nmcli/devices.c:4334
#, c-format
msgid "Error: ssid is too long."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: SSID є Š½Š°Š“тŠ¾ Š“Š¾Š²Š³ŠøŠ¼."
-#: ../src/nmcli/devices.c:4346
+#: ../src/nmcli/devices.c:4352
#, c-format
msgid "Error: band argument value '%s' is invalid; use 'a' or 'bg'."
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š·Š½Š°Ń‡ŠµŠ½Š½Ń Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚Ńƒ Ā«bandĀ» Ā«%sĀ» є Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼; Š¼Š°Ń” Š±ŃƒŃ‚Šø Ā«aĀ» Š°Š±Š¾ Ā«bgĀ»."
-#: ../src/nmcli/devices.c:4397
+#: ../src/nmcli/devices.c:4403
#, c-format
msgid "Error: channel requires band too."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: рŠ°Š·Š¾Š¼ іŠ· ŠŗŠ°Š½Š°Š»Š¾Š¼ сŠ»Ń–Š“ Š²ŠŗŠ°Š·Š°Ń‚Šø сŠ¼ŃƒŠ³Ńƒ."
-#: ../src/nmcli/devices.c:4404
+#: ../src/nmcli/devices.c:4410
#, c-format
msgid "Error: channel '%s' not valid for band '%s'."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾Ń€ŠøстŠ¾Š²ŃƒŠ²Š°Ń‚Šø ŠŗŠ°Š½Š°Š» Ā«%sĀ» Š“Š»Ń сŠ¼ŃƒŠ³Šø Ā«%sĀ»."
-#: ../src/nmcli/devices.c:4435
+#: ../src/nmcli/devices.c:4441
#, c-format
msgid "Error: Device '%s' supports neither AP nor Ad-Hoc mode."
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š“Š»Ń ŠæрŠøстрŠ¾ŃŽ Ā«%sĀ» Š½Šµ ŠæŠµŃ€ŠµŠ“Š±Š°Ń‡ŠµŠ½Š¾ Š½Ń– рŠµŠ¶ŠøŠ¼Ńƒ тŠ¾Ń‡ŠŗŠø Š“Š¾ŃŃ‚ŃƒŠæу, Š½Ń– рŠµŠ¶ŠøŠ¼Ńƒ "
"Ad-Hoc."
-#: ../src/nmcli/devices.c:4462
+#: ../src/nmcli/devices.c:4468
#, c-format
msgid "Error: Invalid 'password': %s."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾Ń€ŠµŠŗтŠ½Šµ Š·Š½Š°Ń‡ŠµŠ½Š½Ń Ā«passwordĀ»: %s."
-#: ../src/nmcli/devices.c:4513 ../src/nmcli/devices.c:4743
+#: ../src/nmcli/devices.c:4519 ../src/nmcli/devices.c:4749
#, c-format
msgid "Error: '%s' cannot repeat."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š¼Š¾Š¶Š½Š° ŠæŠ¾Š²Ń‚Š¾Ń€ŃŽŠ²Š°Ń‚Šø Ā«%sĀ»."
-#: ../src/nmcli/devices.c:4648 ../src/nmcli/devices.c:4651
-#: ../src/nmcli/devices.c:4655 ../src/nmcli/devices.c:4658
+#: ../src/nmcli/devices.c:4654 ../src/nmcli/devices.c:4657
+#: ../src/nmcli/devices.c:4661 ../src/nmcli/devices.c:4664
#: ../src/nmtui/nmt-page-wifi.c:253
msgid "Security"
msgstr "Š—Š°Ń…Šøст"
-#: ../src/nmcli/devices.c:4648
+#: ../src/nmcli/devices.c:4654
msgid "None"
msgstr "ŠŠµŠ¼Š°Ń”"
-#: ../src/nmcli/devices.c:4777
+#: ../src/nmcli/devices.c:4783
#, c-format
msgid "%s"
msgstr "%s"
#. Main header name
-#: ../src/nmcli/devices.c:4830
+#: ../src/nmcli/devices.c:4836
msgid "Device LLDP neighbors"
msgstr "LLDP-сусіŠ“Šø ŠæрŠøстрŠ¾ŃŽ"
-#: ../src/nmcli/devices.c:4963
+#: ../src/nmcli/devices.c:4969
#, c-format
msgid "Error: 'device lldp list': %s"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«device lldp listĀ»: %s"
@@ -14564,7 +14613,7 @@ msgid "master"
msgstr "Š¾ŃŠ½Š¾Š²Š½ŠøŠ¹"
#: ../src/nmcli/general.c:1419 ../src/nmtui/nm-editor-utils.c:247
-#: ../src/nmtui/nmt-connect-connection-list.c:390
+#: ../src/nmtui/nmt-connect-connection-list.c:391
msgid "VPN"
msgstr "VPN"
@@ -14707,59 +14756,59 @@ msgstr "ŠœŠ°Š»Š¾ Š±ŃƒŃ‚Šø Š·Š½Š°Ń‡ŠµŠ½Š½Ń Š“Š»Ń Ā«%sĀ»\n"
msgid "Expected a line break following '%s'\n"
msgstr "ŠœŠ°Š² Š±ŃƒŃ‚Šø сŠøŠ¼Š²Š¾Š» рŠ¾Š·Ń€ŠøŠ²Ńƒ ряŠ“ŠŗŠ° іŠ· Š½Š°ŃŃ‚ŃƒŠæŠ½ŠøŠ¼ Ā«%sĀ»\n"
-#: ../src/nmcli/nmcli.c:789
+#: ../src/nmcli/nmcli.c:792
#, c-format
msgid "Error: Option '--terse' is specified the second time."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«--terseĀ» Š²ŠŗŠ°Š·Š°Š½Š¾ Š“Š²Ń–чі."
-#: ../src/nmcli/nmcli.c:795
+#: ../src/nmcli/nmcli.c:798
#, c-format
msgid "Error: Option '--terse' is mutually exclusive with '--pretty'."
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«--terseĀ» і Ā«--prettyĀ» Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾Ń€ŠøстŠ¾Š²ŃƒŠ²Š°Ń‚Šø Š¾Š“Š½Š¾Ń‡Š°ŃŠ½Š¾."
-#: ../src/nmcli/nmcli.c:803
+#: ../src/nmcli/nmcli.c:806
#, c-format
msgid "Error: Option '--pretty' is specified the second time."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«--prettyĀ» Š²ŠŗŠ°Š·Š°Š½Š¾ Š“Š²Ń–чі."
-#: ../src/nmcli/nmcli.c:809
+#: ../src/nmcli/nmcli.c:812
#, c-format
msgid "Error: Option '--pretty' is mutually exclusive with '--terse'."
msgstr ""
"ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«--prettyĀ» і Ā«--terseĀ» Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾Ń€ŠøстŠ¾Š²ŃƒŠ²Š°Ń‚Šø Š¾Š“Š½Š¾Ń‡Š°ŃŠ½Š¾"
-#: ../src/nmcli/nmcli.c:824
+#: ../src/nmcli/nmcli.c:827
#, c-format
msgid "Error: '%s' is not a valid argument for '%s' option."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚Š¾Š¼ Ā«%sĀ»."
-#: ../src/nmcli/nmcli.c:841 ../src/nmcli/nmcli.c:856
+#: ../src/nmcli/nmcli.c:844 ../src/nmcli/nmcli.c:859
#, c-format
msgid "Error: '%s' is not valid argument for '%s' option."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ Š°Ń€Š³ŃƒŠ¼ŠµŠ½Ń‚Š¾Š¼ Ā«%sĀ»."
-#: ../src/nmcli/nmcli.c:882
+#: ../src/nmcli/nmcli.c:885
#, c-format
msgid "Error: '%s' is not a valid timeout."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«%sĀ» Š½Šµ є ŠŗŠ¾Ń€ŠµŠŗтŠ½ŠøŠ¼ чŠ°ŃŠ¾Š¼ Š¾Ń‡Ń–ŠŗуŠ²Š°Š½Š½Ń."
-#: ../src/nmcli/nmcli.c:889
+#: ../src/nmcli/nmcli.c:892
#, c-format
msgid "nmcli tool, version %s\n"
msgstr "іŠ½ŃŃ‚Ń€ŃƒŠ¼ŠµŠ½Ń‚ nmcli, Š²ŠµŃ€ŃŃ–я %s\n"
-#: ../src/nmcli/nmcli.c:898
+#: ../src/nmcli/nmcli.c:901
#, c-format
msgid "Error: Option '%s' is unknown, try 'nmcli -help'."
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ²Ń–Š“Š¾Š¼ŠøŠ¹ ŠæŠ°Ń€Š°Š¼ŠµŃ‚Ń€ Ā«%sĀ», сŠæрŠ¾Š±ŃƒŠ¹Ń‚Šµ Ā«nmcli -helpĀ»."
-#: ../src/nmcli/nmcli.c:956 ../src/nmcli/nmcli.c:965
+#: ../src/nmcli/nmcli.c:959 ../src/nmcli/nmcli.c:968
#, c-format
msgid "Error: nmcli terminated by signal %s (%d)"
msgstr "ŠŸŠ¾Š¼ŠøŠ»ŠŗŠ°: рŠ¾Š±Š¾Ń‚Ńƒ nmcli ŠæŠµŃ€ŠµŃ€Š²Š°Š½Š¾ сŠøŠ³Š½Š°Š»Š¾Š¼ %s (%d)"
-#: ../src/nmcli/nmcli.c:1030
+#: ../src/nmcli/nmcli.c:1035
msgid "Success"
msgstr "Š’ŠøŠŗŠ¾Š½Š°Š½Š¾"
diff --git a/src/c-list/.github/workflows/ci.yml b/src/c-list/.github/workflows/ci.yml
index 76a41592d0..e07f3118d7 100644
--- a/src/c-list/.github/workflows/ci.yml
+++ b/src/c-list/.github/workflows/ci.yml
@@ -9,23 +9,19 @@ on:
jobs:
ci:
name: CI with Default Configuration
- runs-on: ubuntu-latest
-
- steps:
- - name: Fetch Sources
- uses: actions/checkout@v2
- - name: Run through C-Util CI
- uses: c-util/automation/src/ci-c-util@v1
- with:
- m32: 1
- valgrind: 1
+ uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1
+ with:
+ cabuild_ref: "v1"
+ m32: true
+ matrixmode: true
+ valgrind: true
ci-msvc:
name: CI with MSVC
runs-on: ${{ matrix.os }}
strategy:
matrix:
- os: [windows-2016, windows-latest]
+ os: [windows-2019, windows-latest]
steps:
- name: Fetch Sources
diff --git a/src/c-list/AUTHORS b/src/c-list/AUTHORS
index 439473ced6..76dea8729d 100644
--- a/src/c-list/AUTHORS
+++ b/src/c-list/AUTHORS
@@ -30,11 +30,12 @@ AUTHORS-LGPL:
along with this program; If not, see <http://www.gnu.org/licenses/>.
COPYRIGHT: (ordered alphabetically)
- Copyright (C) 2015-2019 Red Hat, Inc.
+ Copyright (C) 2015-2022 Red Hat, Inc.
AUTHORS: (ordered alphabetically)
Danilo Horta <danilo.horta@pm.me>
David Rheinsberg <david.rheinsberg@gmail.com>
Lucas De Marchi <lucas.de.marchi@gmail.com>
+ Michele Dionisio
Thomas Haller <thaller@redhat.com>
Tom Gundersen <teg@jklm.no>
diff --git a/src/c-list/NEWS.md b/src/c-list/NEWS.md
index 0404389597..02d2c9a5ca 100644
--- a/src/c-list/NEWS.md
+++ b/src/c-list/NEWS.md
@@ -1,5 +1,18 @@
# c-list - Circular Intrusive Double Linked List Collection
+## CHANGES WITH 4:
+
+ * The minimum required meson version is now 0.60.0.
+
+ * New function c_list_split() is added. It reverses c_list_splice()
+ and thus allows to split a list in half.
+
+ * TBD
+
+ Contributions from: David Rheinsberg
+
+ - TBD, YYYY-MM-DD
+
## CHANGES WITH 3:
* API break: The c_list_loop_*() symbols were removed, since we saw
diff --git a/src/c-list/README.md b/src/c-list/README.md
index d14198999f..a2e47528ed 100644
--- a/src/c-list/README.md
+++ b/src/c-list/README.md
@@ -20,7 +20,7 @@ The requirements for this project are:
At build-time, the following software is required:
- * `meson >= 0.41`
+ * `meson >= 0.60`
* `pkg-config >= 0.29`
### Build
diff --git a/src/c-list/meson.build b/src/c-list/meson.build
index 21bb784f1c..1776b105f2 100644
--- a/src/c-list/meson.build
+++ b/src/c-list/meson.build
@@ -1,15 +1,46 @@
project(
'c-list',
'c',
- version: '3',
- license: 'Apache',
default_options: [
'c_std=c99',
],
+ license: 'Apache',
+ meson_version: '>=0.60.0',
+ version: '3.0.0',
)
+major = meson.project_version().split('.')[0]
project_description = 'Circular Intrusive Double Linked List Collection'
-add_project_arguments('-D_GNU_SOURCE', language: 'c')
mod_pkgconfig = import('pkgconfig')
+# See c-stdaux for details on these. We do not have c-stdaux as dependency, so
+# we keep a duplicated set here, reduced to the minimum.
+cflags = meson.get_compiler('c').get_supported_arguments(
+ '-D_GNU_SOURCE',
+
+ '-Wno-gnu-alignof-expression',
+ '-Wno-maybe-uninitialized',
+ '-Wno-unknown-warning-option',
+ '-Wno-unused-parameter',
+
+ '-Wno-error=type-limits',
+ '-Wno-error=missing-field-initializers',
+
+ '-Wdate-time',
+ '-Wdeclaration-after-statement',
+ '-Wlogical-op',
+ '-Wmissing-include-dirs',
+ '-Wmissing-noreturn',
+ '-Wnested-externs',
+ '-Wredundant-decls',
+ '-Wshadow',
+ '-Wstrict-aliasing=3',
+ '-Wsuggest-attribute=noreturn',
+ '-Wundef',
+ '-Wwrite-strings',
+)
+add_project_arguments(cflags, language: 'c')
+
subdir('src')
+
+meson.override_dependency('libclist-'+major, libclist_dep, static: true)
diff --git a/src/c-list/src/c-list.h b/src/c-list/src/c-list.h
index 69de0b31eb..711b54d630 100644
--- a/src/c-list/src/c-list.h
+++ b/src/c-list/src/c-list.h
@@ -260,6 +260,31 @@ static inline void c_list_splice(CList *target, CList *source) {
}
/**
+ * c_list_split() - split one list in two
+ * @source: the list to split
+ * @where: new starting element of newlist
+ * @target: new list
+ *
+ * This splits @source in two. All elements following @where (including @where)
+ * are moved to @target, replacing any old list. If @where points to @source
+ * (i.e., the end of the list), @target will be empty.
+ */
+static inline void c_list_split(CList *source, CList *where, CList *target) {
+ if (where == source) {
+ *target = (CList)C_LIST_INIT(*target);
+ } else {
+ target->next = where;
+ target->prev = source->prev;
+
+ where->prev->next = source;
+ source->prev = where->prev;
+
+ where->prev = target;
+ target->prev->next = target;
+ }
+}
+
+/**
* c_list_first() - return pointer to first element, or NULL if empty
* @list: list to operate on, or NULL
*
diff --git a/src/c-list/src/meson.build b/src/c-list/src/meson.build
index 0261ae0c2f..ec7f29d5f5 100644
--- a/src/c-list/src/meson.build
+++ b/src/c-list/src/meson.build
@@ -13,10 +13,10 @@ if not meson.is_subproject()
install_headers('c-list.h')
mod_pkgconfig.generate(
- version: meson.project_version(),
- name: 'libclist',
- filebase: 'libclist',
description: project_description,
+ filebase: 'libclist-'+major,
+ name: 'libclist',
+ version: meson.project_version(),
)
endif
diff --git a/src/c-list/src/test-api.c b/src/c-list/src/test-api.c
index bf760cf92f..864d198a65 100644
--- a/src/c-list/src/test-api.c
+++ b/src/c-list/src/test-api.c
@@ -17,7 +17,8 @@ typedef struct {
} Node;
static void test_api(void) {
- CList *list_iter, *list_safe, list = C_LIST_INIT(list);
+ CList *list_iter, *list_safe;
+ CList list = C_LIST_INIT(list), list2 = C_LIST_INIT(list2);
Node node = { .id = 0, .link = C_LIST_INIT(node.link) };
assert(c_list_init(&list) == &list);
@@ -68,7 +69,7 @@ static void test_api(void) {
c_list_unlink(&node.link);
assert(!c_list_is_linked(&node.link));
- /* swap / splice list operators */
+ /* swap / splice / split list operators */
c_list_swap(&list, &list);
assert(c_list_is_empty(&list));
@@ -76,6 +77,10 @@ static void test_api(void) {
c_list_splice(&list, &list);
assert(c_list_is_empty(&list));
+ c_list_split(&list, &list, &list2);
+ assert(c_list_is_empty(&list));
+ assert(c_list_is_empty(&list2));
+
/* direct/raw iterators */
c_list_for_each(list_iter, &list)
diff --git a/src/c-list/src/test-basic.c b/src/c-list/src/test-basic.c
index 06cccd852b..58ed863684 100644
--- a/src/c-list/src/test-basic.c
+++ b/src/c-list/src/test-basic.c
@@ -11,6 +11,18 @@
#include <string.h>
#include "c-list.h"
+static void assert_list_integrity(CList *list) {
+ CList *iter;
+
+ iter = list;
+ do {
+ assert(iter->next->prev == iter);
+ assert(iter->prev->next == iter);
+
+ iter = iter->next;
+ } while (iter != list);
+}
+
static void test_iterators(void) {
CList *iter, *safe, a, b, list = C_LIST_INIT(list);
unsigned int i;
@@ -158,6 +170,85 @@ static void test_splice(void) {
assert(c_list_last(&target) == &e2);
}
+static void test_split(void) {
+ CList e1, e2;
+
+ /* split empty list */
+ {
+ CList source = C_LIST_INIT(source), target;
+
+ c_list_split(&source, &source, &target);
+ assert(c_list_is_empty(&source));
+ assert(c_list_is_empty(&target));
+ assert_list_integrity(&source);
+ assert_list_integrity(&target);
+ }
+
+ /* split 1-element list excluding the element */
+ {
+ CList source = C_LIST_INIT(source), target;
+
+ c_list_link_tail(&source, &e1);
+ c_list_split(&source, &source, &target);
+ assert(!c_list_is_empty(&source));
+ assert(c_list_is_empty(&target));
+ assert_list_integrity(&source);
+ assert_list_integrity(&target);
+ }
+
+ /* split 1-element list including the element */
+ {
+ CList source = C_LIST_INIT(source), target;
+
+ c_list_link_tail(&source, &e1);
+ c_list_split(&source, &e1, &target);
+ assert(c_list_is_empty(&source));
+ assert(!c_list_is_empty(&target));
+ assert_list_integrity(&source);
+ assert_list_integrity(&target);
+ }
+
+ /* split 2-element list excluding the elements */
+ {
+ CList source = C_LIST_INIT(source), target;
+
+ c_list_link_tail(&source, &e1);
+ c_list_link_tail(&source, &e2);
+ c_list_split(&source, &source, &target);
+ assert(!c_list_is_empty(&source));
+ assert(c_list_is_empty(&target));
+ assert_list_integrity(&source);
+ assert_list_integrity(&target);
+ }
+
+ /* split 2-element list including one element */
+ {
+ CList source = C_LIST_INIT(source), target;
+
+ c_list_link_tail(&source, &e1);
+ c_list_link_tail(&source, &e2);
+ c_list_split(&source, &e2, &target);
+ assert(!c_list_is_empty(&source));
+ assert(!c_list_is_empty(&target));
+ assert_list_integrity(&source);
+ assert_list_integrity(&target);
+ }
+
+ /* split 2-element list including both elements */
+ {
+ CList source = C_LIST_INIT(source), target;
+
+ c_list_link_tail(&source, &e1);
+ c_list_link_tail(&source, &e2);
+ c_list_split(&source, &e1, &target);
+ assert(c_list_is_empty(&source));
+ assert(!c_list_is_empty(&target));
+ assert_list_integrity(&source);
+ assert_list_integrity(&target);
+ }
+}
+
+
static void test_flush(void) {
CList e1 = C_LIST_INIT(e1), e2 = C_LIST_INIT(e2);
CList list1 = C_LIST_INIT(list1), list2 = C_LIST_INIT(list2);
@@ -220,6 +311,7 @@ int main(void) {
test_iterators();
test_swap();
test_splice();
+ test_split();
test_flush();
test_macros();
test_gnu();
diff --git a/src/c-rbtree/.github/workflows/ci.yml b/src/c-rbtree/.github/workflows/ci.yml
index c270c52ca7..6350d3c746 100644
--- a/src/c-rbtree/.github/workflows/ci.yml
+++ b/src/c-rbtree/.github/workflows/ci.yml
@@ -9,25 +9,15 @@ on:
jobs:
ci:
name: CI with Default Configuration
- runs-on: ubuntu-latest
-
- steps:
- - name: Fetch Sources
- uses: actions/checkout@v2
- - name: Run through C-Util CI
- uses: c-util/automation/src/ci-c-util@v1
- with:
- m32: 1
- valgrind: 1
-
+ uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1
+ with:
+ cabuild_ref: "v1"
+ m32: true
+ matrixmode: true
+ valgrind: true
ci-ptrace:
name: Reduced CI with PTrace
- runs-on: ubuntu-latest
- env:
- CRBTREE_TEST_PTRACE: '1'
-
- steps:
- - name: Fetch Sources
- uses: actions/checkout@v2
- - name: Run through C-Util CI
- uses: c-util/automation/src/ci-c-util@v1
+ uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1
+ with:
+ cabuild_ref: "v1"
+ mesonargs: '-Dptrace=true'
diff --git a/src/c-rbtree/.gitmodules b/src/c-rbtree/.gitmodules
index a86b29fd1c..e69de29bb2 100644
--- a/src/c-rbtree/.gitmodules
+++ b/src/c-rbtree/.gitmodules
@@ -1,3 +0,0 @@
-[submodule "subprojects/c-stdaux"]
- path = subprojects/c-stdaux
- url = https://github.com/c-util/c-stdaux.git
diff --git a/src/c-rbtree/AUTHORS b/src/c-rbtree/AUTHORS
index ed4e72e915..cd557de26c 100644
--- a/src/c-rbtree/AUTHORS
+++ b/src/c-rbtree/AUTHORS
@@ -30,7 +30,7 @@ AUTHORS-LGPL:
along with this program; If not, see <http://www.gnu.org/licenses/>.
COPYRIGHT: (ordered alphabetically)
- Copyright (C) 2015-2019 Red Hat, Inc.
+ Copyright (C) 2015-2022 Red Hat, Inc.
AUTHORS: (ordered alphabetically)
David Rheinsberg <david.rheinsberg@gmail.com>
diff --git a/src/c-rbtree/NEWS.md b/src/c-rbtree/NEWS.md
index d76a412908..3fe061d977 100644
--- a/src/c-rbtree/NEWS.md
+++ b/src/c-rbtree/NEWS.md
@@ -1,5 +1,20 @@
# c-rbtree - Intrusive Red-Black Tree Collection
+## CHANGES WITH 4:
+
+ * Add 'ptrace' build option to enable running tests using 'ptrace'
+ to verify extended execution properties. This option should not
+ be used in setups where 'ptrace' cannot be employed (like running
+ under gdb or valgrind). This option only affects the test-suite.
+
+ * meson-0.60.0 is now the minimum required meson version.
+
+ * TBD
+
+ Contributions from: David Rheinsberg
+
+ - TBD, YYYY-MM-DD
+
## CHANGES WITH 3:
* Add more helpers. Add both a collection of iteratiors and helpers
diff --git a/src/c-rbtree/README.md b/src/c-rbtree/README.md
index c725bbb8f4..e3183ac8aa 100644
--- a/src/c-rbtree/README.md
+++ b/src/c-rbtree/README.md
@@ -22,7 +22,7 @@ The requirements for this project are:
At build-time, the following software is required:
- * `meson >= 0.41`
+ * `meson >= 0.60`
* `pkg-config >= 0.29`
### Build
diff --git a/src/c-rbtree/meson.build b/src/c-rbtree/meson.build
index c131946762..f3ae209dbb 100644
--- a/src/c-rbtree/meson.build
+++ b/src/c-rbtree/meson.build
@@ -1,19 +1,22 @@
project(
'c-rbtree',
'c',
- version: '3',
- license: 'Apache',
default_options: [
'c_std=c11'
],
+ license: 'Apache',
+ meson_version: '>=0.60.0',
+ version: '3.0.0',
)
+major = meson.project_version().split('.')[0]
project_description = 'Intrusive Red-Black Tree Collection'
-add_project_arguments('-D_GNU_SOURCE', language: 'c')
mod_pkgconfig = import('pkgconfig')
+use_ptrace = get_option('ptrace')
-sub_cstdaux = subproject('c-stdaux')
-
-dep_cstdaux = sub_cstdaux.get_variable('libcstdaux_dep')
+dep_cstdaux = dependency('libcstdaux-1')
+add_project_arguments(dep_cstdaux.get_variable('cflags').split(' '), language: 'c')
subdir('src')
+
+meson.override_dependency('libcrbtree-'+major, libcrbtree_dep, static: true)
diff --git a/src/c-rbtree/meson_options.txt b/src/c-rbtree/meson_options.txt
new file mode 100644
index 0000000000..ec35818053
--- /dev/null
+++ b/src/c-rbtree/meson_options.txt
@@ -0,0 +1 @@
+option('ptrace', type: 'boolean', value: false, description: 'Allow ptrace in test suite')
diff --git a/src/c-rbtree/src/c-rbtree.h b/src/c-rbtree/src/c-rbtree.h
index d4d0fe45c0..5c6fd0a559 100644
--- a/src/c-rbtree/src/c-rbtree.h
+++ b/src/c-rbtree/src/c-rbtree.h
@@ -144,6 +144,11 @@ static inline void c_rbnode_init(CRBNode *n) {
*
* Return: Pointer to parent container, or NULL.
*/
+/*
+ * Note: This was carefully designed to avoid multiple evaluation of `_what`,
+ * but avoid context-expression-extensions. That is why it uses the
+ * possibly odd style of `(x ?: offsetof(...)) - offsetof(...))`.
+ */
#define c_rbnode_entry(_what, _t, _m) \
((_t *)(void *)(((unsigned long)(void *)(_what) ?: \
offsetof(_t, _m)) - offsetof(_t, _m)))
diff --git a/src/c-rbtree/src/meson.build b/src/c-rbtree/src/meson.build
index d0b4d63ce9..c5cce8102c 100644
--- a/src/c-rbtree/src/meson.build
+++ b/src/c-rbtree/src/meson.build
@@ -8,8 +8,8 @@ libcrbtree_deps = [
dep_cstdaux,
]
-libcrbtree_private = static_library(
- 'crbtree-private',
+libcrbtree_both = both_libraries(
+ 'crbtree-'+major,
[
'c-rbtree.c',
],
@@ -18,26 +18,19 @@ libcrbtree_private = static_library(
'-fno-common',
],
dependencies: libcrbtree_deps,
- pic: true,
-)
-
-libcrbtree_shared = shared_library(
- 'crbtree',
- objects: libcrbtree_private.extract_all_objects(),
- dependencies: libcrbtree_deps,
install: not meson.is_subproject(),
- soversion: 0,
- link_depends: libcrbtree_symfile,
link_args: [
'-Wl,--no-undefined',
'-Wl,--version-script=@0@'.format(libcrbtree_symfile),
],
+ link_depends: libcrbtree_symfile,
+ soversion: 0,
)
libcrbtree_dep = declare_dependency(
- include_directories: include_directories('.'),
- link_with: libcrbtree_private,
dependencies: libcrbtree_deps,
+ include_directories: include_directories('.'),
+ link_with: libcrbtree_both.get_static_lib(),
version: meson.project_version(),
)
@@ -45,11 +38,11 @@ if not meson.is_subproject()
install_headers('c-rbtree.h')
mod_pkgconfig.generate(
- libraries: libcrbtree_shared,
- version: meson.project_version(),
- name: 'libcrbtree',
- filebase: 'libcrbtree',
description: project_description,
+ filebase: 'libcrbtree-'+major,
+ libraries: libcrbtree_both.get_shared_lib(),
+ name: 'libcrbtree',
+ version: meson.project_version(),
)
endif
@@ -57,7 +50,7 @@ endif
# target: test-*
#
-test_api = executable('test-api', ['test-api.c'], link_with: libcrbtree_shared)
+test_api = executable('test-api', ['test-api.c'], link_with: libcrbtree_both.get_shared_lib())
test('API Symbol Visibility', test_api)
test_basic = executable('test-basic', ['test-basic.c'], dependencies: libcrbtree_dep)
@@ -70,7 +63,9 @@ test_misc = executable('test-misc', ['test-misc.c'], dependencies: libcrbtree_de
test('Miscellaneous', test_misc)
test_parallel = executable('test-parallel', ['test-parallel.c'], dependencies: libcrbtree_dep)
-test('Lockless Parallel Readers', test_parallel)
+if use_ptrace
+ test('Lockless Parallel Readers', test_parallel)
+endif
test_posix = executable('test-posix', ['test-posix.c'], dependencies: libcrbtree_dep)
test('Posix tsearch(3p) Comparison', test_posix)
diff --git a/src/c-rbtree/src/test-parallel.c b/src/c-rbtree/src/test-parallel.c
index 1388722bf3..4baf8e702d 100644
--- a/src/c-rbtree/src/test-parallel.c
+++ b/src/c-rbtree/src/test-parallel.c
@@ -364,9 +364,6 @@ int main(int argc, char **argv) {
unsigned int i;
int r;
- if (!getenv("CRBTREE_TEST_PTRACE"))
- return 77;
-
/* we want stable tests, so use fixed seed */
srand(0xdeadbeef);
diff --git a/src/c-rbtree/subprojects/c-stdaux b/src/c-rbtree/subprojects/c-stdaux
deleted file mode 160000
-Subproject c5f166d02ff68af5cdcbad1bdcea2cb134e34ce
diff --git a/src/c-rbtree/subprojects/libcstdaux-1.wrap b/src/c-rbtree/subprojects/libcstdaux-1.wrap
new file mode 100644
index 0000000000..036020aafe
--- /dev/null
+++ b/src/c-rbtree/subprojects/libcstdaux-1.wrap
@@ -0,0 +1,3 @@
+[wrap-git]
+url = https://github.com/c-util/c-stdaux.git
+revision = v1
diff --git a/src/c-siphash/.github/workflows/ci.yml b/src/c-siphash/.github/workflows/ci.yml
index b40abf690f..d54b120011 100644
--- a/src/c-siphash/.github/workflows/ci.yml
+++ b/src/c-siphash/.github/workflows/ci.yml
@@ -9,13 +9,9 @@ on:
jobs:
ci:
name: CI with Default Configuration
- runs-on: ubuntu-latest
-
- steps:
- - name: Fetch Sources
- uses: actions/checkout@v2
- - name: Run through C-Util CI
- uses: c-util/automation/src/ci-c-util@v1
- with:
- m32: 1
- valgrind: 1
+ uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1
+ with:
+ cabuild_ref: "v1"
+ m32: true
+ matrixmode: true
+ valgrind: true
diff --git a/src/c-siphash/.gitmodules b/src/c-siphash/.gitmodules
index a86b29fd1c..e69de29bb2 100644
--- a/src/c-siphash/.gitmodules
+++ b/src/c-siphash/.gitmodules
@@ -1,3 +0,0 @@
-[submodule "subprojects/c-stdaux"]
- path = subprojects/c-stdaux
- url = https://github.com/c-util/c-stdaux.git
diff --git a/src/c-siphash/AUTHORS b/src/c-siphash/AUTHORS
index b59660c5ee..3c6436a932 100644
--- a/src/c-siphash/AUTHORS
+++ b/src/c-siphash/AUTHORS
@@ -30,7 +30,7 @@ AUTHORS-LGPL:
along with this program; If not, see <http://www.gnu.org/licenses/>.
COPYRIGHT: (ordered alphabetically)
- Copyright (C) 2015-2019 Red Hat, Inc.
+ Copyright (C) 2015-2022 Red Hat, Inc.
AUTHORS: (ordered alphabetically)
David Rheinsberg <david.rheinsberg@gmail.com>
diff --git a/src/c-siphash/README.md b/src/c-siphash/README.md
index ba09041be4..bd97d06b61 100644
--- a/src/c-siphash/README.md
+++ b/src/c-siphash/README.md
@@ -21,7 +21,7 @@ The requirements for this project are:
At build-time, the following software is required:
- * `meson >= 0.41`
+ * `meson >= 0.60`
* `pkg-config >= 0.29`
### Build
diff --git a/src/c-siphash/meson.build b/src/c-siphash/meson.build
index 2b07b019b3..ffcb6a76ae 100644
--- a/src/c-siphash/meson.build
+++ b/src/c-siphash/meson.build
@@ -1,19 +1,21 @@
project(
'c-siphash',
'c',
- version: '1',
- license: 'Apache',
default_options: [
'c_std=c11'
],
+ license: 'Apache',
+ meson_version: '>=0.60.0',
+ version: '1.0.0',
)
+major = meson.project_version().split('.')[0]
project_description = 'Streaming-capable SipHash Implementation'
-add_project_arguments('-D_GNU_SOURCE', language: 'c')
mod_pkgconfig = import('pkgconfig')
-sub_cstdaux = subproject('c-stdaux')
-
-dep_cstdaux = sub_cstdaux.get_variable('libcstdaux_dep')
+dep_cstdaux = dependency('libcstdaux-1')
+add_project_arguments(dep_cstdaux.get_variable('cflags').split(' '), language: 'c')
subdir('src')
+
+meson.override_dependency('libcsiphash-'+major, libcsiphash_dep, static: true)
diff --git a/src/c-siphash/src/meson.build b/src/c-siphash/src/meson.build
index 7ee9c601e7..55c2e4f150 100644
--- a/src/c-siphash/src/meson.build
+++ b/src/c-siphash/src/meson.build
@@ -8,8 +8,8 @@ libcsiphash_deps = [
dep_cstdaux,
]
-libcsiphash_private = static_library(
- 'csiphash-private',
+libcsiphash_both = both_libraries(
+ 'csiphash-'+major,
[
'c-siphash.c',
],
@@ -18,26 +18,19 @@ libcsiphash_private = static_library(
'-fno-common',
],
dependencies: libcsiphash_deps,
- pic: true,
-)
-
-libcsiphash_shared = shared_library(
- 'csiphash',
- objects: libcsiphash_private.extract_all_objects(),
- dependencies: libcsiphash_deps,
install: not meson.is_subproject(),
- soversion: 0,
- link_depends: libcsiphash_symfile,
link_args: [
'-Wl,--no-undefined',
'-Wl,--version-script=@0@'.format(libcsiphash_symfile),
],
+ link_depends: libcsiphash_symfile,
+ soversion: 0,
)
libcsiphash_dep = declare_dependency(
- include_directories: include_directories('.'),
- link_with: libcsiphash_private,
dependencies: libcsiphash_deps,
+ include_directories: include_directories('.'),
+ link_with: libcsiphash_both.get_static_lib(),
version: meson.project_version(),
)
@@ -45,11 +38,11 @@ if not meson.is_subproject()
install_headers('c-siphash.h')
mod_pkgconfig.generate(
- libraries: libcsiphash_shared,
- version: meson.project_version(),
- name: 'libcsiphash',
- filebase: 'libcsiphash',
description: project_description,
+ filebase: 'libcsiphash-'+major,
+ libraries: libcsiphash_both.get_shared_lib(),
+ name: 'libcsiphash',
+ version: meson.project_version(),
)
endif
@@ -57,7 +50,7 @@ endif
# target: test-*
#
-test_api = executable('test-api', ['test-api.c'], link_with: libcsiphash_shared)
+test_api = executable('test-api', ['test-api.c'], link_with: libcsiphash_both.get_shared_lib())
test('API Symbol Visibility', test_api)
test_basic = executable('test-basic', ['test-basic.c'], dependencies: libcsiphash_dep)
diff --git a/src/c-siphash/subprojects/c-stdaux b/src/c-siphash/subprojects/c-stdaux
deleted file mode 160000
-Subproject c5f166d02ff68af5cdcbad1bdcea2cb134e34ce
diff --git a/src/c-siphash/subprojects/libcstdaux-1.wrap b/src/c-siphash/subprojects/libcstdaux-1.wrap
new file mode 100644
index 0000000000..036020aafe
--- /dev/null
+++ b/src/c-siphash/subprojects/libcstdaux-1.wrap
@@ -0,0 +1,3 @@
+[wrap-git]
+url = https://github.com/c-util/c-stdaux.git
+revision = v1
diff --git a/src/c-stdaux/.github/workflows/ci.yml b/src/c-stdaux/.github/workflows/ci.yml
index b40abf690f..d54b120011 100644
--- a/src/c-stdaux/.github/workflows/ci.yml
+++ b/src/c-stdaux/.github/workflows/ci.yml
@@ -9,13 +9,9 @@ on:
jobs:
ci:
name: CI with Default Configuration
- runs-on: ubuntu-latest
-
- steps:
- - name: Fetch Sources
- uses: actions/checkout@v2
- - name: Run through C-Util CI
- uses: c-util/automation/src/ci-c-util@v1
- with:
- m32: 1
- valgrind: 1
+ uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1
+ with:
+ cabuild_ref: "v1"
+ m32: true
+ matrixmode: true
+ valgrind: true
diff --git a/src/c-stdaux/AUTHORS b/src/c-stdaux/AUTHORS
index 6015c4f31c..555ecb5581 100644
--- a/src/c-stdaux/AUTHORS
+++ b/src/c-stdaux/AUTHORS
@@ -30,7 +30,7 @@ AUTHORS-LGPL:
along with this program; If not, see <http://www.gnu.org/licenses/>.
COPYRIGHT: (ordered alphabetically)
- Copyright (C) 2018-2019 Red Hat, Inc.
+ Copyright (C) 2018-2022 Red Hat, Inc.
AUTHORS: (ordered alphabetically)
David Rheinsberg <david.rheinsberg@gmail.com>
diff --git a/src/c-stdaux/README.md b/src/c-stdaux/README.md
index 51bff9778f..124c692e12 100644
--- a/src/c-stdaux/README.md
+++ b/src/c-stdaux/README.md
@@ -21,7 +21,7 @@ The requirements for this project are:
At build-time, the following software is required:
- * `meson >= 0.41`
+ * `meson >= 0.60`
* `pkg-config >= 0.29`
### Build
diff --git a/src/c-stdaux/meson.build b/src/c-stdaux/meson.build
index c8c5da536f..3054e25073 100644
--- a/src/c-stdaux/meson.build
+++ b/src/c-stdaux/meson.build
@@ -1,15 +1,86 @@
project(
'c-stdaux',
'c',
- version: '1',
- license: 'Apache',
default_options: [
'c_std=c11'
],
+ license: 'Apache',
+ meson_version: '>=0.60.0',
+ version: '1.0.0',
)
+major = meson.project_version().split('.')[0]
project_description = 'Auxiliary macros and functions for the C standard library'
-add_project_arguments('-D_GNU_SOURCE', language: 'c')
mod_pkgconfig = import('pkgconfig')
+#
+# CFLAGS
+#
+# We have a set of compiler flags for GCC and CLANG which adjust their warnings
+# and behavior to our coding-style.
+#
+# This variable is exported to dependent projects via meson for them to use as
+# well. Since these exports are limited to strings, we need to be careful that
+# the individual entries do not contain spaces (see the assertion below).
+#
+cflags = meson.get_compiler('c').get_supported_arguments(
+ # Enable GNU features of our dependencies. See feature_test_macros(7).
+ '-D_GNU_SOURCE',
+
+ # Prevent CLANG from complaining that alignof-expressions are GNU-only.
+ '-Wno-gnu-alignof-expression',
+ # Never complain about *MAYBE* uninit variables. This is very flaky and
+ # produces bogus results with LTO.
+ '-Wno-maybe-uninitialized',
+ # Do not complain about unknown GCC/CLANG warnings.
+ '-Wno-unknown-warning-option',
+ # There is no standardized way to mark unused arguments, so never
+ # complain about them.
+ '-Wno-unused-parameter',
+
+ # Preprocessor evaluations often lead to warnings about comparisons
+ # that are always true/false. Make sure they do not break a build but
+ # keep them on for diagnostics.
+ '-Wno-error=type-limits',
+ # As we use designated field-initializers, this warning should never
+ # trigger, but still does on GCC in combination with some other
+ # preprocessor checks. Lets just make sure it does not break builds.
+ '-Wno-error=missing-field-initializers',
+
+ # Warn if we ever use `__DATE__` and similar in our build. We want
+ # reproducible builds.
+ '-Wdate-time',
+ # We strictly follow decl-before-statements, so check it.
+ '-Wdeclaration-after-statement',
+ # More strict logical-op sanity checks.
+ '-Wlogical-op',
+ # Loudly complain about missing include-directories.
+ '-Wmissing-include-dirs',
+ # We want hints about noreturn functions, so warn about them.
+ '-Wmissing-noreturn',
+ # Warn if an extern-decl is inside a function. We want imports as
+ # global attributes, never as local ones.
+ '-Wnested-externs',
+ # Warn about redundant declarations. We want declarations in headers
+ # and want them to be unique.
+ '-Wredundant-decls',
+ # Warn about shadowed variables so we do not accidentally override
+ # variables of parent scopes and thus confuse macros.
+ '-Wshadow',
+ # Warn about aliasing violations. Level-3 produces the least false
+ # positives, but is the slowest. Force it to avoid breaking -Werror
+ # builds.
+ '-Wstrict-aliasing=3',
+ # Suggest 'noreturn' attributes. They are useful, we want them!
+ '-Wsuggest-attribute=noreturn',
+ # Warn about undefined identifiers in preprocessor conditionals.
+ '-Wundef',
+ # Make sure literal strings are considered 'const'.
+ '-Wwrite-strings',
+)
+assert(not ''.join(cflags).contains(' '), 'Malformed compiler flags.')
+add_project_arguments(cflags, language: 'c')
+
subdir('src')
+
+meson.override_dependency('libcstdaux-'+major, libcstdaux_dep, static: true)
diff --git a/src/c-stdaux/src/meson.build b/src/c-stdaux/src/meson.build
index f6db824d24..a9322d4daa 100644
--- a/src/c-stdaux/src/meson.build
+++ b/src/c-stdaux/src/meson.build
@@ -6,6 +6,7 @@
libcstdaux_dep = declare_dependency(
include_directories: include_directories('.'),
+ variables: { 'cflags': ' '.join(cflags) },
version: meson.project_version(),
)
@@ -13,10 +14,10 @@ if not meson.is_subproject()
install_headers('c-stdaux.h')
mod_pkgconfig.generate(
- version: meson.project_version(),
- name: 'libcstdaux',
- filebase: 'libcstdaux',
description: project_description,
+ filebase: 'libcstdaux-'+major,
+ name: 'libcstdaux',
+ version: meson.project_version(),
)
endif
diff --git a/src/c-stdaux/src/test-basic.c b/src/c-stdaux/src/test-basic.c
index d58d561d23..15499353cb 100644
--- a/src/c-stdaux/src/test-basic.c
+++ b/src/c-stdaux/src/test-basic.c
@@ -359,7 +359,7 @@ static void test_destructors(void) {
/* make sure c_closep() deals fine with negative FDs */
{
- _c_cleanup_(c_closep) int t = 0;
+ _c_cleanup_(c_closep) _c_unused_ int t = 0;
t = -1;
}
@@ -370,7 +370,7 @@ static void test_destructors(void) {
* path works as well.
*/
for (i = 0; i < 2; ++i) {
- _c_cleanup_(c_closep) int t = -1;
+ _c_cleanup_(c_closep) _c_unused_ int t = -1;
t = eventfd(0, EFD_CLOEXEC);
c_assert(t >= 0);
@@ -401,7 +401,7 @@ static void test_destructors(void) {
/* make sure c_flosep() deals fine with NULL */
{
- _c_cleanup_(c_fclosep) FILE *t = (void *)0xdeadbeef;
+ _c_cleanup_(c_fclosep) _c_unused_ FILE *t = (void *)0xdeadbeef;
t = NULL;
}
@@ -412,7 +412,7 @@ static void test_destructors(void) {
* path works as well.
*/
for (i = 0; i < 2; ++i) {
- _c_cleanup_(c_fclosep) FILE *t = NULL;
+ _c_cleanup_(c_fclosep) _c_unused_ FILE *t = NULL;
int tfd;
tfd = eventfd(0, EFD_CLOEXEC);
diff --git a/src/core/NetworkManagerUtils.c b/src/core/NetworkManagerUtils.c
index 5727aac814..56f551060c 100644
--- a/src/core/NetworkManagerUtils.c
+++ b/src/core/NetworkManagerUtils.c
@@ -30,7 +30,6 @@
#include "libnm-platform/nm-linux-platform.h"
#include "libnm-platform/nm-platform-utils.h"
#include "nm-auth-utils.h"
-#include "libnm-systemd-shared/nm-sd-utils-shared.h"
/*****************************************************************************/
@@ -1155,7 +1154,7 @@ nm_utils_file_is_in_path(const char *abs_filename, const char *abs_path)
g_return_val_if_fail(abs_filename && abs_filename[0] == '/', NULL);
g_return_val_if_fail(abs_path && abs_path[0] == '/', NULL);
- path = nm_sd_utils_path_startswith(abs_filename, abs_path);
+ path = nm_path_startswith(abs_filename, abs_path);
if (!path)
return NULL;
diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c
index 16896d5753..21fe9b07eb 100644
--- a/src/core/devices/nm-device-bond.c
+++ b/src/core/devices/nm-device-bond.c
@@ -312,7 +312,7 @@ set_bond_attr_or_default(NMDevice *device, NMSettingBond *s_bond, const char *op
NMDeviceBond *self = NM_DEVICE_BOND(device);
const char *value;
- value = nm_setting_bond_get_option_or_default(s_bond, opt);
+ value = nm_setting_bond_get_option_normalized(s_bond, opt);
if (!value) {
if (_LOGT_ENABLED(LOGD_BOND) && nm_setting_bond_get_option_by_name(s_bond, opt))
_LOGT(LOGD_BOND, "bond option '%s' not set as it conflicts with other options", opt);
@@ -346,7 +346,7 @@ set_bond_arp_ip_targets(NMDevice *device, NMSettingBond *s_bond)
set_arp_targets(
device,
cur_arp_ip_target,
- nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET));
+ nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET));
}
static gboolean
@@ -361,7 +361,7 @@ apply_bonding_config(NMDeviceBond *self)
s_bond = nm_device_get_applied_setting(device, NM_TYPE_SETTING_BOND);
g_return_val_if_fail(s_bond, FALSE);
- mode_str = nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_MODE);
+ mode_str = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE);
mode = _nm_setting_bond_mode_from_string(mode_str);
g_return_val_if_fail(mode != NM_BOND_MODE_UNKNOWN, FALSE);
@@ -424,8 +424,14 @@ commit_port_options(NMDevice *bond_device, NMDevice *port, NMSettingBondPort *s_
queue_id_str);
}
-static gboolean
-enslave_slave(NMDevice *device, NMDevice *port, NMConnection *connection, gboolean configure)
+static NMTernary
+attach_port(NMDevice *device,
+ NMDevice *port,
+ NMConnection *connection,
+ gboolean configure,
+ GCancellable *cancellable,
+ NMDeviceAttachPortCallback callback,
+ gpointer user_data)
{
NMDeviceBond *self = NM_DEVICE_BOND(device);
NMSettingBondPort *s_port;
@@ -442,7 +448,7 @@ enslave_slave(NMDevice *device, NMDevice *port, NMConnection *connection, gboole
nm_device_bring_up(port, TRUE, NULL);
if (!success) {
- _LOGI(LOGD_BOND, "assigning bond port %s: failed", nm_device_get_ip_iface(port));
+ _LOGI(LOGD_BOND, "attaching bond port %s: failed", nm_device_get_ip_iface(port));
return FALSE;
}
@@ -450,15 +456,15 @@ enslave_slave(NMDevice *device, NMDevice *port, NMConnection *connection, gboole
commit_port_options(device, port, s_port);
- _LOGI(LOGD_BOND, "assigned bond port %s", nm_device_get_ip_iface(port));
+ _LOGI(LOGD_BOND, "attached bond port %s", nm_device_get_ip_iface(port));
} else
- _LOGI(LOGD_BOND, "bond port %s was assigned", nm_device_get_ip_iface(port));
+ _LOGI(LOGD_BOND, "bond port %s was attached", nm_device_get_ip_iface(port));
return TRUE;
}
static void
-release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
+detach_port(NMDevice *device, NMDevice *port, gboolean configure)
{
NMDeviceBond *self = NM_DEVICE_BOND(device);
gboolean success;
@@ -472,10 +478,10 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
configure = FALSE;
}
- ifindex_slave = nm_device_get_ip_ifindex(slave);
+ ifindex_slave = nm_device_get_ip_ifindex(port);
if (ifindex_slave <= 0)
- _LOGD(LOGD_BOND, "bond slave %s is already released", nm_device_get_ip_iface(slave));
+ _LOGD(LOGD_BOND, "bond port %s is already detached", nm_device_get_ip_iface(port));
if (configure) {
NMConnection *applied;
@@ -490,9 +496,9 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
ifindex_slave);
if (success) {
- _LOGI(LOGD_BOND, "released bond slave %s", nm_device_get_ip_iface(slave));
+ _LOGI(LOGD_BOND, "detached bond port %s", nm_device_get_ip_iface(port));
} else {
- _LOGW(LOGD_BOND, "failed to release bond slave %s", nm_device_get_ip_iface(slave));
+ _LOGW(LOGD_BOND, "failed to detach bond port %s", nm_device_get_ip_iface(port));
}
}
@@ -512,12 +518,12 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
* other state is noticed by the now-released slave.
*/
if (ifindex_slave > 0) {
- if (!nm_device_bring_up(slave, TRUE, NULL))
- _LOGW(LOGD_BOND, "released bond slave could not be brought up.");
+ if (!nm_device_bring_up(port, TRUE, NULL))
+ _LOGW(LOGD_BOND, "detached bond port could not be brought up.");
}
} else {
if (ifindex_slave > 0) {
- _LOGI(LOGD_BOND, "bond slave %s was released", nm_device_get_ip_iface(slave));
+ _LOGI(LOGD_BOND, "bond port %s was detached", nm_device_get_ip_iface(port));
}
}
}
@@ -612,7 +618,7 @@ reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_ne
s_bond = nm_connection_get_setting_bond(con_new);
g_return_if_fail(s_bond);
- value = nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_MODE);
+ value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE);
mode = _nm_setting_bond_mode_from_string(value);
g_return_if_fail(mode != NM_BOND_MODE_UNKNOWN);
@@ -663,8 +669,8 @@ nm_device_bond_class_init(NMDeviceBondClass *klass)
device_class->create_and_realize = create_and_realize;
device_class->act_stage1_prepare = act_stage1_prepare;
device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired;
- device_class->enslave_slave = enslave_slave;
- device_class->release_slave = release_slave;
+ device_class->attach_port = attach_port;
+ device_class->detach_port = detach_port;
device_class->can_reapply_change = can_reapply_change;
device_class->reapply_connection = reapply_connection;
}
diff --git a/src/core/devices/nm-device-bridge.c b/src/core/devices/nm-device-bridge.c
index f11c172abb..dcdd160195 100644
--- a/src/core/devices/nm-device-bridge.c
+++ b/src/core/devices/nm-device-bridge.c
@@ -974,8 +974,14 @@ deactivate(NMDevice *device)
}
}
-static gboolean
-enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure)
+static NMTernary
+attach_port(NMDevice *device,
+ NMDevice *port,
+ NMConnection *connection,
+ gboolean configure,
+ GCancellable *cancellable,
+ NMDeviceAttachPortCallback callback,
+ gpointer user_data)
{
NMDeviceBridge *self = NM_DEVICE_BRIDGE(device);
NMConnection *master_connection;
@@ -985,7 +991,7 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool
if (configure) {
if (!nm_platform_link_enslave(nm_device_get_platform(device),
nm_device_get_ip_ifindex(device),
- nm_device_get_ip_ifindex(slave)))
+ nm_device_get_ip_ifindex(port)))
return FALSE;
master_connection = nm_device_get_applied_connection(device);
@@ -1009,25 +1015,25 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool
* (except for the default one) and so there's no need to flush. */
if (plat_vlans
- && !nm_platform_link_set_bridge_vlans(nm_device_get_platform(slave),
- nm_device_get_ifindex(slave),
+ && !nm_platform_link_set_bridge_vlans(nm_device_get_platform(port),
+ nm_device_get_ifindex(port),
TRUE,
plat_vlans))
return FALSE;
}
- commit_slave_options(slave, s_port);
+ commit_slave_options(port, s_port);
- _LOGI(LOGD_BRIDGE, "attached bridge port %s", nm_device_get_ip_iface(slave));
+ _LOGI(LOGD_BRIDGE, "attached bridge port %s", nm_device_get_ip_iface(port));
} else {
- _LOGI(LOGD_BRIDGE, "bridge port %s was attached", nm_device_get_ip_iface(slave));
+ _LOGI(LOGD_BRIDGE, "bridge port %s was attached", nm_device_get_ip_iface(port));
}
return TRUE;
}
static void
-release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
+detach_port(NMDevice *device, NMDevice *port, gboolean configure)
{
NMDeviceBridge *self = NM_DEVICE_BRIDGE(device);
gboolean success;
@@ -1040,10 +1046,10 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
configure = FALSE;
}
- ifindex_slave = nm_device_get_ip_ifindex(slave);
+ ifindex_slave = nm_device_get_ip_ifindex(port);
if (ifindex_slave <= 0) {
- _LOGD(LOGD_TEAM, "bond slave %s is already released", nm_device_get_ip_iface(slave));
+ _LOGD(LOGD_TEAM, "bridge port %s is already detached", nm_device_get_ip_iface(port));
return;
}
@@ -1053,12 +1059,12 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
ifindex_slave);
if (success) {
- _LOGI(LOGD_BRIDGE, "detached bridge port %s", nm_device_get_ip_iface(slave));
+ _LOGI(LOGD_BRIDGE, "detached bridge port %s", nm_device_get_ip_iface(port));
} else {
- _LOGW(LOGD_BRIDGE, "failed to detach bridge port %s", nm_device_get_ip_iface(slave));
+ _LOGW(LOGD_BRIDGE, "failed to detach bridge port %s", nm_device_get_ip_iface(port));
}
} else {
- _LOGI(LOGD_BRIDGE, "bridge port %s was detached", nm_device_get_ip_iface(slave));
+ _LOGI(LOGD_BRIDGE, "bridge port %s was detached", nm_device_get_ip_iface(port));
}
}
@@ -1084,10 +1090,6 @@ create_and_realize(NMDevice *device,
s_bridge = nm_connection_get_setting_bridge(connection);
nm_assert(s_bridge);
- s_wired = nm_connection_get_setting_wired(connection);
- if (s_wired)
- mtu = nm_setting_wired_get_mtu(s_wired);
-
hwaddr = nm_setting_bridge_get_mac_address(s_bridge);
if (!hwaddr
&& nm_device_hw_addr_get_cloned(device, connection, FALSE, &hwaddr_cloned, NULL, NULL)) {
@@ -1112,6 +1114,11 @@ create_and_realize(NMDevice *device,
_platform_lnk_bridge_init_from_setting(s_bridge, &props);
+ s_wired = nm_connection_get_setting_wired(connection);
+ nm_assert(s_wired);
+
+ mtu = nm_setting_wired_get_mtu(s_wired);
+
/* If mtu != 0, we set the MTU of the new bridge at creation time. However, kernel will still
* automatically adjust the MTU of the bridge based on the minimum of the slave's MTU.
* We don't want this automatism as the user asked for a fixed MTU.
@@ -1182,8 +1189,8 @@ nm_device_bridge_class_init(NMDeviceBridgeClass *klass)
device_class->act_stage1_prepare = act_stage1_prepare;
device_class->act_stage2_config = act_stage2_config;
device_class->deactivate = deactivate;
- device_class->enslave_slave = enslave_slave;
- device_class->release_slave = release_slave;
+ device_class->attach_port = attach_port;
+ device_class->detach_port = detach_port;
device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired;
}
diff --git a/src/core/devices/nm-device-vrf.c b/src/core/devices/nm-device-vrf.c
index ae80e1d462..2aef0e3d1e 100644
--- a/src/core/devices/nm-device-vrf.c
+++ b/src/core/devices/nm-device-vrf.c
@@ -206,38 +206,44 @@ update_connection(NMDevice *device, NMConnection *connection)
g_object_set(G_OBJECT(s_vrf), NM_SETTING_VRF_TABLE, priv->props.table, NULL);
}
-static gboolean
-enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure)
+static NMTernary
+attach_port(NMDevice *device,
+ NMDevice *port,
+ NMConnection *connection,
+ gboolean configure,
+ GCancellable *cancellable,
+ NMDeviceAttachPortCallback callback,
+ gpointer user_data)
{
- NMDeviceVrf *self = NM_DEVICE_VRF(device);
- gboolean success = TRUE;
- const char *slave_iface = nm_device_get_ip_iface(slave);
+ NMDeviceVrf *self = NM_DEVICE_VRF(device);
+ gboolean success = TRUE;
+ const char *port_iface = nm_device_get_ip_iface(port);
- nm_device_master_check_slave_physical_port(device, slave, LOGD_DEVICE);
+ nm_device_master_check_slave_physical_port(device, port, LOGD_DEVICE);
if (configure) {
- nm_device_take_down(slave, TRUE);
+ nm_device_take_down(port, TRUE);
success = nm_platform_link_enslave(nm_device_get_platform(device),
nm_device_get_ip_ifindex(device),
- nm_device_get_ip_ifindex(slave));
- nm_device_bring_up(slave, TRUE, NULL);
+ nm_device_get_ip_ifindex(port));
+ nm_device_bring_up(port, TRUE, NULL);
if (!success)
return FALSE;
- _LOGI(LOGD_DEVICE, "enslaved VRF slave %s", slave_iface);
+ _LOGI(LOGD_DEVICE, "attached VRF port %s", port_iface);
} else
- _LOGI(LOGD_BOND, "VRF slave %s was enslaved", slave_iface);
+ _LOGI(LOGD_BOND, "VRF port %s was attached", port_iface);
return TRUE;
}
static void
-release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
+detach_port(NMDevice *device, NMDevice *port, gboolean configure)
{
NMDeviceVrf *self = NM_DEVICE_VRF(device);
gboolean success;
- int ifindex_slave;
+ int ifindex_port;
int ifindex;
if (configure) {
@@ -246,26 +252,26 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
configure = FALSE;
}
- ifindex_slave = nm_device_get_ip_ifindex(slave);
+ ifindex_port = nm_device_get_ip_ifindex(port);
- if (ifindex_slave <= 0)
- _LOGD(LOGD_DEVICE, "VRF slave %s is already released", nm_device_get_ip_iface(slave));
+ if (ifindex_port <= 0)
+ _LOGD(LOGD_DEVICE, "VRF port %s is already detached", nm_device_get_ip_iface(port));
if (configure) {
- if (ifindex_slave > 0) {
+ if (ifindex_port > 0) {
success = nm_platform_link_release(nm_device_get_platform(device),
nm_device_get_ip_ifindex(device),
- ifindex_slave);
+ ifindex_port);
if (success) {
- _LOGI(LOGD_DEVICE, "released VRF slave %s", nm_device_get_ip_iface(slave));
+ _LOGI(LOGD_DEVICE, "detached VRF port %s", nm_device_get_ip_iface(port));
} else {
- _LOGW(LOGD_DEVICE, "failed to release VRF slave %s", nm_device_get_ip_iface(slave));
+ _LOGW(LOGD_DEVICE, "failed to detach VRF port %s", nm_device_get_ip_iface(port));
}
}
} else {
- if (ifindex_slave > 0) {
- _LOGI(LOGD_DEVICE, "VRF slave %s was released", nm_device_get_ip_iface(slave));
+ if (ifindex_port > 0) {
+ _LOGI(LOGD_DEVICE, "VRF port %s was detached", nm_device_get_ip_iface(port));
}
}
}
@@ -316,8 +322,8 @@ nm_device_vrf_class_init(NMDeviceVrfClass *klass)
device_class->is_master = TRUE;
device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_VRF);
- device_class->enslave_slave = enslave_slave;
- device_class->release_slave = release_slave;
+ device_class->attach_port = attach_port;
+ device_class->detach_port = detach_port;
device_class->link_changed = link_changed;
device_class->unrealize_notify = unrealize_notify;
device_class->create_and_realize = create_and_realize;
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 70b52b1ac1..f4171630a2 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -120,11 +120,12 @@ typedef enum _nm_packed {
} AddrMethodState;
typedef struct {
- CList lst_slave;
- NMDevice *slave;
- gulong watch_id;
- bool slave_is_enslaved;
- bool configure;
+ CList lst_slave;
+ NMDevice *slave;
+ GCancellable *cancellable;
+ gulong watch_id;
+ bool slave_is_enslaved;
+ bool configure;
} SlaveInfo;
typedef struct {
@@ -604,6 +605,7 @@ typedef struct _NMDevicePrivate {
const NMDeviceIPState state;
NMDeviceIPState state_;
};
+ gulong dnsmgr_update_pending_signal_id;
} ip_data;
union {
@@ -2930,6 +2932,13 @@ _add_capabilities(NMDevice *self, NMDeviceCapabilities capabilities)
/*****************************************************************************/
static void
+_dev_ip_state_dnsmgr_update_pending_changed(NMDnsManager *dnsmgr, GParamSpec *pspec, NMDevice *self)
+{
+ _dev_ip_state_check(self, AF_INET);
+ _dev_ip_state_check(self, AF_INET6);
+}
+
+static void
_dev_ip_state_req_timeout_cancel(NMDevice *self, int addr_family)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
@@ -3321,6 +3330,27 @@ got_ip_state:
combinedip_state = priv->ip_data.state;
}
+ if (combinedip_state == NM_DEVICE_IP_STATE_READY
+ && priv->ip_data.state <= NM_DEVICE_IP_STATE_PENDING
+ && nm_dns_manager_get_update_pending(nm_manager_get_dns_manager(priv->manager))) {
+ /* We would be ready, but a DNS update is pending. That prevents us from getting fully ready. */
+ if (priv->ip_data.dnsmgr_update_pending_signal_id == 0) {
+ priv->ip_data.dnsmgr_update_pending_signal_id =
+ g_signal_connect(nm_manager_get_dns_manager(priv->manager),
+ "notify::" NM_DNS_MANAGER_UPDATE_PENDING,
+ G_CALLBACK(_dev_ip_state_dnsmgr_update_pending_changed),
+ self);
+ _LOGT_ip(AF_UNSPEC,
+ "check-state: (combined) state: wait for DNS before becoming ready");
+ }
+ combinedip_state = NM_DEVICE_IP_STATE_PENDING;
+ }
+ if (combinedip_state != NM_DEVICE_IP_STATE_PENDING
+ && priv->ip_data.dnsmgr_update_pending_signal_id != 0) {
+ nm_clear_g_signal_handler(nm_manager_get_dns_manager(priv->manager),
+ &priv->ip_data.dnsmgr_update_pending_signal_id);
+ }
+
_LOGT_ip(AF_UNSPEC,
"check-state: (combined) state %s => %s",
nm_device_ip_state_to_string(priv->ip_data.state),
@@ -5898,43 +5928,16 @@ find_slave_info(NMDevice *self, NMDevice *slave)
return NULL;
}
-/**
- * nm_device_master_enslave_slave:
- * @self: the master device
- * @slave: the slave device to enslave
- * @connection: (allow-none): the slave device's connection
- *
- * If @self is capable of enslaving other devices (ie it's a bridge, bond, team,
- * etc) then this function enslaves @slave.
- *
- * Returns: %TRUE on success, %FALSE on failure or if this device cannot enslave
- * other devices.
- */
-static gboolean
-nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *connection)
+static void
+attach_port_done(NMDevice *self, NMDevice *slave, gboolean success)
{
SlaveInfo *info;
- gboolean success = FALSE;
- gboolean configure;
-
- g_return_val_if_fail(self != NULL, FALSE);
- g_return_val_if_fail(slave != NULL, FALSE);
- g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->enslave_slave != NULL, FALSE);
info = find_slave_info(self, slave);
if (!info)
- return FALSE;
-
- if (info->slave_is_enslaved)
- success = TRUE;
- else {
- configure = (info->configure && connection != NULL);
- if (configure)
- g_return_val_if_fail(nm_device_get_state(slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE);
+ return;
- success = NM_DEVICE_GET_CLASS(self)->enslave_slave(self, slave, connection, configure);
- info->slave_is_enslaved = success;
- }
+ info->slave_is_enslaved = success;
nm_device_slave_notify_enslave(info->slave, success);
@@ -5954,8 +5957,71 @@ nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *co
*/
if (success)
nm_device_activate_schedule_stage3_ip_config(self, FALSE);
+}
- return success;
+static void
+attach_port_cb(NMDevice *self, GError *error, gpointer user_data)
+{
+ NMDevice *slave = user_data;
+ SlaveInfo *info;
+
+ if (nm_utils_error_is_cancelled(error))
+ return;
+
+ info = find_slave_info(self, slave);
+ if (!info)
+ return;
+
+ nm_clear_g_cancellable(&info->cancellable);
+ attach_port_done(self, slave, !error);
+}
+
+/**
+ * nm_device_master_enslave_slave:
+ * @self: the master device
+ * @slave: the slave device to enslave
+ * @connection: (allow-none): the slave device's connection
+ *
+ * If @self is capable of enslaving other devices (ie it's a bridge, bond, team,
+ * etc) then this function enslaves @slave.
+ */
+static void
+nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *connection)
+{
+ SlaveInfo *info;
+ NMTernary success;
+ gboolean configure;
+
+ g_return_if_fail(self);
+ g_return_if_fail(slave);
+ g_return_if_fail(NM_DEVICE_GET_CLASS(self)->attach_port);
+
+ info = find_slave_info(self, slave);
+ if (!info)
+ return;
+
+ if (info->slave_is_enslaved)
+ success = TRUE;
+ else {
+ configure = (info->configure && connection != NULL);
+ if (configure)
+ g_return_if_fail(nm_device_get_state(slave) >= NM_DEVICE_STATE_DISCONNECTED);
+
+ nm_clear_g_cancellable(&info->cancellable);
+ info->cancellable = g_cancellable_new();
+ success = NM_DEVICE_GET_CLASS(self)->attach_port(self,
+ slave,
+ connection,
+ configure,
+ info->cancellable,
+ attach_port_cb,
+ slave);
+
+ if (success == NM_TERNARY_DEFAULT)
+ return;
+ }
+
+ attach_port_done(self, slave, success);
}
/**
@@ -5988,7 +6054,7 @@ nm_device_master_release_slave(NMDevice *self,
RELEASE_SLAVE_TYPE_NO_CONFIG,
RELEASE_SLAVE_TYPE_CONFIG,
RELEASE_SLAVE_TYPE_CONFIG_FORCE));
- g_return_if_fail(NM_DEVICE_GET_CLASS(self)->release_slave != NULL);
+ g_return_if_fail(NM_DEVICE_GET_CLASS(self)->detach_port != NULL);
info = find_slave_info(self, slave);
@@ -6009,13 +6075,14 @@ nm_device_master_release_slave(NMDevice *self,
g_return_if_fail(self == slave_priv->master);
nm_assert(slave == info->slave);
+ nm_clear_g_cancellable(&info->cancellable);
/* first, let subclasses handle the release ... */
if (info->slave_is_enslaved || nm_device_sys_iface_state_is_external(slave)
|| release_type >= RELEASE_SLAVE_TYPE_CONFIG_FORCE)
- NM_DEVICE_GET_CLASS(self)->release_slave(self,
- slave,
- release_type >= RELEASE_SLAVE_TYPE_CONFIG);
+ NM_DEVICE_GET_CLASS(self)->detach_port(self,
+ slave,
+ release_type >= RELEASE_SLAVE_TYPE_CONFIG);
/* raise notifications about the release, including clearing is_enslaved. */
nm_device_slave_notify_release(slave, reason);
@@ -6356,7 +6423,7 @@ device_recheck_slave_status(NMDevice *self, const NMPlatformLink *plink)
NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
}
- if (master && NM_DEVICE_GET_CLASS(master)->enslave_slave) {
+ if (master && NM_DEVICE_GET_CLASS(master)->attach_port) {
nm_device_master_add_slave(master, self, FALSE);
goto out;
}
@@ -7581,7 +7648,7 @@ nm_device_master_add_slave(NMDevice *self, NMDevice *slave, gboolean configure)
g_return_val_if_fail(NM_IS_DEVICE(self), FALSE);
g_return_val_if_fail(NM_IS_DEVICE(slave), FALSE);
- g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->enslave_slave != NULL, FALSE);
+ g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->attach_port, FALSE);
priv = NM_DEVICE_GET_PRIVATE(self);
slave_priv = NM_DEVICE_GET_PRIVATE(slave);
@@ -10036,6 +10103,7 @@ _dev_ipdhcpx_notify(NMDhcpClient *client, const NMDhcpClientNotifyData *notify_d
FALSE);
if (notify_data->lease_update.accepted) {
+ nm_manager_write_device_state(priv->manager, self, NULL);
if (priv->ipdhcp_data_x[IS_IPv4].state != NM_DEVICE_IP_STATE_READY) {
_dev_ipdhcpx_set_state(self, addr_family, NM_DEVICE_IP_STATE_READY);
nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP_CHANGE_X(IS_IPv4),
@@ -12342,7 +12410,8 @@ delete_on_deactivate_check_and_schedule(NMDevice *self)
static void
_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean from_reapply)
{
- const int IS_IPv4 = NM_IS_IPv4(addr_family);
+ const int IS_IPv4 = NM_IS_IPv4(addr_family);
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
_dev_ipsharedx_cleanup(self, addr_family);
@@ -12358,6 +12427,9 @@ _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gbool
_dev_ipmanual_cleanup(self);
+ nm_clear_g_signal_handler(nm_manager_get_dns_manager(priv->manager),
+ &priv->ip_data.dnsmgr_update_pending_signal_id);
+
_dev_ip_state_cleanup(self, AF_UNSPEC, from_reapply);
_dev_ip_state_cleanup(self, addr_family, from_reapply);
}
diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h
index 80def12511..377c2fb6b8 100644
--- a/src/core/devices/nm-device.h
+++ b/src/core/devices/nm-device.h
@@ -163,6 +163,7 @@ typedef enum {
} NMDeviceCheckDevAvailableFlags;
typedef void (*NMDeviceDeactivateCallback)(NMDevice *self, GError *error, gpointer user_data);
+typedef void (*NMDeviceAttachPortCallback)(NMDevice *self, GError *error, gpointer user_data);
typedef struct _NMDeviceClass {
NMDBusObjectClass parent;
@@ -373,12 +374,18 @@ typedef struct _NMDeviceClass {
NMConnection *connection,
GError **error);
- gboolean (*enslave_slave)(NMDevice *self,
- NMDevice *slave,
- NMConnection *connection,
- gboolean configure);
-
- void (*release_slave)(NMDevice *self, NMDevice *slave, gboolean configure);
+ /* Attachs a port asynchronously. Returns TRUE/FALSE on immediate
+ * success/error; in such cases, the callback is not invoked. If the
+ * action couldn't be completed immediately, DEFAULT is returned and
+ * the callback will always be invoked asynchronously. */
+ NMTernary (*attach_port)(NMDevice *self,
+ NMDevice *port,
+ NMConnection *connection,
+ gboolean configure,
+ GCancellable *cancellable,
+ NMDeviceAttachPortCallback callback,
+ gpointer user_data);
+ void (*detach_port)(NMDevice *self, NMDevice *port, gboolean configure);
void (*parent_changed_notify)(NMDevice *self,
int old_ifindex,
diff --git a/src/core/devices/ovs/nm-device-ovs-bridge.c b/src/core/devices/ovs/nm-device-ovs-bridge.c
index 683ada1339..bea6e77bc8 100644
--- a/src/core/devices/ovs/nm-device-ovs-bridge.c
+++ b/src/core/devices/ovs/nm-device-ovs-bridge.c
@@ -78,20 +78,26 @@ act_stage3_ip_config(NMDevice *device, int addr_family)
nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, NULL);
}
-static gboolean
-enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure)
+static NMTernary
+attach_port(NMDevice *device,
+ NMDevice *port,
+ NMConnection *connection,
+ gboolean configure,
+ GCancellable *cancellable,
+ NMDeviceAttachPortCallback callback,
+ gpointer user_data)
{
if (!configure)
return TRUE;
- if (!NM_IS_DEVICE_OVS_PORT(slave))
+ if (!NM_IS_DEVICE_OVS_PORT(port))
return FALSE;
return TRUE;
}
static void
-release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
+detach_port(NMDevice *device, NMDevice *port, gboolean configure)
{}
void
@@ -159,8 +165,8 @@ nm_device_ovs_bridge_class_init(NMDeviceOvsBridgeClass *klass)
device_class->get_generic_capabilities = get_generic_capabilities;
device_class->act_stage3_ip_config = act_stage3_ip_config;
device_class->ready_for_ip_config = ready_for_ip_config;
- device_class->enslave_slave = enslave_slave;
- device_class->release_slave = release_slave;
+ device_class->attach_port = attach_port;
+ device_class->detach_port = detach_port;
device_class->can_reapply_change_ovs_external_ids = TRUE;
device_class->reapply_connection = nm_device_ovs_reapply_connection;
}
diff --git a/src/core/devices/ovs/nm-device-ovs-port.c b/src/core/devices/ovs/nm-device-ovs-port.c
index 116f58c43a..a64314dd0c 100644
--- a/src/core/devices/ovs/nm-device-ovs-port.c
+++ b/src/core/devices/ovs/nm-device-ovs-port.c
@@ -72,20 +72,42 @@ act_stage3_ip_config(NMDevice *device, int addr_family)
nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, NULL);
}
+typedef struct {
+ NMDevice *device;
+ NMDevice *port;
+ GCancellable *cancellable;
+ NMDeviceAttachPortCallback callback;
+ gpointer callback_user_data;
+} AttachPortData;
+
static void
add_iface_cb(GError *error, gpointer user_data)
{
- NMDevice *slave = user_data;
-
- if (error && !g_error_matches(error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING)) {
- nm_log_warn(LOGD_DEVICE,
- "device %s could not be added to a ovs port: %s",
- nm_device_get_iface(slave),
- error->message);
- nm_device_state_changed(slave, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_OVSDB_FAILED);
+ AttachPortData *data = user_data;
+ NMDeviceOvsPort *self;
+ gs_free_error GError *local = NULL;
+
+ if (g_cancellable_is_cancelled(data->cancellable)) {
+ local = nm_utils_error_new_cancelled(FALSE, NULL);
+ error = local;
+ } else if (error && !nm_utils_error_is_cancelled_or_disposing(error)) {
+ self = NM_DEVICE_OVS_PORT(data->device);
+ _LOGW(LOGD_DEVICE,
+ "device %s could not be added to a ovs port: %s",
+ nm_device_get_iface(data->port),
+ error->message);
+ nm_device_state_changed(data->port,
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_OVSDB_FAILED);
}
- g_object_unref(slave);
+ data->callback(data->device, error, data->callback_user_data);
+
+ g_object_unref(data->device);
+ g_object_unref(data->port);
+ nm_clear_g_cancellable(&data->cancellable);
+
+ nm_g_slice_free(data);
}
static gboolean
@@ -115,14 +137,21 @@ set_mtu_cb(GError *error, gpointer user_data)
g_object_unref(self);
}
-static gboolean
-enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure)
+static NMTernary
+attach_port(NMDevice *device,
+ NMDevice *port,
+ NMConnection *connection,
+ gboolean configure,
+ GCancellable *cancellable,
+ NMDeviceAttachPortCallback callback,
+ gpointer user_data)
{
NMDeviceOvsPort *self = NM_DEVICE_OVS_PORT(device);
NMActiveConnection *ac_port = NULL;
NMActiveConnection *ac_bridge = NULL;
NMDevice *bridge_device;
NMSettingWired *s_wired;
+ AttachPortData *data;
if (!configure)
return TRUE;
@@ -131,42 +160,49 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool
ac_bridge = nm_active_connection_get_master(ac_port);
if (!ac_bridge) {
_LOGW(LOGD_DEVICE,
- "can't enslave %s: bridge active-connection not found",
- nm_device_get_iface(slave));
+ "can't attach %s: bridge active-connection not found",
+ nm_device_get_iface(port));
return FALSE;
}
bridge_device = nm_active_connection_get_device(ac_bridge);
if (!bridge_device) {
- _LOGW(LOGD_DEVICE, "can't enslave %s: bridge device not found", nm_device_get_iface(slave));
+ _LOGW(LOGD_DEVICE, "can't attach %s: bridge device not found", nm_device_get_iface(port));
return FALSE;
}
+ data = g_slice_new(AttachPortData);
+ *data = (AttachPortData){
+ .device = g_object_ref(device),
+ .port = g_object_ref(port),
+ .cancellable = g_object_ref(cancellable),
+ .callback = callback,
+ .callback_user_data = user_data,
+ };
+
nm_ovsdb_add_interface(nm_ovsdb_get(),
nm_active_connection_get_applied_connection(ac_bridge),
nm_device_get_applied_connection(device),
- nm_device_get_applied_connection(slave),
+ nm_device_get_applied_connection(port),
bridge_device,
- slave,
+ port,
add_iface_cb,
- g_object_ref(slave));
+ data);
/* DPDK ports does not have a link after the devbind, so the MTU must be
* set on ovsdb after adding the interface. */
- if (NM_IS_DEVICE_OVS_INTERFACE(slave) && _ovs_interface_is_dpdk(slave)) {
- s_wired = nm_device_get_applied_setting(slave, NM_TYPE_SETTING_WIRED);
-
- if (!s_wired || !nm_setting_wired_get_mtu(s_wired))
- return TRUE;
-
- nm_ovsdb_set_interface_mtu(nm_ovsdb_get(),
- nm_device_get_ip_iface(slave),
- nm_setting_wired_get_mtu(s_wired),
- set_mtu_cb,
- g_object_ref(slave));
+ if (NM_IS_DEVICE_OVS_INTERFACE(port) && _ovs_interface_is_dpdk(port)) {
+ s_wired = nm_device_get_applied_setting(port, NM_TYPE_SETTING_WIRED);
+ if (s_wired && nm_setting_wired_get_mtu(s_wired)) {
+ nm_ovsdb_set_interface_mtu(nm_ovsdb_get(),
+ nm_device_get_ip_iface(port),
+ nm_setting_wired_get_mtu(s_wired),
+ set_mtu_cb,
+ g_object_ref(port));
+ }
}
- return TRUE;
+ return NM_TERNARY_DEFAULT;
}
static void
@@ -186,31 +222,31 @@ del_iface_cb(GError *error, gpointer user_data)
}
static void
-release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
+detach_port(NMDevice *device, NMDevice *port, gboolean configure)
{
- NMDeviceOvsPort *self = NM_DEVICE_OVS_PORT(device);
- bool slave_not_managed = !NM_IN_SET(nm_device_sys_iface_state_get(slave),
- NM_DEVICE_SYS_IFACE_STATE_MANAGED,
- NM_DEVICE_SYS_IFACE_STATE_ASSUME);
+ NMDeviceOvsPort *self = NM_DEVICE_OVS_PORT(device);
+ bool port_not_managed = !NM_IN_SET(nm_device_sys_iface_state_get(port),
+ NM_DEVICE_SYS_IFACE_STATE_MANAGED,
+ NM_DEVICE_SYS_IFACE_STATE_ASSUME);
- _LOGI(LOGD_DEVICE, "releasing ovs interface %s", nm_device_get_ip_iface(slave));
+ _LOGI(LOGD_DEVICE, "detaching ovs interface %s", nm_device_get_ip_iface(port));
/* Even if the an interface's device has gone away (e.g. externally
* removed and thus we're called with configure=FALSE), we still need
* to make sure its OVSDB entry is gone.
*/
- if (configure || slave_not_managed) {
+ if (configure || port_not_managed) {
nm_ovsdb_del_interface(nm_ovsdb_get(),
- nm_device_get_iface(slave),
+ nm_device_get_iface(port),
del_iface_cb,
- g_object_ref(slave));
+ g_object_ref(port));
}
if (configure) {
/* Open VSwitch is going to delete this one. We must ignore what happens
* next with the interface. */
- if (NM_IS_DEVICE_OVS_INTERFACE(slave))
- nm_device_update_from_platform_link(slave, NULL);
+ if (NM_IS_DEVICE_OVS_INTERFACE(port))
+ nm_device_update_from_platform_link(port, NULL);
}
}
@@ -245,8 +281,8 @@ nm_device_ovs_port_class_init(NMDeviceOvsPortClass *klass)
device_class->get_generic_capabilities = get_generic_capabilities;
device_class->act_stage3_ip_config = act_stage3_ip_config;
device_class->ready_for_ip_config = ready_for_ip_config;
- device_class->enslave_slave = enslave_slave;
- device_class->release_slave = release_slave;
+ device_class->attach_port = attach_port;
+ device_class->detach_port = detach_port;
device_class->can_reapply_change_ovs_external_ids = TRUE;
device_class->reapply_connection = nm_device_ovs_reapply_connection;
}
diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c
index 44e16cb78f..eb8efe4bf8 100644
--- a/src/core/devices/ovs/nm-ovsdb.c
+++ b/src/core/devices/ovs/nm-ovsdb.c
@@ -376,6 +376,9 @@ ovsdb_call_method(NMOvsdb *self,
NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self);
OvsdbMethodCall *call;
+ /* FIXME(shutdown): this function should accept a cancellable to
+ * interrupt the operation. */
+
/* Ensure we're not unsynchronized before we queue the method call. */
ovsdb_try_connect(self);
@@ -1550,7 +1553,7 @@ _external_ids_to_string(const GArray *arr)
if (!arr)
return g_strdup("empty");
- nm_str_buf_init(&strbuf, NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE);
+ strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE);
nm_str_buf_append(&strbuf, "[");
for (i = 0; i < arr->len; i++) {
const NMUtilsNamedValue *n = &g_array_index(arr, NMUtilsNamedValue, i);
diff --git a/src/core/devices/team/nm-device-team.c b/src/core/devices/team/nm-device-team.c
index b67c710020..1f098806d3 100644
--- a/src/core/devices/team/nm-device-team.c
+++ b/src/core/devices/team/nm-device-team.c
@@ -790,19 +790,25 @@ deactivate(NMDevice *device)
teamd_cleanup(self, TRUE);
}
-static gboolean
-enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure)
+static NMTernary
+attach_port(NMDevice *device,
+ NMDevice *port,
+ NMConnection *connection,
+ gboolean configure,
+ GCancellable *cancellable,
+ NMDeviceAttachPortCallback callback,
+ gpointer user_data)
{
- NMDeviceTeam *self = NM_DEVICE_TEAM(device);
- NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self);
- gboolean success = TRUE;
- const char *slave_iface = nm_device_get_ip_iface(slave);
+ NMDeviceTeam *self = NM_DEVICE_TEAM(device);
+ NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self);
+ gboolean success = TRUE;
+ const char *port_iface = nm_device_get_ip_iface(port);
NMSettingTeamPort *s_team_port;
- nm_device_master_check_slave_physical_port(device, slave, LOGD_TEAM);
+ nm_device_master_check_slave_physical_port(device, port, LOGD_TEAM);
if (configure) {
- nm_device_take_down(slave, TRUE);
+ nm_device_take_down(port, TRUE);
s_team_port = nm_connection_get_setting_team_port(connection);
if (s_team_port) {
@@ -811,19 +817,19 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool
if (config) {
if (!priv->tdc) {
_LOGW(LOGD_TEAM,
- "enslaved team port %s config not changed, not connected to teamd",
- slave_iface);
+ "attached team port %s config not changed, not connected to teamd",
+ port_iface);
} else {
gs_free char *sanitized_config = NULL;
int err;
sanitized_config = g_strdup(config);
g_strdelimit(sanitized_config, "\r\n", ' ');
- err = teamdctl_port_config_update_raw(priv->tdc, slave_iface, sanitized_config);
+ err = teamdctl_port_config_update_raw(priv->tdc, port_iface, sanitized_config);
if (err != 0) {
_LOGE(LOGD_TEAM,
"failed to update config for port %s (err=%d)",
- slave_iface,
+ port_iface,
err);
return FALSE;
}
@@ -832,8 +838,8 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool
}
success = nm_platform_link_enslave(nm_device_get_platform(device),
nm_device_get_ip_ifindex(device),
- nm_device_get_ip_ifindex(slave));
- nm_device_bring_up(slave, TRUE, NULL);
+ nm_device_get_ip_ifindex(port));
+ nm_device_bring_up(port, TRUE, NULL);
if (!success)
return FALSE;
@@ -841,21 +847,21 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool
nm_clear_g_source(&priv->teamd_read_timeout);
priv->teamd_read_timeout = g_timeout_add_seconds(5, teamd_read_timeout_cb, self);
- _LOGI(LOGD_TEAM, "enslaved team port %s", slave_iface);
+ _LOGI(LOGD_TEAM, "attached team port %s", port_iface);
} else
- _LOGI(LOGD_TEAM, "team port %s was enslaved", slave_iface);
+ _LOGI(LOGD_TEAM, "team port %s was attached", port_iface);
return TRUE;
}
static void
-release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
+detach_port(NMDevice *device, NMDevice *port, gboolean configure)
{
NMDeviceTeam *self = NM_DEVICE_TEAM(device);
NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self);
gboolean do_release, success;
NMSettingTeamPort *s_port;
- int ifindex_slave;
+ int ifindex_port;
int ifindex;
do_release = configure;
@@ -865,39 +871,39 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure)
do_release = FALSE;
}
- ifindex_slave = nm_device_get_ip_ifindex(slave);
+ ifindex_port = nm_device_get_ip_ifindex(port);
- if (ifindex_slave <= 0) {
- _LOGD(LOGD_TEAM, "team port %s is already released", nm_device_get_ip_iface(slave));
+ if (ifindex_port <= 0) {
+ _LOGD(LOGD_TEAM, "team port %s is already detached", nm_device_get_ip_iface(port));
} else if (do_release) {
success = nm_platform_link_release(nm_device_get_platform(device),
nm_device_get_ip_ifindex(device),
- ifindex_slave);
+ ifindex_port);
if (success)
- _LOGI(LOGD_TEAM, "released team port %s", nm_device_get_ip_iface(slave));
+ _LOGI(LOGD_TEAM, "detached team port %s", nm_device_get_ip_iface(port));
else
- _LOGW(LOGD_TEAM, "failed to release team port %s", nm_device_get_ip_iface(slave));
+ _LOGW(LOGD_TEAM, "failed to detach team port %s", nm_device_get_ip_iface(port));
/* Kernel team code "closes" the port when releasing it, (which clears
* IFF_UP), so we must bring it back up here to ensure carrier changes and
* other state is noticed by the now-released port.
*/
- if (!nm_device_bring_up(slave, TRUE, NULL)) {
+ if (!nm_device_bring_up(port, TRUE, NULL)) {
_LOGW(LOGD_TEAM,
- "released team port %s could not be brought up",
- nm_device_get_ip_iface(slave));
+ "detached team port %s could not be brought up",
+ nm_device_get_ip_iface(port));
}
nm_clear_g_source(&priv->teamd_read_timeout);
priv->teamd_read_timeout = g_timeout_add_seconds(5, teamd_read_timeout_cb, self);
} else
- _LOGI(LOGD_TEAM, "team port %s was released", nm_device_get_ip_iface(slave));
+ _LOGI(LOGD_TEAM, "team port %s was detached", nm_device_get_ip_iface(port));
/* Delete any port configuration we previously set */
if (configure && priv->tdc
- && (s_port = nm_device_get_applied_setting(slave, NM_TYPE_SETTING_TEAM_PORT))
+ && (s_port = nm_device_get_applied_setting(port, NM_TYPE_SETTING_TEAM_PORT))
&& (nm_setting_team_port_get_config(s_port)))
- teamdctl_port_config_update_raw(priv->tdc, nm_device_get_ip_iface(slave), "{}");
+ teamdctl_port_config_update_raw(priv->tdc, nm_device_get_ip_iface(port), "{}");
}
static gboolean
@@ -1064,8 +1070,8 @@ nm_device_team_class_init(NMDeviceTeamClass *klass)
device_class->act_stage1_prepare = act_stage1_prepare;
device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired;
device_class->deactivate = deactivate;
- device_class->enslave_slave = enslave_slave;
- device_class->release_slave = release_slave;
+ device_class->attach_port = attach_port;
+ device_class->detach_port = detach_port;
obj_properties[PROP_CONFIG] = g_param_spec_string(NM_DEVICE_TEAM_CONFIG,
"",
diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c
index 2bfd7e01eb..e71590858a 100644
--- a/src/core/dhcp/nm-dhcp-client.c
+++ b/src/core/dhcp/nm-dhcp-client.c
@@ -291,6 +291,7 @@ nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, const NML3Co
if (!IS_IPv4 && l3cd) {
if (nm_dhcp_utils_merge_new_dhcp6_lease(priv->l3cd, l3cd, &l3cd_merged)) {
+ _LOGD("lease merged with existing one");
l3cd = nm_l3_config_data_seal(l3cd_merged);
}
}
@@ -327,14 +328,6 @@ nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, const NML3Co
keys[i],
(char *) g_hash_table_lookup(options, keys[i]));
}
-
- if (priv->config.addr_family == AF_INET6) {
- gs_free char *event_id = NULL;
-
- event_id = nm_dhcp_utils_get_dhcp6_event_id(options);
- if (event_id)
- _LOGT("event-id: \"%s\"", event_id);
- }
}
}
@@ -1080,7 +1073,7 @@ config_init(NMDhcpClientConfig *config, const NMDhcpClientConfig *src)
if (!config->send_hostname) {
nm_clear_g_free((gpointer *) &config->hostname);
} else if ((config->use_fqdn && !nm_sd_dns_name_is_valid(config->hostname))
- || (!config->use_fqdn && !nm_sd_hostname_is_valid(config->hostname, FALSE))) {
+ || (!config->use_fqdn && !nm_hostname_is_valid(config->hostname, FALSE))) {
nm_log_warn(LOGD_DHCP,
"dhcp%c: %s '%s' is invalid, will be ignored",
nm_utils_addr_family_to_char(config->addr_family),
diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c
index aac189676d..7068a6e924 100644
--- a/src/core/dhcp/nm-dhcp-nettools.c
+++ b/src/core/dhcp/nm-dhcp-nettools.c
@@ -13,22 +13,24 @@
#include <ctype.h>
#include <net/if_arp.h>
+#include "n-dhcp4/src/n-dhcp4.h"
+
#include "libnm-glib-aux/nm-dedup-multi.h"
-#include "libnm-std-aux/unaligned.h"
+#include "libnm-glib-aux/nm-io-utils.h"
#include "libnm-glib-aux/nm-str-buf.h"
+#include "libnm-std-aux/unaligned.h"
-#include "nm-l3-config-data.h"
-#include "nm-utils.h"
-#include "nm-config.h"
-#include "nm-dhcp-utils.h"
-#include "nm-dhcp-options.h"
-#include "nm-core-utils.h"
#include "NetworkManagerUtils.h"
#include "libnm-platform/nm-platform.h"
+#include "nm-config.h"
+#include "nm-core-utils.h"
#include "nm-dhcp-client-logging.h"
-#include "n-dhcp4/src/n-dhcp4.h"
+#include "nm-dhcp-options.h"
+#include "nm-dhcp-utils.h"
+#include "nm-l3-config-data.h"
+#include "nm-utils.h"
+
#include "libnm-systemd-shared/nm-sd-utils-shared.h"
-#include "libnm-systemd-core/nm-sd-utils-dhcp.h"
/*****************************************************************************/
@@ -887,12 +889,15 @@ dhcp4_event_cb(int fd, GIOCondition condition, gpointer user_data)
r = n_dhcp4_client_dispatch(priv->client);
if (r < 0) {
- /* FIXME: if any operation (e.g. send()) fails during the
+ /* If any operation (e.g. send()) fails during the
* dispatch, n-dhcp4 returns an error without arming timers
* or progressing state, so the only reasonable thing to do
* is to move to failed state so that the client will be
- * restarted. Ideally n-dhcp4 should retry failed operations
- * a predefined number of times (possibly infinite).
+ * restarted.
+ *
+ * That means, n_dhcp4_client_dispatch() must not fail if it can
+ * somehow workaround the problem. A failure is really fatal
+ * and the client needs to be restarted.
*/
_LOGE("error %d dispatching events", r);
nm_clear_g_source_inst(&priv->event_source);
@@ -1107,18 +1112,20 @@ ip4_start(NMDhcpClient *client, GError **error)
if (client_config->v4.last_address)
inet_pton(AF_INET, client_config->v4.last_address, &last_addr);
else {
- /*
- * TODO: we stick to the systemd-networkd lease file format. Quite easy for now to
- * just use the functions in systemd code. Anyway, as in the end we just use the
- * ip address from all the options found in the lease, write a function that parses
- * the lease file just for the assigned address and returns it in &last_address.
- * Then drop reference to systemd-networkd structures and functions.
- */
- nm_auto(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
-
- dhcp_lease_load(&lease, lease_file);
- if (lease)
- sd_dhcp_lease_get_address(lease, &last_addr);
+ gs_free char *contents = NULL;
+ gs_free char *s_addr = NULL;
+
+ nm_utils_file_get_contents(-1,
+ lease_file,
+ 64 * 1024,
+ NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE,
+ &contents,
+ NULL,
+ NULL,
+ NULL);
+ nm_parse_env_file(contents, "ADDRESS", &s_addr);
+ if (s_addr)
+ nm_utils_parse_inaddr_bin(AF_INET, s_addr, NULL, &last_addr);
}
if (last_addr.s_addr) {
diff --git a/src/core/dhcp/nm-dhcp-systemd.c b/src/core/dhcp/nm-dhcp-systemd.c
index 4a718de9ec..045d528791 100644
--- a/src/core/dhcp/nm-dhcp-systemd.c
+++ b/src/core/dhcp/nm-dhcp-systemd.c
@@ -25,7 +25,6 @@
#include "libnm-platform/nm-platform.h"
#include "nm-dhcp-client-logging.h"
#include "libnm-systemd-core/nm-sd.h"
-#include "libnm-systemd-core/nm-sd-utils-dhcp.h"
/*****************************************************************************/
@@ -47,7 +46,6 @@ static GType nm_dhcp_systemd_get_type(void);
/*****************************************************************************/
typedef struct {
- sd_dhcp_client *client4;
sd_dhcp6_client *client6;
char *lease_file;
@@ -70,675 +68,6 @@ G_DEFINE_TYPE(NMDhcpSystemd, nm_dhcp_systemd, NM_TYPE_DHCP_CLIENT)
/*****************************************************************************/
static NML3ConfigData *
-lease_to_ip4_config(NMDedupMultiIndex *multi_idx,
- const char *iface,
- int ifindex,
- sd_dhcp_lease *lease,
- GError **error)
-{
- nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
- gs_unref_hashtable GHashTable *options = NULL;
- const struct in_addr *addr_list;
- char addr_str[NM_UTILS_INET_ADDRSTRLEN];
- const char *s;
- nm_auto_free_gstring GString *str = NULL;
- nm_auto_free sd_dhcp_route **routes_static = NULL;
- nm_auto_free sd_dhcp_route **routes_classless = NULL;
- const char *const *search_domains = NULL;
- guint32 default_route_metric_offset;
- guint16 mtu;
- int i;
- int num;
- int is_classless;
- int n_routes_static;
- int n_routes_classless;
- const void *data;
- gsize data_len;
- gboolean has_router_from_classless = FALSE;
- const gint32 ts = nm_utils_get_monotonic_timestamp_sec();
- gint64 ts_time = time(NULL);
- struct in_addr a_address;
- struct in_addr a_netmask;
- struct in_addr a_next_server;
- struct in_addr server_id;
- struct in_addr broadcast;
- const struct in_addr *a_router;
- guint32 a_plen;
- guint32 a_lifetime;
- guint32 renewal;
- guint32 rebinding;
- gs_free nm_sd_dhcp_option *private_options = NULL;
-
- nm_assert(lease != NULL);
-
- if (sd_dhcp_lease_get_address(lease, &a_address) < 0) {
- nm_utils_error_set_literal(error,
- NM_UTILS_ERROR_UNKNOWN,
- "could not get address from lease");
- return NULL;
- }
-
- if (sd_dhcp_lease_get_netmask(lease, &a_netmask) < 0) {
- nm_utils_error_set_literal(error,
- NM_UTILS_ERROR_UNKNOWN,
- "could not get netmask from lease");
- return NULL;
- }
-
- if (sd_dhcp_lease_get_lifetime(lease, &a_lifetime) < 0) {
- nm_utils_error_set_literal(error,
- NM_UTILS_ERROR_UNKNOWN,
- "could not get lifetime from lease");
- return NULL;
- }
-
- l3cd = nm_l3_config_data_new(multi_idx, ifindex, NM_IP_CONFIG_SOURCE_DHCP);
-
- options = nm_dhcp_option_create_options_dict();
-
- _nm_utils_inet4_ntop(a_address.s_addr, addr_str);
- nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS, addr_str);
-
- a_plen = nm_utils_ip4_netmask_to_prefix(a_netmask.s_addr);
- nm_dhcp_option_add_option(options,
- AF_INET,
- NM_DHCP_OPTION_DHCP4_SUBNET_MASK,
- _nm_utils_inet4_ntop(a_netmask.s_addr, addr_str));
-
- nm_dhcp_option_add_option_u64(options,
- AF_INET,
- NM_DHCP_OPTION_DHCP4_IP_ADDRESS_LEASE_TIME,
- a_lifetime);
- nm_dhcp_option_add_option_u64(options,
- AF_INET,
- NM_DHCP_OPTION_DHCP4_NM_EXPIRY,
- (guint64) (ts_time + a_lifetime));
-
- if (sd_dhcp_lease_get_next_server(lease, &a_next_server) == 0) {
- _nm_utils_inet4_ntop(a_next_server.s_addr, addr_str);
- nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER, addr_str);
- }
-
- nm_l3_config_data_add_address_4(l3cd,
- &((const NMPlatformIP4Address){
- .address = a_address.s_addr,
- .peer_address = a_address.s_addr,
- .plen = a_plen,
- .addr_source = NM_IP_CONFIG_SOURCE_DHCP,
- .timestamp = ts,
- .lifetime = a_lifetime,
- .preferred = a_lifetime,
- }));
-
- if (sd_dhcp_lease_get_server_identifier(lease, &server_id) >= 0) {
- _nm_utils_inet4_ntop(server_id.s_addr, addr_str);
- nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_SERVER_ID, addr_str);
- }
-
- if (sd_dhcp_lease_get_broadcast(lease, &broadcast) >= 0) {
- _nm_utils_inet4_ntop(broadcast.s_addr, addr_str);
- nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_BROADCAST, addr_str);
- }
-
- num = sd_dhcp_lease_get_dns(lease, &addr_list);
- if (num > 0) {
- nm_gstring_prepare(&str);
- for (i = 0; i < num; i++) {
- _nm_utils_inet4_ntop(addr_list[i].s_addr, addr_str);
- g_string_append(nm_gstring_add_space_delimiter(str), addr_str);
-
- if (addr_list[i].s_addr == 0 || nm_ip4_addr_is_localhost(addr_list[i].s_addr)) {
- /* Skip localhost addresses, like also networkd does.
- * See https://github.com/systemd/systemd/issues/4524. */
- continue;
- }
- nm_l3_config_data_add_nameserver(l3cd, AF_INET, &addr_list[i].s_addr);
- }
- nm_dhcp_option_add_option(options,
- AF_INET,
- NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER,
- str->str);
- }
-
- num = sd_dhcp_lease_get_search_domains(lease, (char ***) &search_domains);
- if (num > 0) {
- nm_gstring_prepare(&str);
- for (i = 0; i < num; i++) {
- g_string_append(nm_gstring_add_space_delimiter(str), search_domains[i]);
- nm_l3_config_data_add_search(l3cd, AF_INET, search_domains[i]);
- }
- nm_dhcp_option_add_option(options,
- AF_INET,
- NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST,
- str->str);
- }
-
- if (sd_dhcp_lease_get_domainname(lease, &s) >= 0) {
- gs_strfreev char **domains = NULL;
- char **d;
-
- nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_DOMAIN_NAME, s);
-
- /* Multiple domains sometimes stuffed into option 15 "Domain Name".
- * As systemd escapes such characters, split them at \\032. */
- domains = g_strsplit(s, "\\032", 0);
- for (d = domains; *d; d++)
- nm_l3_config_data_add_domain(l3cd, AF_INET, *d);
- }
-
- if (sd_dhcp_lease_get_hostname(lease, &s) >= 0) {
- nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_HOST_NAME, s);
- }
-
- default_route_metric_offset = 0;
- n_routes_static = sd_dhcp_lease_get_static_routes(lease, &routes_static);
- n_routes_classless = sd_dhcp_lease_get_classless_routes(lease, &routes_classless);
- for (is_classless = 1; is_classless >= 0; is_classless--) {
- int n_routes = (is_classless ? n_routes_classless : n_routes_static);
- sd_dhcp_route *const *routes = (is_classless ? routes_classless : routes_static);
-
- if (n_routes <= 0)
- continue;
-
- nm_gstring_prepare(&str);
-
- for (i = 0; i < n_routes; i++) {
- char network_net_str[NM_UTILS_INET_ADDRSTRLEN];
- char gateway_str[NM_UTILS_INET_ADDRSTRLEN];
- guint8 r_plen;
- struct in_addr r_network;
- struct in_addr r_gateway;
- in_addr_t network_net;
- guint32 m;
-
- if (sd_dhcp_route_get_destination(routes[i], &r_network) < 0)
- continue;
- if (sd_dhcp_route_get_destination_prefix_length(routes[i], &r_plen) < 0 || r_plen > 32)
- continue;
- if (sd_dhcp_route_get_gateway(routes[i], &r_gateway) < 0)
- continue;
-
- network_net = nm_utils_ip4_address_clear_host_address(r_network.s_addr, r_plen);
- _nm_utils_inet4_ntop(network_net, network_net_str);
- _nm_utils_inet4_ntop(r_gateway.s_addr, gateway_str);
-
- g_string_append_printf(nm_gstring_add_space_delimiter(str),
- "%s/%d %s",
- network_net_str,
- (int) r_plen,
- gateway_str);
-
- if (!is_classless && n_routes_classless > 0) {
- /* RFC 3443: if the DHCP server returns both a Classless Static Routes
- * option and a Static Routes option, the DHCP client MUST ignore the
- * Static Routes option. */
- continue;
- }
-
- if (r_plen == 0) {
- if (!is_classless) {
- /* for option 33 (static route), RFC 2132 says:
- *
- * The default route (0.0.0.0) is an illegal destination for a static
- * route. */
- continue;
- }
-
- /* if there are multiple default routes, we add them with differing
- * metrics. */
- m = default_route_metric_offset++;
- has_router_from_classless = TRUE;
- } else
- m = 0;
-
- nm_l3_config_data_add_route_4(l3cd,
- &((const NMPlatformIP4Route){
- .rt_source = NM_IP_CONFIG_SOURCE_DHCP,
- .network = network_net,
- .plen = r_plen,
- .gateway = r_gateway.s_addr,
- .pref_src = a_address.s_addr,
- .metric_any = TRUE,
- .metric = m,
- .table_any = TRUE,
- .table_coerced = 0,
- }));
- }
-
- if (str->len > 0) {
- nm_dhcp_option_add_option(options,
- AF_INET,
- is_classless ? NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE
- : NM_DHCP_OPTION_DHCP4_STATIC_ROUTE,
- str->str);
- }
- }
-
- num = sd_dhcp_lease_get_router(lease, &a_router);
- if (num > 0) {
- default_route_metric_offset = 0;
-
- nm_gstring_prepare(&str);
- for (i = 0; i < num; i++) {
- guint32 m;
-
- s = _nm_utils_inet4_ntop(a_router[i].s_addr, addr_str);
- g_string_append(nm_gstring_add_space_delimiter(str), s);
-
- if (a_router[i].s_addr == 0) {
- /* silently skip 0.0.0.0 */
- continue;
- }
-
- if (has_router_from_classless) {
- /* If the DHCP server returns both a Classless Static Routes option and a
- * Router option, the DHCP client MUST ignore the Router option [RFC 3442].
- *
- * Be more lenient and ignore the Router option only if Classless Static
- * Routes contain a default gateway (as other DHCP backends do).
- */
- continue;
- }
-
- /* if there are multiple default routes, we add them with differing
- * metrics. */
- m = default_route_metric_offset++;
-
- nm_l3_config_data_add_route_4(l3cd,
- &((const NMPlatformIP4Route){
- .rt_source = NM_IP_CONFIG_SOURCE_DHCP,
- .gateway = a_router[i].s_addr,
- .pref_src = a_address.s_addr,
- .table_any = TRUE,
- .table_coerced = 0,
- .metric_any = TRUE,
- .metric = m,
- }));
- }
- nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_ROUTER, str->str);
- }
-
- if (sd_dhcp_lease_get_mtu(lease, &mtu) >= 0 && mtu) {
- nm_dhcp_option_add_option_u64(options, AF_INET, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, mtu);
- nm_l3_config_data_set_mtu(l3cd, mtu);
- }
-
- num = sd_dhcp_lease_get_ntp(lease, &addr_list);
- if (num > 0) {
- nm_gstring_prepare(&str);
- for (i = 0; i < num; i++) {
- _nm_utils_inet4_ntop(addr_list[i].s_addr, addr_str);
- g_string_append(nm_gstring_add_space_delimiter(str), addr_str);
- }
- nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NTP_SERVER, str->str);
- }
-
- if (sd_dhcp_lease_get_root_path(lease, &s) >= 0) {
- nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_ROOT_PATH, s);
- }
-
- if (sd_dhcp_lease_get_t1(lease, &renewal) >= 0) {
- nm_dhcp_option_add_option_u64(options,
- AF_INET,
- NM_DHCP_OPTION_DHCP4_RENEWAL_T1_TIME,
- renewal);
- }
-
- if (sd_dhcp_lease_get_t2(lease, &rebinding) >= 0) {
- nm_dhcp_option_add_option_u64(options,
- AF_INET,
- NM_DHCP_OPTION_DHCP4_REBINDING_T2_TIME,
- rebinding);
- }
-
- if (sd_dhcp_lease_get_timezone(lease, &s) >= 0) {
- nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NEW_TZDB_TIMEZONE, s);
- }
-
- if (sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len) >= 0) {
- if (!!memmem(data, data_len, "ANDROID_METERED", NM_STRLEN("ANDROID_METERED")))
- nm_l3_config_data_set_metered(l3cd, TRUE);
- }
-
- num = nm_sd_dhcp_lease_get_private_options(lease, &private_options);
- if (num > 0) {
- for (i = 0; i < num; i++) {
- guint8 code = private_options[i].code;
- const guint8 *l_data = private_options[i].data;
- gsize l_data_len = private_options[i].data_len;
- char *option_string;
-
- if (code == NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY) {
- if (nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) {
- gs_free char *to_free = NULL;
- const char *escaped;
-
- escaped =
- nm_utils_buf_utf8safe_escape((char *) l_data, l_data_len, 0, &to_free);
- nm_dhcp_option_add_option(options,
- AF_INET,
- NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY,
- escaped ?: "");
-
- nm_l3_config_data_set_proxy_method(l3cd, NM_PROXY_CONFIG_METHOD_AUTO);
- nm_l3_config_data_set_proxy_pac_url(l3cd, escaped ?: "");
- }
- continue;
- }
- if (code == NM_DHCP_OPTION_DHCP4_PRIVATE_CLASSLESS_STATIC_ROUTE) {
- /* nettools and dhclient parse option 249 (Microsoft Classless Static Route)
- * as fallback for routes and ignores them from private options.
- *
- * The systemd plugin does not, and for consistency with nettools we
- * also don't expose it as private option either. */
- continue;
- }
-
- option_string = nm_utils_bin2hexstr_full(l_data, l_data_len, ':', FALSE, NULL);
- nm_dhcp_option_take_option(options, AF_INET, code, option_string);
- }
- }
-
- nm_dhcp_option_add_requests_to_options(options, AF_INET);
-
- nm_l3_config_data_set_dhcp_lease_from_options(l3cd, AF_INET, g_steal_pointer(&options));
-
- return g_steal_pointer(&l3cd);
-}
-
-/*****************************************************************************/
-
-static void
-bound4_handle(NMDhcpSystemd *self, gboolean extended)
-{
- NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self);
- const char *iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self));
- nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
- sd_dhcp_lease *lease = NULL;
- GError *error = NULL;
-
- if (sd_dhcp_client_get_lease(priv->client4, &lease) < 0 || !lease) {
- _LOGW("no lease!");
- nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL);
- return;
- }
-
- _LOGD("lease available");
-
- l3cd = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)),
- iface,
- nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)),
- lease,
- &error);
- if (!l3cd) {
- _LOGW("%s", error->message);
- g_clear_error(&error);
- nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL);
- return;
- }
-
- dhcp_lease_save(lease, priv->lease_file);
-
- nm_dhcp_client_set_state(NM_DHCP_CLIENT(self),
- extended ? NM_DHCP_STATE_EXTENDED : NM_DHCP_STATE_BOUND,
- l3cd);
-}
-
-static int
-dhcp_event_cb(sd_dhcp_client *client, int event, gpointer user_data)
-{
- NMDhcpSystemd *self = NM_DHCP_SYSTEMD(user_data);
- NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self);
- char addr_str[INET_ADDRSTRLEN];
- sd_dhcp_lease *lease = NULL;
- struct in_addr addr;
- int r;
-
- nm_assert(priv->client4 == client);
-
- _LOGD("client event %d", event);
-
- switch (event) {
- case SD_DHCP_CLIENT_EVENT_EXPIRED:
- nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_EXPIRE, NULL);
- break;
- case SD_DHCP_CLIENT_EVENT_STOP:
- nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL);
- break;
- case SD_DHCP_CLIENT_EVENT_RENEW:
- case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
- bound4_handle(self, TRUE);
- break;
- case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
- bound4_handle(self, FALSE);
- break;
- case SD_DHCP_CLIENT_EVENT_SELECTING:
- r = sd_dhcp_client_get_lease(priv->client4, &lease);
- if (r < 0)
- return r;
- r = sd_dhcp_lease_get_server_identifier(lease, &addr);
- if (r < 0)
- return r;
- if (nm_dhcp_client_server_id_is_rejected(NM_DHCP_CLIENT(user_data), &addr)) {
- _LOGD("server-id %s is in the reject-list, ignoring",
- nm_utils_inet_ntop(AF_INET, &addr, addr_str));
- return -ENOMSG;
- }
- break;
- case SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE:
- break;
- default:
- _LOGW("unhandled DHCP event %d", event);
- break;
- }
-
- return 0;
-}
-
-static gboolean
-ip4_start(NMDhcpClient *client, GError **error)
-{
- nm_auto(sd_dhcp_client_unrefp) sd_dhcp_client *sd_client = NULL;
- NMDhcpSystemd *self = NM_DHCP_SYSTEMD(client);
- NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self);
- const NMDhcpClientConfig *client_config;
- gs_free char *lease_file = NULL;
- GBytes *hwaddr;
- const uint8_t *hwaddr_arr;
- gsize hwaddr_len;
- int arp_type;
- GBytes *client_id;
- gs_unref_bytes GBytes *client_id_new = NULL;
- GBytes *vendor_class_identifier;
- const uint8_t *client_id_arr;
- size_t client_id_len;
- struct in_addr last_addr = {0};
- const char *hostname;
- const char *mud_url;
- int r, i;
- GBytes *bcast_hwaddr;
- const uint8_t *bcast_hwaddr_arr;
- gsize bcast_hwaddr_len;
-
- g_return_val_if_fail(!priv->client4, FALSE);
- g_return_val_if_fail(!priv->client6, FALSE);
-
- client_config = nm_dhcp_client_get_config(client);
-
- /* TODO: honor nm_dhcp_client_get_anycast_address() */
-
- r = sd_dhcp_client_new(&sd_client, FALSE);
- if (r < 0) {
- nm_utils_error_set_errno(error, r, "failed to create dhcp-client: %s");
- return FALSE;
- }
-
- _LOGT("dhcp-client4: set " NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(sd_client));
-
- r = sd_dhcp_client_attach_event(sd_client, NULL, 0);
- if (r < 0) {
- nm_utils_error_set_errno(error, r, "failed to attach event: %s");
- return FALSE;
- }
-
- hwaddr = client_config->hwaddr;
- if (!hwaddr || !(hwaddr_arr = g_bytes_get_data(hwaddr, &hwaddr_len))
- || (arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len)) < 0) {
- nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address");
- return FALSE;
- }
-
- bcast_hwaddr_arr = NULL;
- bcast_hwaddr = client_config->bcast_hwaddr;
- if (bcast_hwaddr) {
- bcast_hwaddr_arr = g_bytes_get_data(bcast_hwaddr, &bcast_hwaddr_len);
- if (bcast_hwaddr_len != hwaddr_len)
- bcast_hwaddr_arr = NULL;
- }
-
- r = sd_dhcp_client_set_mac(sd_client,
- hwaddr_arr,
- bcast_hwaddr_arr,
- hwaddr_len,
- (guint16) arp_type);
- if (r < 0) {
- nm_utils_error_set_errno(error, r, "failed to set MAC address: %s");
- return FALSE;
- }
-
- r = sd_dhcp_client_set_ifindex(sd_client, nm_dhcp_client_get_ifindex(client));
- if (r < 0) {
- nm_utils_error_set_errno(error, r, "failed to set ifindex: %s");
- return FALSE;
- }
-
- nm_dhcp_utils_get_leasefile_path(AF_INET,
- "internal",
- client_config->iface,
- client_config->uuid,
- &lease_file);
-
- if (client_config->v4.last_address)
- inet_pton(AF_INET, client_config->v4.last_address, &last_addr);
- else {
- nm_auto(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
-
- dhcp_lease_load(&lease, lease_file);
- if (lease)
- sd_dhcp_lease_get_address(lease, &last_addr);
- }
-
- r = sd_dhcp_client_set_request_broadcast(sd_client, client_config->v4.request_broadcast);
- nm_assert(r >= 0);
-
- if (last_addr.s_addr) {
- r = sd_dhcp_client_set_request_address(sd_client, &last_addr);
- if (r < 0) {
- nm_utils_error_set_errno(error, r, "failed to set last IPv4 address: %s");
- return FALSE;
- }
- }
-
- client_id = client_config->client_id;
- if (!client_id) {
- client_id_new = nm_utils_dhcp_client_id_mac(arp_type, hwaddr_arr, hwaddr_len);
- client_id = client_id_new;
- }
-
- if (!(client_id_arr = g_bytes_get_data(client_id, &client_id_len)) || client_id_len < 2) {
- /* invalid client-ids are not expected. */
- nm_assert_not_reached();
-
- nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "no valid IPv4 client-id");
- return FALSE;
- }
-
- /* Note that we always set a client-id. In particular for infiniband that is necessary,
- * see https://tools.ietf.org/html/rfc4390#section-2.1 . */
- r = sd_dhcp_client_set_client_id(sd_client,
- client_id_arr[0],
- client_id_arr + 1,
- NM_MIN(client_id_len - 1, _NM_MAX_CLIENT_ID_LEN));
- if (r < 0) {
- nm_utils_error_set_errno(error, r, "failed to set IPv4 client-id: %s");
- return FALSE;
- }
-
- /* Add requested options */
- for (i = 0; i < (int) G_N_ELEMENTS(_nm_dhcp_option_dhcp4_options); i++) {
- if (_nm_dhcp_option_dhcp4_options[i].include) {
- nm_assert(_nm_dhcp_option_dhcp4_options[i].option_num <= 255);
- r = sd_dhcp_client_set_request_option(sd_client,
- _nm_dhcp_option_dhcp4_options[i].option_num);
- nm_assert(r >= 0 || r == -EEXIST);
- }
- }
-
- hostname = client_config->hostname;
- if (hostname) {
- /* FIXME: sd-dhcp decides which hostname/FQDN option to send (12 or 81)
- * only based on whether the hostname has a domain part or not. At the
- * moment there is no way to force one or another.
- */
- r = sd_dhcp_client_set_hostname(sd_client, hostname);
- if (r < 0) {
- nm_utils_error_set_errno(error, r, "failed to set DHCP hostname: %s");
- return FALSE;
- }
- }
-
- mud_url = client_config->mud_url;
- if (mud_url) {
- r = sd_dhcp_client_set_mud_url(sd_client, mud_url);
- if (r < 0) {
- nm_utils_error_set_errno(error, r, "failed to set DHCP MUDURL: %s");
- return FALSE;
- }
- }
-
- vendor_class_identifier = client_config->vendor_class_identifier;
- if (vendor_class_identifier) {
- const char *option_data;
- gsize len;
-
- option_data = g_bytes_get_data(vendor_class_identifier, &len);
- nm_assert(option_data);
- nm_assert(len <= 255);
-
- option_data = nm_strndup_a(300, option_data, len, NULL);
-
- r = sd_dhcp_client_set_vendor_class_identifier(sd_client, option_data);
- if (r < 0) {
- nm_utils_error_set_errno(error, r, "failed to set DHCP vendor class identifier: %s");
- return FALSE;
- }
- }
-
- r = sd_dhcp_client_set_callback(sd_client, dhcp_event_cb, client);
- if (r < 0) {
- nm_utils_error_set_errno(error, r, "failed to set callback: %s");
- return FALSE;
- }
-
- priv->client4 = g_steal_pointer(&sd_client);
-
- g_free(priv->lease_file);
- priv->lease_file = g_steal_pointer(&lease_file);
-
- nm_dhcp_client_set_effective_client_id(client, client_id);
-
- r = sd_dhcp_client_start(priv->client4);
- if (r < 0) {
- sd_dhcp_client_set_callback(priv->client4, NULL, NULL);
- nm_clear_pointer(&priv->client4, sd_dhcp_client_unref);
- nm_utils_error_set_errno(error, r, "failed to start DHCP client: %s");
- return FALSE;
- }
-
- return TRUE;
-}
-
-static NML3ConfigData *
lease_to_ip6_config(NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
@@ -952,7 +281,6 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
GBytes *duid;
gboolean prefix_delegation;
- g_return_val_if_fail(!priv->client4, FALSE);
g_return_val_if_fail(!priv->client6, FALSE);
client_config = nm_dhcp_client_get_config(client);
@@ -1079,18 +407,13 @@ stop(NMDhcpClient *client, gboolean release)
NM_DHCP_CLIENT_CLASS(nm_dhcp_systemd_parent_class)->stop(client, release);
- _LOGT("dhcp-client%d: stop %p",
- priv->client4 ? '4' : '6',
- priv->client4 ? (gpointer) priv->client4 : (gpointer) priv->client6);
+ _LOGT("dhcp-client6: stop");
- if (priv->client4) {
- sd_dhcp_client_set_callback(priv->client4, NULL, NULL);
- r = sd_dhcp_client_stop(priv->client4);
- } else if (priv->client6) {
- sd_dhcp6_client_set_callback(priv->client6, NULL, NULL);
- r = sd_dhcp6_client_stop(priv->client6);
- }
+ if (!priv->client6)
+ return;
+ sd_dhcp6_client_set_callback(priv->client6, NULL, NULL);
+ r = sd_dhcp6_client_stop(priv->client6);
if (r)
_LOGW("failed to stop client (%d)", r);
}
@@ -1108,12 +431,6 @@ dispose(GObject *object)
nm_clear_g_free(&priv->lease_file);
- if (priv->client4) {
- sd_dhcp_client_stop(priv->client4);
- sd_dhcp_client_unref(priv->client4);
- priv->client4 = NULL;
- }
-
if (priv->client6) {
sd_dhcp6_client_stop(priv->client6);
sd_dhcp6_client_unref(priv->client6);
@@ -1131,14 +448,13 @@ nm_dhcp_systemd_class_init(NMDhcpSystemdClass *sdhcp_class)
object_class->dispose = dispose;
- client_class->ip4_start = ip4_start;
client_class->ip6_start = ip6_start;
client_class->stop = stop;
}
const NMDhcpClientFactory _nm_dhcp_client_factory_systemd = {
.name = "systemd",
- .get_type_4 = nm_dhcp_systemd_get_type,
+ .get_type_4 = nm_dhcp_nettools_get_type,
.get_type_6 = nm_dhcp_systemd_get_type,
.undocumented = TRUE,
};
diff --git a/src/core/dhcp/nm-dhcp-utils.c b/src/core/dhcp/nm-dhcp-utils.c
index 081e284196..3ae7e6b71c 100644
--- a/src/core/dhcp/nm-dhcp-utils.c
+++ b/src/core/dhcp/nm-dhcp-utils.c
@@ -295,7 +295,7 @@ process_classful_routes(const char *iface,
return;
if ((NM_PTRARRAY_LEN(searches) % 2) != 0) {
- _LOG2I(LOGD_DHCP, iface, " static routes provided, but invalid");
+ _LOG2I(LOGD_DHCP4, iface, " static routes provided, but invalid");
return;
}
@@ -305,11 +305,11 @@ process_classful_routes(const char *iface,
guint32 rt_addr, rt_route;
if (inet_pton(AF_INET, *s, &rt_addr) <= 0) {
- _LOG2W(LOGD_DHCP, iface, "DHCP provided invalid static route address: '%s'", *s);
+ _LOG2W(LOGD_DHCP4, iface, "DHCP provided invalid static route address: '%s'", *s);
continue;
}
if (inet_pton(AF_INET, *(s + 1), &rt_route) <= 0) {
- _LOG2W(LOGD_DHCP, iface, "DHCP provided invalid static route gateway: '%s'", *(s + 1));
+ _LOG2W(LOGD_DHCP4, iface, "DHCP provided invalid static route gateway: '%s'", *(s + 1));
continue;
}
@@ -340,7 +340,7 @@ process_classful_routes(const char *iface,
nm_l3_config_data_add_route_4(l3cd, &route);
- _LOG2I(LOGD_DHCP,
+ _LOG2I(LOGD_DHCP4,
iface,
" static route %s",
nm_platform_ip4_route_to_string(&route, sbuf, sizeof(sbuf)));
@@ -352,6 +352,7 @@ process_domain_search(int addr_family, const char *iface, const char *str, NML3C
{
gs_free const char **searches = NULL;
gs_free char *unescaped = NULL;
+ NMLogDomain logd = NM_IS_IPv4(addr_family) ? LOGD_DHCP4 : LOGD_DHCP6;
const char **s;
char *p;
int i;
@@ -373,13 +374,13 @@ process_domain_search(int addr_family, const char *iface, const char *str, NML3C
} while (*p++);
if (strchr(unescaped, '\\')) {
- _LOG2W(LOGD_DHCP, iface, " invalid domain search: '%s'", unescaped);
+ _LOG2W(logd, iface, " invalid domain search: '%s'", unescaped);
return;
}
searches = nm_strsplit_set(unescaped, " ");
for (s = searches; searches && *s; s++) {
- _LOG2I(LOGD_DHCP, iface, " domain search '%s'", *s);
+ _LOG2I(logd, iface, " domain search '%s'", *s);
nm_l3_config_data_add_search(l3cd, addr_family, *s);
}
}
@@ -822,26 +823,6 @@ nm_dhcp_utils_get_leasefile_path(int addr_family,
return FALSE;
}
-char *
-nm_dhcp_utils_get_dhcp6_event_id(GHashTable *lease)
-{
- const char *start;
- const char *iaid;
-
- if (!lease)
- return NULL;
-
- iaid = g_hash_table_lookup(lease, "iaid");
- if (!iaid)
- return NULL;
-
- start = g_hash_table_lookup(lease, "life_starts");
- if (!start)
- return NULL;
-
- return g_strdup_printf("%s|%s", iaid, start);
-}
-
gboolean
nm_dhcp_utils_merge_new_dhcp6_lease(const NML3ConfigData *l3cd_old,
const NML3ConfigData *l3cd_new,
diff --git a/src/core/dns/nm-dns-dnsmasq.c b/src/core/dns/nm-dns-dnsmasq.c
index 43426882ed..7d0f0490e0 100644
--- a/src/core/dns/nm-dns-dnsmasq.c
+++ b/src/core/dns/nm-dns-dnsmasq.c
@@ -678,19 +678,23 @@ typedef struct {
char *name_owner;
+ GSource *main_timeout_source;
+ GSource *burst_retry_timeout_source;
+
gint64 burst_start_at;
GPid process_pid;
guint name_owner_changed_id;
- guint main_timeout_id;
-
- guint burst_retry_timeout_id;
guint8 burst_count;
bool is_stopped : 1;
+ bool set_server_ex_args_dirty : 1;
+
+ bool update_pending : 1;
+
} NMDnsDnsmasqPrivate;
struct _NMDnsDnsmasq {
@@ -704,7 +708,8 @@ struct _NMDnsDnsmasqClass {
G_DEFINE_TYPE(NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN)
-#define NM_DNS_DNSMASQ_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDnsDnsmasq, NM_IS_DNS_DNSMASQ)
+#define NM_DNS_DNSMASQ_GET_PRIVATE(self) \
+ _NM_GET_PRIVATE(self, NMDnsDnsmasq, NM_IS_DNS_DNSMASQ, NMDnsPlugin)
/*****************************************************************************/
@@ -717,6 +722,55 @@ static gboolean start_dnsmasq(NMDnsDnsmasq *self, gboolean force_start, GError *
/*****************************************************************************/
+static gboolean
+_update_pending_detect(NMDnsDnsmasq *self)
+{
+ NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self);
+
+ if (priv->is_stopped)
+ return FALSE;
+ if (priv->main_timeout_source) {
+ /* we are waiting for dnsmasq to start. */
+ return TRUE;
+ }
+ if (priv->update_cancellable) {
+ /* An update is in progress. Busy. */
+ return TRUE;
+ }
+ if (priv->set_server_ex_args_dirty) {
+ /* the args just changed and were not yet sent. Busy. */
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+_update_pending_maybe_changed(NMDnsDnsmasq *self)
+{
+ NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self);
+ gboolean update_pending;
+
+ update_pending = _update_pending_detect(self);
+ if (priv->update_pending == update_pending)
+ return;
+
+ priv->update_pending = update_pending;
+ _nm_dns_plugin_update_pending_maybe_changed(NM_DNS_PLUGIN(self));
+}
+
+static gboolean
+get_update_pending(NMDnsPlugin *plugin)
+{
+ NMDnsDnsmasq *self = NM_DNS_DNSMASQ(plugin);
+ NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self);
+
+ nm_assert(priv->update_pending == _update_pending_detect(self));
+ return priv->update_pending;
+}
+
+/*****************************************************************************/
+
static void
add_dnsmasq_nameserver(NMDnsDnsmasq *self,
GVariantBuilder *servers,
@@ -871,6 +925,7 @@ static void
dnsmasq_update_done(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
NMDnsDnsmasq *self;
+ NMDnsDnsmasqPrivate *priv;
gs_free_error GError *error = NULL;
gs_unref_variant GVariant *response = NULL;
@@ -880,10 +935,16 @@ dnsmasq_update_done(GObject *source_object, GAsyncResult *res, gpointer user_dat
return;
self = user_data;
+ priv = NM_DNS_DNSMASQ_GET_PRIVATE(self);
+
+ nm_clear_g_cancellable(&priv->update_cancellable);
+
if (!response)
_LOGW("dnsmasq update failed: %s", error->message);
else
_LOGD("dnsmasq update successful");
+
+ _update_pending_maybe_changed(self);
}
static void
@@ -899,6 +960,8 @@ send_dnsmasq_update(NMDnsDnsmasq *self)
nm_clear_g_cancellable(&priv->update_cancellable);
priv->update_cancellable = g_cancellable_new();
+ priv->set_server_ex_args_dirty = FALSE;
+
g_dbus_connection_call(priv->dbus_connection,
priv->name_owner,
DNSMASQ_DBUS_PATH,
@@ -911,6 +974,8 @@ send_dnsmasq_update(NMDnsDnsmasq *self)
priv->update_cancellable,
dnsmasq_update_done,
self);
+
+ _update_pending_maybe_changed(self);
}
/*****************************************************************************/
@@ -928,17 +993,19 @@ _main_cleanup(NMDnsDnsmasq *self, gboolean emit_failed)
nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id);
- nm_clear_g_source(&priv->main_timeout_id);
+ nm_clear_g_source_inst(&priv->main_timeout_source);
nm_clear_g_cancellable(&priv->update_cancellable);
/* cancelling the main_cancellable will also cause _gl_pid_spawn*() to terminate the
* process in the background. */
nm_clear_g_cancellable(&priv->main_cancellable);
- if (!priv->is_stopped && priv->burst_retry_timeout_id == 0) {
+ if (!priv->is_stopped && !priv->burst_retry_timeout_source) {
start_dnsmasq(self, FALSE, NULL);
send_dnsmasq_update(self);
}
+
+ _update_pending_maybe_changed(self);
}
static void
@@ -961,8 +1028,10 @@ name_owner_changed(NMDnsDnsmasq *self, const char *name_owner)
}
_LOGT("D-Bus name for dnsmasq got owner %s", name_owner);
- nm_clear_g_source(&priv->main_timeout_id);
+ nm_clear_g_source_inst(&priv->main_timeout_source);
send_dnsmasq_update(self);
+
+ _update_pending_maybe_changed(self);
}
static void
@@ -1047,11 +1116,11 @@ _burst_retry_timeout_cb(gpointer user_data)
NMDnsDnsmasq *self = user_data;
NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self);
- priv->burst_retry_timeout_id = 0;
+ nm_clear_g_source_inst(&priv->burst_retry_timeout_source);
start_dnsmasq(self, TRUE, NULL);
send_dnsmasq_update(self);
- return G_SOURCE_REMOVE;
+ return G_SOURCE_CONTINUE;
}
static gboolean
@@ -1090,33 +1159,35 @@ start_dnsmasq(NMDnsDnsmasq *self, gboolean force_start, GError **error)
|| priv->burst_start_at + RATELIMIT_INTERVAL_MSEC <= now) {
priv->burst_start_at = now;
priv->burst_count = 1;
- nm_clear_g_source(&priv->burst_retry_timeout_id);
+ nm_clear_g_source_inst(&priv->burst_retry_timeout_source);
_LOGT("rate-limit: start burst interval of %d seconds %s",
RATELIMIT_INTERVAL_MSEC / 1000,
force_start ? " (force)" : "");
} else if (priv->burst_count < RATELIMIT_BURST) {
- nm_assert(priv->burst_retry_timeout_id == 0);
+ nm_assert(!priv->burst_retry_timeout_source);
priv->burst_count++;
_LOGT("rate-limit: %u try within burst interval of %d seconds",
(guint) priv->burst_count,
RATELIMIT_INTERVAL_MSEC / 1000);
} else {
- if (priv->burst_retry_timeout_id == 0) {
+ if (!priv->burst_retry_timeout_source) {
_LOGW("dnsmasq dies and gets respawned too quickly. Back off. Something is very wrong");
- priv->burst_retry_timeout_id =
- g_timeout_add_seconds((2 * RATELIMIT_INTERVAL_MSEC) / 1000,
- _burst_retry_timeout_cb,
- self);
+ priv->burst_retry_timeout_source =
+ nm_g_timeout_add_seconds_source((2 * RATELIMIT_INTERVAL_MSEC) / 1000,
+ _burst_retry_timeout_cb,
+ self);
} else
_LOGT("rate-limit: currently rate-limited from restart");
return TRUE;
}
- priv->main_timeout_id = g_timeout_add(10000, spawn_timeout_cb, self);
+ priv->main_timeout_source = nm_g_timeout_add_source(10000, spawn_timeout_cb, self);
priv->main_cancellable = g_cancellable_new();
_gl_pid_spawn(dm_binary, priv->main_cancellable, spawn_notify, self);
+
+ _update_pending_maybe_changed(self);
return TRUE;
}
@@ -1136,8 +1207,11 @@ update(NMDnsPlugin *plugin,
nm_clear_pointer(&priv->set_server_ex_args, g_variant_unref);
priv->set_server_ex_args =
g_variant_ref_sink(create_update_args(self, global_config, ip_data_lst_head, hostdomain));
+ priv->set_server_ex_args_dirty = TRUE;
send_dnsmasq_update(self);
+
+ _update_pending_maybe_changed(self);
return TRUE;
}
@@ -1151,11 +1225,13 @@ stop(NMDnsPlugin *plugin)
priv->is_stopped = TRUE;
priv->burst_start_at = 0;
- nm_clear_g_source(&priv->burst_retry_timeout_id);
+ nm_clear_g_source_inst(&priv->burst_retry_timeout_source);
/* Cancelling the cancellable will also terminate the
* process (in the background). */
_main_cleanup(self, FALSE);
+
+ _update_pending_maybe_changed(self);
}
/*****************************************************************************/
@@ -1178,7 +1254,7 @@ dispose(GObject *object)
priv->is_stopped = TRUE;
- nm_clear_g_source(&priv->burst_retry_timeout_id);
+ nm_clear_g_source_inst(&priv->burst_retry_timeout_source);
_main_cleanup(self, FALSE);
@@ -1197,8 +1273,9 @@ nm_dns_dnsmasq_class_init(NMDnsDnsmasqClass *dns_class)
object_class->dispose = dispose;
- plugin_class->plugin_name = "dnsmasq";
- plugin_class->is_caching = TRUE;
- plugin_class->stop = stop;
- plugin_class->update = update;
+ plugin_class->plugin_name = "dnsmasq";
+ plugin_class->is_caching = TRUE;
+ plugin_class->stop = stop;
+ plugin_class->update = update;
+ plugin_class->get_update_pending = get_update_pending;
}
diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c
index 566f3d6626..1e54452aa4 100644
--- a/src/core/dns/nm-dns-manager.c
+++ b/src/core/dns/nm-dns-manager.c
@@ -26,7 +26,6 @@
#include "libnm-core-intern/nm-core-internal.h"
#include "libnm-glib-aux/nm-str-buf.h"
-#include "libnm-systemd-shared/nm-sd-utils-shared.h"
#include "NetworkManagerUtils.h"
#include "devices/nm-device.h"
@@ -35,7 +34,6 @@
#include "nm-dns-dnsmasq.h"
#include "nm-dns-plugin.h"
#include "nm-dns-systemd-resolved.h"
-#include "nm-dns-unbound.h"
#include "nm-ip-config.h"
#include "nm-l3-config-data.h"
#include "nm-manager.h"
@@ -57,6 +55,8 @@
#define HAS_NETCONFIG 1
#endif
+#define UPDATE_PENDING_UNBLOCK_TIMEOUT_MSEC 5000
+
/*****************************************************************************/
typedef enum { SR_SUCCESS, SR_NOTFOUND, SR_ERROR } SpawnResult;
@@ -78,7 +78,11 @@ enum {
LAST_SIGNAL
};
-NM_GOBJECT_PROPERTIES_DEFINE(NMDnsManager, PROP_MODE, PROP_RC_MANAGER, PROP_CONFIGURATION, );
+NM_GOBJECT_PROPERTIES_DEFINE(NMDnsManager,
+ PROP_MODE,
+ PROP_RC_MANAGER,
+ PROP_CONFIGURATION,
+ PROP_UPDATE_PENDING, );
static guint signals[LAST_SIGNAL] = {0};
@@ -89,6 +93,11 @@ typedef struct {
CList ip_data_lst_head;
GVariant *config_variant;
+ /* A DNS plugin should not be marked as pending indefinitely.
+ * We are only blocked if "update_pending" is TRUE and we have
+ * "update_pending_unblock" timer ticking. */
+ GSource *update_pending_unblock;
+
bool ip_data_lst_need_sort : 1;
bool configs_lst_need_sort : 1;
@@ -98,6 +107,8 @@ typedef struct {
bool config_changed : 1;
+ bool update_pending : 1;
+
char *hostdomain;
guint updates_queue;
@@ -109,6 +120,9 @@ typedef struct {
NMDnsPlugin *sd_resolve_plugin;
NMDnsPlugin *plugin;
+ gulong update_changed_signal_id_sd;
+ gulong update_changed_signal_id;
+
NMConfig *config;
struct {
@@ -137,28 +151,23 @@ NM_DEFINE_SINGLETON_GETTER(NMDnsManager, nm_dns_manager_get, NM_TYPE_DNS_MANAGER
#define _NMLOG_PREFIX_NAME "dns-mgr"
#define _NMLOG_DOMAIN LOGD_DNS
-#define _NMLOG(level, ...) \
- G_STMT_START \
- { \
- const NMLogLevel __level = (level); \
- \
- if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \
- char __prefix[20]; \
- const NMDnsManager *const __self = (self); \
- \
- _nm_log(__level, \
- _NMLOG_DOMAIN, \
- 0, \
- NULL, \
- NULL, \
- "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
- _NMLOG_PREFIX_NAME, \
- ((!__self || __self == singleton_instance) \
- ? "" \
- : nm_sprintf_buf(__prefix, "[%p]", __self)) \
- _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
- } \
- } \
+#define _NMLOG(level, ...) \
+ G_STMT_START \
+ { \
+ const NMLogLevel __level = (level); \
+ \
+ if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \
+ _nm_unused const NMDnsManager *const __self = (self); \
+ \
+ _nm_log(__level, \
+ _NMLOG_DOMAIN, \
+ 0, \
+ NULL, \
+ NULL, \
+ "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+ _NMLOG_PREFIX_NAME _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+ } \
+ } \
G_STMT_END
/*****************************************************************************/
@@ -207,6 +216,85 @@ static NM_UTILS_LOOKUP_STR_DEFINE(
/*****************************************************************************/
+static gboolean
+_update_pending_detect(NMDnsManager *self)
+{
+ NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self);
+
+ if (priv->plugin && nm_dns_plugin_get_update_pending(priv->plugin))
+ return TRUE;
+ if (priv->sd_resolve_plugin && nm_dns_plugin_get_update_pending(priv->sd_resolve_plugin))
+ return TRUE;
+ return FALSE;
+}
+
+static gboolean
+_update_pending_unblock_cb(gpointer user_data)
+{
+ NMDnsManager *self = user_data;
+ NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self);
+
+ nm_assert(priv->update_pending);
+ nm_assert(priv->update_pending_unblock);
+ nm_assert(_update_pending_detect(self));
+
+ nm_clear_g_source_inst(&priv->update_pending_unblock);
+
+ _LOGW(
+ "update-pending changed: DNS plugin did not become ready again. Assume something is wrong");
+
+ _notify(self, PROP_UPDATE_PENDING);
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+_update_pending_maybe_changed(NMDnsManager *self)
+{
+ NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self);
+ gboolean update_pending;
+
+ update_pending = _update_pending_detect(self);
+ if (priv->update_pending == update_pending)
+ return;
+
+ if (update_pending) {
+ nm_assert(!priv->update_pending_unblock);
+ priv->update_pending_unblock = nm_g_timeout_add_source(UPDATE_PENDING_UNBLOCK_TIMEOUT_MSEC,
+ _update_pending_unblock_cb,
+ self);
+ } else
+ nm_clear_g_source_inst(&priv->update_pending_unblock);
+
+ priv->update_pending = update_pending;
+ _LOGD("update-pending changed: %spending", update_pending ? "" : "not ");
+ _notify(self, PROP_UPDATE_PENDING);
+}
+
+static void
+_update_pending_changed_cb(NMDnsPlugin *plugin, gboolean update_pending, NMDnsManager *self)
+{
+ _update_pending_maybe_changed(self);
+}
+
+gboolean
+nm_dns_manager_get_update_pending(NMDnsManager *self)
+{
+ NMDnsManagerPrivate *priv;
+
+ g_return_val_if_fail(NM_IS_DNS_MANAGER(self), FALSE);
+
+ priv = NM_DNS_MANAGER_GET_PRIVATE(self);
+ nm_assert(priv->update_pending == _update_pending_detect(self));
+ nm_assert(priv->update_pending || !priv->update_pending_unblock);
+
+ /* update-pending can only be TRUE for a certain time (before we assume
+ * something is really wrong with the plugin). That is, as long as
+ * update_pending_unblock is ticking. */
+ return !!priv->update_pending_unblock;
+}
+
+/*****************************************************************************/
+
static int
_dns_config_ip_data_get_dns_priority1(const NML3ConfigData *l3cd, int addr_family)
{
@@ -2015,7 +2103,7 @@ nm_dns_manager_set_hostname(NMDnsManager *self, const char *hostname, gboolean s
domain = hostname;
}
- if (!nm_sd_hostname_is_valid(domain, FALSE))
+ if (!nm_hostname_is_valid(domain, FALSE))
domain = NULL;
}
}
@@ -2120,6 +2208,7 @@ _clear_plugin(NMDnsManager *self)
nm_clear_g_source(&priv->plugin_ratelimit.timer);
if (priv->plugin) {
+ nm_clear_g_signal_handler(priv->plugin, &priv->update_changed_signal_id);
nm_dns_plugin_stop(priv->plugin);
g_clear_object(&priv->plugin);
return TRUE;
@@ -2127,6 +2216,20 @@ _clear_plugin(NMDnsManager *self)
return FALSE;
}
+static gboolean
+_clear_sd_resolved_plugin(NMDnsManager *self)
+{
+ NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self);
+
+ if (priv->sd_resolve_plugin) {
+ nm_clear_g_signal_handler(priv->sd_resolve_plugin, &priv->update_changed_signal_id_sd);
+ nm_dns_plugin_stop(priv->sd_resolve_plugin);
+ g_clear_object(&priv->sd_resolve_plugin);
+ return TRUE;
+ }
+ return FALSE;
+}
+
static NMDnsManagerResolvConfManager
_check_resconf_immutable(NMDnsManagerResolvConfManager rc_manager)
{
@@ -2313,16 +2416,14 @@ again:
priv->plugin = nm_dns_dnsmasq_new();
plugin_changed = TRUE;
}
- } else if (nm_streq0(mode, "unbound")) {
- if (force_reload_plugin || !NM_IS_DNS_UNBOUND(priv->plugin)) {
- _clear_plugin(self);
- priv->plugin = nm_dns_unbound_new();
- plugin_changed = TRUE;
- }
} else {
if (!NM_IN_STRSET(mode, "none", "default")) {
- if (mode)
- _LOGW("init: unknown dns mode '%s'", mode);
+ if (mode) {
+ if (nm_streq(mode, "unbound"))
+ _LOGW("init: ns mode 'unbound' was removed. Update your configuration");
+ else
+ _LOGW("init: unknown dns mode '%s'", mode);
+ }
mode = "default";
}
if (_clear_plugin(self))
@@ -2359,7 +2460,7 @@ again:
priv->sd_resolve_plugin = nm_dns_systemd_resolved_new();
systemd_resolved_changed = TRUE;
}
- } else if (nm_clear_g_object(&priv->sd_resolve_plugin))
+ } else if (_clear_sd_resolved_plugin(self))
systemd_resolved_changed = TRUE;
g_object_freeze_notify(G_OBJECT(self));
@@ -2390,6 +2491,23 @@ again:
""));
}
+ if (plugin_changed && priv->plugin && priv->update_changed_signal_id == 0) {
+ priv->update_changed_signal_id = g_signal_connect(priv->plugin,
+ NM_DNS_PLUGIN_UPDATE_PENDING_CHANGED,
+ G_CALLBACK(_update_pending_changed_cb),
+ self);
+ }
+
+ if (systemd_resolved_changed && priv->sd_resolve_plugin
+ && priv->update_changed_signal_id_sd == 0) {
+ priv->update_changed_signal_id_sd = g_signal_connect(priv->sd_resolve_plugin,
+ NM_DNS_PLUGIN_UPDATE_PENDING_CHANGED,
+ G_CALLBACK(_update_pending_changed_cb),
+ self);
+ }
+
+ _update_pending_maybe_changed(self);
+
g_object_thaw_notify(G_OBJECT(self));
}
@@ -2594,6 +2712,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
case PROP_CONFIGURATION:
g_value_set_variant(value, _get_config_variant(self));
break;
+ case PROP_UPDATE_PENDING:
+ g_value_set_boolean(value, nm_dns_manager_get_update_pending(self));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
@@ -2641,9 +2762,11 @@ dispose(GObject *object)
if (priv->config)
g_signal_handlers_disconnect_by_func(priv->config, config_changed_cb, self);
- g_clear_object(&priv->sd_resolve_plugin);
+ _clear_sd_resolved_plugin(self);
_clear_plugin(self);
+ nm_clear_g_source_inst(&priv->update_pending_unblock);
+
c_list_for_each_entry_safe (ip_data, ip_data_safe, &priv->ip_data_lst_head, ip_data_lst)
_dns_config_ip_data_free(ip_data);
@@ -2719,6 +2842,13 @@ nm_dns_manager_class_init(NMDnsManagerClass *klass)
NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ obj_properties[PROP_UPDATE_PENDING] =
+ g_param_spec_boolean(NM_DNS_MANAGER_UPDATE_PENDING,
+ "",
+ "",
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
signals[CONFIG_CHANGED] = g_signal_new(NM_DNS_MANAGER_CONFIG_CHANGED,
diff --git a/src/core/dns/nm-dns-manager.h b/src/core/dns/nm-dns-manager.h
index c30d4b3ac6..210f9f6cb3 100644
--- a/src/core/dns/nm-dns-manager.h
+++ b/src/core/dns/nm-dns-manager.h
@@ -80,9 +80,10 @@ typedef struct _NMDnsConfigData {
(G_TYPE_INSTANCE_GET_CLASS((o), NM_TYPE_DNS_MANAGER, NMDnsManagerClass))
/* properties */
-#define NM_DNS_MANAGER_MODE "mode"
-#define NM_DNS_MANAGER_RC_MANAGER "rc-manager"
-#define NM_DNS_MANAGER_CONFIGURATION "configuration"
+#define NM_DNS_MANAGER_MODE "mode"
+#define NM_DNS_MANAGER_RC_MANAGER "rc-manager"
+#define NM_DNS_MANAGER_CONFIGURATION "configuration"
+#define NM_DNS_MANAGER_UPDATE_PENDING "update-pending"
/* internal signals */
#define NM_DNS_MANAGER_CONFIG_CHANGED "config-changed"
@@ -149,6 +150,8 @@ void nm_dns_manager_stop(NMDnsManager *self);
NMDnsPlugin *nm_dns_manager_get_systemd_resolved(NMDnsManager *self);
+gboolean nm_dns_manager_get_update_pending(NMDnsManager *self);
+
/*****************************************************************************/
char *nmtst_dns_create_resolv_conf(const char *const *searches,
diff --git a/src/core/dns/nm-dns-plugin.c b/src/core/dns/nm-dns-plugin.c
index 847d783996..41a0dbc138 100644
--- a/src/core/dns/nm-dns-plugin.c
+++ b/src/core/dns/nm-dns-plugin.c
@@ -17,11 +17,16 @@
/*****************************************************************************/
+enum {
+ UPDATE_PENDING_CHANGED,
+ LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
typedef struct _NMDnsPluginPrivate {
- GPid pid;
- guint watch_id;
- char *progname;
- char *pidfile;
+ bool update_pending_inited : 1;
+ bool update_pending : 1;
} NMDnsPluginPrivate;
G_DEFINE_ABSTRACT_TYPE(NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT)
@@ -32,26 +37,29 @@ G_DEFINE_ABSTRACT_TYPE(NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT)
#define _NMLOG_PREFIX_NAME "dns-plugin"
#define _NMLOG_DOMAIN LOGD_DNS
-#define _NMLOG(level, ...) \
- G_STMT_START \
- { \
- const NMLogLevel __level = (level); \
- \
- if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \
- char __prefix[20]; \
- const NMDnsPlugin *const __self = (self); \
- \
- _nm_log(__level, \
- _NMLOG_DOMAIN, \
- 0, \
- NULL, \
- NULL, \
- "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
- _NMLOG_PREFIX_NAME, \
- (!__self ? "" : nm_sprintf_buf(__prefix, "[%p]", __self)) \
- _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
- } \
- } \
+#define _NMLOG(level, ...) \
+ G_STMT_START \
+ { \
+ const NMLogLevel __level = (level); \
+ \
+ if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \
+ char __prefix[20]; \
+ const NMDnsPlugin *const __self = (self); \
+ \
+ _nm_log(__level, \
+ _NMLOG_DOMAIN, \
+ 0, \
+ NULL, \
+ NULL, \
+ "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
+ _NMLOG_PREFIX_NAME, \
+ (!__self ? "" \
+ : nm_sprintf_buf(__prefix, \
+ "[" NM_HASH_OBFUSCATE_PTR_FMT "]", \
+ NM_HASH_OBFUSCATE_PTR( \
+ __self))) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
+ } \
+ } \
G_STMT_END
/*****************************************************************************/
@@ -104,10 +112,109 @@ nm_dns_plugin_stop(NMDnsPlugin *self)
/*****************************************************************************/
+static gboolean
+_get_update_pending(NMDnsPlugin *self)
+{
+ NMDnsPluginClass *klass;
+
+ nm_assert(NM_IS_DNS_PLUGIN(self));
+
+ klass = NM_DNS_PLUGIN_GET_CLASS(self);
+ if (klass->get_update_pending) {
+ if (klass->get_update_pending(self))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+gboolean
+nm_dns_plugin_get_update_pending(NMDnsPlugin *self)
+{
+ NMDnsPluginPrivate *priv;
+
+ g_return_val_if_fail(NM_IS_DNS_PLUGIN(self), FALSE);
+
+ priv = NM_DNS_PLUGIN_GET_PRIVATE(self);
+
+ /* We cache the boolean and rely on the subclass to call
+ * _nm_dns_plugin_update_pending_maybe_changed(). The subclass
+ * anyway must get it right to notify us when the value (maybe)
+ * changes. By caching the value, the subclass is free to notify
+ * even if the value did not actually change.
+ *
+ * Also, this allows the base implementation to combine multiple
+ * sources/reasons (if we need that in the future). */
+
+ if (!priv->update_pending_inited) {
+ priv->update_pending_inited = TRUE;
+ priv->update_pending = _get_update_pending(self);
+ _LOGD("[%s] update-pending changed (%spending)",
+ nm_dns_plugin_get_name(self),
+ priv->update_pending ? "" : "not ");
+ } else
+ nm_assert(priv->update_pending == _get_update_pending(self));
+
+ return priv->update_pending;
+}
+
+void
+_nm_dns_plugin_update_pending_maybe_changed(NMDnsPlugin *self)
+{
+ NMDnsPluginPrivate *priv;
+ gboolean v;
+
+ g_return_if_fail(NM_IS_DNS_PLUGIN(self));
+
+ priv = NM_DNS_PLUGIN_GET_PRIVATE(self);
+
+ v = _get_update_pending(self);
+
+ if (!priv->update_pending_inited)
+ priv->update_pending_inited = TRUE;
+ else if (priv->update_pending == v)
+ return;
+
+ priv->update_pending = v;
+
+ _LOGD("[%s] update-pending changed (%spending)",
+ nm_dns_plugin_get_name(self),
+ priv->update_pending ? "" : "not ");
+
+ g_signal_emit(self, signals[UPDATE_PENDING_CHANGED], 0, (gboolean) priv->update_pending);
+}
+
+/*****************************************************************************/
+
static void
nm_dns_plugin_init(NMDnsPlugin *self)
-{}
+{
+ NMDnsPluginPrivate *priv;
+
+ priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_DNS_PLUGIN, NMDnsPluginPrivate);
+
+ self->_priv = priv;
+
+ nm_assert(priv->update_pending_inited == FALSE);
+ nm_assert(priv->update_pending == FALSE);
+
+ nm_shutdown_wait_obj_register_object(self, "dns-plugin");
+}
static void
-nm_dns_plugin_class_init(NMDnsPluginClass *plugin_class)
-{}
+nm_dns_plugin_class_init(NMDnsPluginClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ g_type_class_add_private(object_class, sizeof(NMDnsPluginPrivate));
+
+ signals[UPDATE_PENDING_CHANGED] = g_signal_new(NM_DNS_PLUGIN_UPDATE_PENDING_CHANGED,
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+}
diff --git a/src/core/dns/nm-dns-plugin.h b/src/core/dns/nm-dns-plugin.h
index f9c424abfa..24d6083be1 100644
--- a/src/core/dns/nm-dns-plugin.h
+++ b/src/core/dns/nm-dns-plugin.h
@@ -19,8 +19,13 @@
#define NM_DNS_PLUGIN_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DNS_PLUGIN, NMDnsPluginClass))
+#define NM_DNS_PLUGIN_UPDATE_PENDING_CHANGED "update-pending-changed"
+
+struct _NMDnsPluginPrivate;
+
typedef struct {
- GObject parent;
+ GObject parent;
+ struct _NMDnsPluginPrivate *_priv;
} NMDnsPlugin;
typedef struct {
@@ -39,6 +44,8 @@ typedef struct {
void (*stop)(NMDnsPlugin *self);
+ gboolean (*get_update_pending)(NMDnsPlugin *self);
+
const char *plugin_name;
/* Types should set to TRUE if they start a local caching nameserver
@@ -63,4 +70,8 @@ gboolean nm_dns_plugin_update(NMDnsPlugin *self,
void nm_dns_plugin_stop(NMDnsPlugin *self);
+gboolean nm_dns_plugin_get_update_pending(NMDnsPlugin *self);
+
+void _nm_dns_plugin_update_pending_maybe_changed(NMDnsPlugin *self);
+
#endif /* __NM_DNS_PLUGIN_H__ */
diff --git a/src/core/dns/nm-dns-systemd-resolved.c b/src/core/dns/nm-dns-systemd-resolved.c
index c4993884d2..ac6fe5dedb 100644
--- a/src/core/dns/nm-dns-systemd-resolved.c
+++ b/src/core/dns/nm-dns-systemd-resolved.c
@@ -40,8 +40,8 @@ static const char *const DBUS_OP_SET_LINK_DNS_OVER_TLS = "SetLinkDNSOverTLS";
/*****************************************************************************/
typedef struct {
- int ifindex;
- CList configs_lst_head;
+ int ifindex;
+ GPtrArray *ip_data_list;
} InterfaceConfig;
typedef struct {
@@ -50,6 +50,7 @@ typedef struct {
GVariant *argument;
NMDnsSystemdResolved *self;
int ifindex;
+ int ref_count;
} RequestItem;
struct _NMDnsSystemdResolvedResolveHandle {
@@ -82,10 +83,13 @@ typedef struct {
char *dbus_owner;
CList handle_lst_head;
guint name_owner_changed_id;
+ guint n_pending;
bool send_updates_warn_ratelimited : 1;
bool try_start_blocked : 1;
+ bool stopped : 1;
bool dbus_initied : 1;
bool send_updates_waiting : 1;
+ bool update_pending : 1;
/* These two variables ensure that the log is not spammed with
* API (not) supported messages.
* They can be removed when no distro uses systemd-resolved < v240 anymore
@@ -106,7 +110,7 @@ struct _NMDnsSystemdResolvedClass {
G_DEFINE_TYPE(NMDnsSystemdResolved, nm_dns_systemd_resolved, NM_TYPE_DNS_PLUGIN)
#define NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self) \
- _NM_GET_PRIVATE(self, NMDnsSystemdResolved, NM_IS_DNS_SYSTEMD_RESOLVED)
+ _NM_GET_PRIVATE(self, NMDnsSystemdResolved, NM_IS_DNS_SYSTEMD_RESOLVED, NMDnsPlugin)
/*****************************************************************************/
@@ -146,10 +150,88 @@ static void _resolve_start(NMDnsSystemdResolved *self, NMDnsSystemdResolvedResol
/*****************************************************************************/
+static gboolean
+_update_pending_detect(NMDnsSystemdResolved *self)
+{
+ NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+
+ if (priv->n_pending > 0) {
+ /* we have pending calls. We definitely want to wait for them to complete. */
+ return TRUE;
+ }
+ if (!priv->dbus_initied) {
+ if (!priv->dbus_connection)
+ return FALSE;
+ /* D-Bus not yet initialized (and we don't know the name owner yet). Pending. */
+ return TRUE;
+ }
+ if (priv->try_start_timeout_source) {
+ /* We are waiting to D-Bus activate resolved. Pending. */
+ return TRUE;
+ }
+ if (priv->try_start_blocked) {
+ /* We earlier tried to start resolved, but are rate limited. We are not pending an update
+ * (that we expect to complete any time soon). */
+ return FALSE;
+ }
+ if (priv->send_updates_waiting) {
+ /* we wait to send updates. We are pending. */
+ return TRUE;
+ }
+ return FALSE;
+}
+
static void
-_request_item_free(RequestItem *request_item)
+_update_pending_maybe_changed(NMDnsSystemdResolved *self)
{
- c_list_unlink_stale(&request_item->request_queue_lst);
+ NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+ gboolean update_pending;
+
+ /* Important: we need to make sure that we call _update_pending_maybe_changed(), when
+ * the state changes. */
+
+ update_pending = _update_pending_detect(self);
+ if (priv->update_pending != update_pending) {
+ priv->update_pending = update_pending;
+ _nm_dns_plugin_update_pending_maybe_changed(NM_DNS_PLUGIN(self));
+ }
+}
+
+static gboolean
+get_update_pending(NMDnsPlugin *plugin)
+{
+ NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(plugin);
+ NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+
+ nm_assert(priv->update_pending == _update_pending_detect(self));
+ return priv->update_pending;
+}
+
+/*****************************************************************************/
+
+static RequestItem *
+_request_item_ref(RequestItem *request_item)
+{
+ nm_assert(request_item);
+ nm_assert(request_item->ref_count > 0);
+ nm_assert(request_item->ref_count < G_MAXINT);
+ nm_assert(!c_list_is_empty(&request_item->request_queue_lst));
+
+ request_item->ref_count++;
+ return request_item;
+}
+
+static void
+_request_item_unref(RequestItem *request_item)
+{
+ nm_assert(request_item);
+ nm_assert(request_item->ref_count > 0);
+
+ if (--request_item->ref_count > 0)
+ return;
+
+ nm_assert(c_list_is_empty(&request_item->request_queue_lst));
+
g_variant_unref(request_item->argument);
nm_g_slice_free(request_item);
}
@@ -165,6 +247,7 @@ _request_item_append(NMDnsSystemdResolved *self,
request_item = g_slice_new(RequestItem);
*request_item = (RequestItem){
+ .ref_count = 1,
.operation = operation,
.argument = g_variant_ref_sink(argument),
.self = self,
@@ -178,8 +261,8 @@ _request_item_append(NMDnsSystemdResolved *self,
static void
_interface_config_free(InterfaceConfig *config)
{
- nm_c_list_elem_free_all(&config->configs_lst_head, NULL);
- g_slice_free(InterfaceConfig, config);
+ nm_g_ptr_array_unref(config->ip_data_list);
+ nm_g_slice_free(config);
}
static void
@@ -191,42 +274,48 @@ call_done(GObject *source, GAsyncResult *r, gpointer user_data)
NMDnsSystemdResolvedPrivate *priv;
RequestItem *request_item;
NMLogLevel log_level;
-
- v = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), r, &error);
- if (nm_utils_error_is_cancelled(error))
- return;
+ const char *operation;
+ int ifindex;
request_item = user_data;
self = request_item->self;
- priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+ operation = request_item->operation;
+ ifindex = request_item->ifindex;
+ _request_item_unref(request_item);
+
+ priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+
+ v = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), r, &error);
+ if (nm_utils_error_is_cancelled(error))
+ goto out_dec_pending;
if (v) {
- if (request_item->operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE
+ if (operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE
&& priv->has_link_default_route == NM_TERNARY_DEFAULT) {
priv->has_link_default_route = NM_TERNARY_TRUE;
_LOGD("systemd-resolved support for SetLinkDefaultRoute(): API supported");
}
- if (request_item->operation == DBUS_OP_SET_LINK_DNS_OVER_TLS
+ if (operation == DBUS_OP_SET_LINK_DNS_OVER_TLS
&& priv->has_link_dns_over_tls == NM_TERNARY_DEFAULT) {
priv->has_link_dns_over_tls = NM_TERNARY_TRUE;
_LOGD("systemd-resolved support for SetLinkDNSOverTLS(): API supported");
}
priv->send_updates_warn_ratelimited = FALSE;
- return;
+ goto out_dec_pending;
}
if (nm_g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
if (priv->has_link_default_route == NM_TERNARY_DEFAULT
- && request_item->operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE) {
+ && operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE) {
priv->has_link_default_route = NM_TERNARY_FALSE;
_LOGD("systemd-resolved support for SetLinkDefaultRoute(): API not supported");
}
if (priv->has_link_dns_over_tls == NM_TERNARY_DEFAULT
- && request_item->operation == DBUS_OP_SET_LINK_DNS_OVER_TLS) {
+ && operation == DBUS_OP_SET_LINK_DNS_OVER_TLS) {
priv->has_link_dns_over_tls = NM_TERNARY_FALSE;
_LOGD("systemd-resolved support for SetLinkDNSOverTLS(): API not supported");
}
- return;
+ goto out_dec_pending;
}
log_level = LOGL_DEBUG;
@@ -234,18 +323,25 @@ call_done(GObject *source, GAsyncResult *r, gpointer user_data)
priv->send_updates_warn_ratelimited = TRUE;
log_level = LOGL_WARN;
}
- _NMLOG(log_level,
- "send-updates %s@%d failed: %s",
- request_item->operation,
- request_item->ifindex,
- error->message);
+ _NMLOG(log_level, "send-updates %s@%d failed: %s", operation, ifindex, error->message);
+
+out_dec_pending:
+ nm_assert(priv->n_pending > 0);
+ if (--priv->n_pending <= 0) {
+ _update_pending_maybe_changed(self);
+ /* We keep @self alive while pending operations are in progress. It's simpler
+ * to implement. But this requires that we implement "stop()" signal to cancel
+ * all pending requests. Cancelling is necessary, because during shutdown,
+ * we must wrap up fast, and not hang an undefined amount time. */
+ g_object_unref(self);
+ }
}
static gboolean
-update_add_ip_config(NMDnsSystemdResolved *self,
- GVariantBuilder *dns,
- GVariantBuilder *domains,
- NMDnsConfigIPData *ip_data)
+update_add_ip_config(NMDnsSystemdResolved *self,
+ GVariantBuilder *dns,
+ GVariantBuilder *domains,
+ const NMDnsConfigIPData *ip_data)
{
gsize addr_size;
guint n;
@@ -258,8 +354,12 @@ update_add_ip_config(NMDnsSystemdResolved *self,
addr_size = nm_utils_addr_family_to_size(ip_data->addr_family);
if ((!ip_data->domains.search || !ip_data->domains.search[0])
- && !ip_data->domains.has_default_route_exclusive && !ip_data->domains.has_default_route)
+ && !ip_data->domains.has_default_route_exclusive && !ip_data->domains.has_default_route) {
+ /* we have no search domain (which systemd-resolved uses to routing the request), but
+ * also the "DefaultRoute" is not set on the interface. This setting has no effect and
+ * gets ignored. */
return FALSE;
+ }
nameservers = nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &n);
for (i = 0; i < n; i++) {
@@ -295,23 +395,28 @@ free_pending_updates(NMDnsSystemdResolved *self)
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
RequestItem *request_item;
- while ((request_item =
- c_list_first_entry(&priv->request_queue_lst_head, RequestItem, request_queue_lst)))
- _request_item_free(request_item);
+ while (
+ (request_item =
+ c_list_first_entry(&priv->request_queue_lst_head, RequestItem, request_queue_lst))) {
+ c_list_unlink(&request_item->request_queue_lst);
+ _request_item_unref(request_item);
+ }
}
static gboolean
-prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic)
+prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic)
{
GVariantBuilder dns;
GVariantBuilder domains;
- NMCListElem *elem;
- NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT;
- NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT;
- NMSettingConnectionDnsOverTls dns_over_tls = NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT;
- const char *mdns_arg = NULL, *llmnr_arg = NULL, *dns_over_tls_arg = NULL;
+ NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT;
+ NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT;
+ NMSettingConnectionDnsOverTls dns_over_tls = NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT;
+ const char *mdns_arg = NULL;
+ const char *llmnr_arg = NULL;
+ const char *dns_over_tls_arg = NULL;
gboolean has_config = FALSE;
gboolean has_default_route = FALSE;
+ guint i;
g_variant_builder_init(&dns, G_VARIANT_TYPE("(ia(iay))"));
g_variant_builder_add(&dns, "i", ic->ifindex);
@@ -321,18 +426,22 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic)
g_variant_builder_add(&domains, "i", ic->ifindex);
g_variant_builder_open(&domains, G_VARIANT_TYPE("a(sb)"));
- c_list_for_each_entry (elem, &ic->configs_lst_head, lst) {
- NMDnsConfigIPData *ip_data = elem->data;
+ if (ic->ip_data_list) {
+ for (i = 0; i < ic->ip_data_list->len; i++) {
+ const NMDnsConfigIPData *ip_data = ic->ip_data_list->pdata[i];
- has_config |= update_add_ip_config(self, &dns, &domains, ip_data);
+ if (update_add_ip_config(self, &dns, &domains, ip_data))
+ has_config = TRUE;
- if (ip_data->domains.has_default_route)
- has_default_route = TRUE;
+ if (ip_data->domains.has_default_route)
+ has_default_route = TRUE;
- if (NM_IS_IPv4(ip_data->addr_family)) {
- mdns = NM_MAX(mdns, nm_l3_config_data_get_mdns(ip_data->l3cd));
- llmnr = NM_MAX(llmnr, nm_l3_config_data_get_llmnr(ip_data->l3cd));
- dns_over_tls = NM_MAX(dns_over_tls, nm_l3_config_data_get_dns_over_tls(ip_data->l3cd));
+ if (NM_IS_IPv4(ip_data->addr_family)) {
+ mdns = NM_MAX(mdns, nm_l3_config_data_get_mdns(ip_data->l3cd));
+ llmnr = NM_MAX(llmnr, nm_l3_config_data_get_llmnr(ip_data->l3cd));
+ dns_over_tls =
+ NM_MAX(dns_over_tls, nm_l3_config_data_get_dns_over_tls(ip_data->l3cd));
+ }
}
}
@@ -439,6 +548,7 @@ again:
goto again;
}
+ _update_pending_maybe_changed(self);
return G_SOURCE_CONTINUE;
}
@@ -447,6 +557,9 @@ ensure_resolved_running(NMDnsSystemdResolved *self)
{
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+ if (priv->stopped)
+ return NM_TERNARY_FALSE;
+
if (!priv->dbus_initied)
return NM_TERNARY_DEFAULT;
@@ -469,6 +582,7 @@ ensure_resolved_running(NMDnsSystemdResolved *self)
NULL,
NULL,
NULL);
+ _update_pending_maybe_changed(self);
return NM_TERNARY_DEFAULT;
}
@@ -523,6 +637,12 @@ send_updates(NMDnsSystemdResolved *self)
request_item->operation,
(ss = g_variant_print(request_item->argument, FALSE)));
+ if (priv->n_pending++ == 0) {
+ /* We are inside send_updates(). All callers are already calling
+ * _update_pending_maybe_changed() afterwards. */
+ g_object_ref(self);
+ }
+
g_dbus_connection_call(priv->dbus_connection,
priv->dbus_owner,
SYSTEMD_RESOLVED_DBUS_PATH,
@@ -534,7 +654,7 @@ send_updates(NMDnsSystemdResolved *self)
-1,
priv->cancellable,
call_done,
- request_item);
+ _request_item_ref(request_item));
}
start_resolve:
@@ -554,43 +674,54 @@ update(NMDnsPlugin *plugin,
const char *hostdomain,
GError **error)
{
- NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(plugin);
- NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
- gs_unref_hashtable GHashTable *interfaces = NULL;
- gs_free gpointer *interfaces_keys = NULL;
+ NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(plugin);
+ NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+ gs_unref_hashtable GHashTable *interfaces = NULL;
+ const NMUtilsNamedValue *interfaces_arr;
+ NMUtilsNamedValue interfaces_arr_stack[50];
+ gs_free NMUtilsNamedValue *interfaces_arr_heap = NULL;
guint interfaces_len;
- int ifindex;
gpointer pointer;
NMDnsConfigIPData *ip_data;
GHashTableIter iter;
+ gs_unref_array GArray *dirty_array = NULL;
guint i;
+ nm_assert(!priv->stopped);
+
+ /* Group configs by ifindex/interfaces. */
interfaces =
g_hash_table_new_full(nm_direct_hash, NULL, NULL, (GDestroyNotify) _interface_config_free);
c_list_for_each_entry (ip_data, ip_data_lst_head, ip_data_lst) {
- InterfaceConfig *ic = NULL;
+ InterfaceConfig *ic = NULL;
+ int ifindex = ip_data->data->ifindex;
- ifindex = ip_data->data->ifindex;
nm_assert(ifindex == nm_l3_config_data_get_ifindex(ip_data->l3cd));
ic = g_hash_table_lookup(interfaces, GINT_TO_POINTER(ifindex));
if (!ic) {
- ic = g_slice_new(InterfaceConfig);
- ic->ifindex = ifindex;
- c_list_init(&ic->configs_lst_head);
+ ic = g_slice_new(InterfaceConfig);
+ *ic = (InterfaceConfig){
+ .ifindex = ifindex,
+ .ip_data_list = g_ptr_array_sized_new(4),
+ };
g_hash_table_insert(interfaces, GINT_TO_POINTER(ifindex), ic);
}
- c_list_link_tail(&ic->configs_lst_head, &nm_c_list_elem_new_stale(ip_data)->lst);
+ g_ptr_array_add(ic->ip_data_list, ip_data);
}
free_pending_updates(self);
- interfaces_keys =
- nm_utils_hash_keys_to_array(interfaces, nm_cmp_int2ptr_p_with_data, NULL, &interfaces_len);
+ interfaces_arr = nm_utils_hash_to_array_with_buffer(interfaces,
+ &interfaces_len,
+ nm_cmp_int2ptr_p_with_data,
+ NULL,
+ interfaces_arr_stack,
+ &interfaces_arr_heap);
for (i = 0; i < interfaces_len; i++) {
- InterfaceConfig *ic = g_hash_table_lookup(interfaces, GINT_TO_POINTER(interfaces_keys[i]));
+ const InterfaceConfig *ic = interfaces_arr[i].value_ptr;
if (prepare_one_interface(self, ic))
g_hash_table_add(priv->dirty_interfaces, GINT_TO_POINTER(ic->ifindex));
@@ -602,23 +733,38 @@ update(NMDnsPlugin *plugin,
* resolved, and the current update doesn't contain that interface,
* reset the resolved configuration for that ifindex. */
g_hash_table_iter_init(&iter, priv->dirty_interfaces);
- while (g_hash_table_iter_next(&iter, (gpointer *) &pointer, NULL)) {
- ifindex = GPOINTER_TO_INT(pointer);
- if (!g_hash_table_contains(interfaces, GINT_TO_POINTER(ifindex))) {
+ while (g_hash_table_iter_next(&iter, &pointer, NULL)) {
+ int ifindex = GPOINTER_TO_INT(pointer);
+
+ if (g_hash_table_contains(interfaces, GINT_TO_POINTER(ifindex))) {
+ /* the interface is still tracked and still dirty. Keep. */
+ continue;
+ }
+
+ if (!dirty_array)
+ dirty_array = g_array_new(FALSE, FALSE, sizeof(int));
+ g_array_append_val(dirty_array, ifindex);
+
+ g_hash_table_iter_remove(&iter);
+ }
+ if (dirty_array) {
+ g_array_sort_with_data(dirty_array, nm_cmp_int2ptr_p_with_data, NULL);
+ for (i = 0; i < dirty_array->len; i++) {
+ int ifindex = g_array_index(dirty_array, int, i);
InterfaceConfig ic;
_LOGT("clear previously configured ifindex %d", ifindex);
ic = (InterfaceConfig){
- .ifindex = ifindex,
- .configs_lst_head = C_LIST_INIT(ic.configs_lst_head),
+ .ifindex = ifindex,
+ .ip_data_list = NULL,
};
prepare_one_interface(self, &ic);
- g_hash_table_iter_remove(&iter);
}
}
priv->send_updates_waiting = TRUE;
send_updates(self);
+ _update_pending_maybe_changed(self);
return TRUE;
}
@@ -649,6 +795,7 @@ name_owner_changed(NMDnsSystemdResolved *self, const char *owner)
}
send_updates(self);
+ _update_pending_maybe_changed(self);
}
static void
@@ -957,6 +1104,48 @@ nm_dns_systemd_resolved_resolve_cancel(NMDnsSystemdResolvedResolveHandle *handle
/*****************************************************************************/
static void
+stop(NMDnsPlugin *plugin)
+{
+ NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(plugin);
+ NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
+ NMDnsSystemdResolvedResolveHandle *handle;
+
+ /* This function must be re-entrant!!
+ *
+ * Currently there is no concept of unregistering/shutting down. It's not
+ * clear whether we should de-configure anything in systemd-resolved, we
+ * don't.
+ *
+ * Implementing stop() is important because pending operations take a
+ * reference on @self. We can only cancel (fast shutdown) the instance
+ * by cancelling those requests. */
+
+ priv->stopped = TRUE;
+ priv->try_start_blocked = TRUE;
+
+ nm_clear_g_cancellable(&priv->cancellable);
+
+ nm_clear_g_free(&priv->dbus_owner);
+
+ while ((handle = c_list_first_entry(&priv->handle_lst_head,
+ NMDnsSystemdResolvedResolveHandle,
+ handle_lst))) {
+ gs_free_error GError *error = NULL;
+
+ nm_utils_error_set_cancelled(&error, TRUE, "NMDnsSystemdResolved");
+ _resolve_complete_error(handle, error);
+ }
+
+ free_pending_updates(self);
+
+ nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id);
+
+ nm_clear_g_source_inst(&priv->try_start_timeout_source);
+}
+
+/*****************************************************************************/
+
+static void
nm_dns_systemd_resolved_init(NMDnsSystemdResolved *self)
{
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
@@ -974,6 +1163,8 @@ nm_dns_systemd_resolved_init(NMDnsSystemdResolved *self)
return;
}
+ priv->update_pending = TRUE;
+
priv->name_owner_changed_id =
nm_dbus_connection_signal_subscribe_name_owner_changed(priv->dbus_connection,
SYSTEMD_RESOLVED_DBUS_SERVICE,
@@ -998,33 +1189,15 @@ nm_dns_systemd_resolved_new(void)
static void
dispose(GObject *object)
{
- NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(object);
- NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
- NMDnsSystemdResolvedResolveHandle *handle;
-
- while ((handle = c_list_first_entry(&priv->handle_lst_head,
- NMDnsSystemdResolvedResolveHandle,
- handle_lst))) {
- gs_free_error GError *error = NULL;
-
- nm_utils_error_set_cancelled(&error, TRUE, "NMDnsSystemdResolved");
- _resolve_complete_error(handle, error);
- }
-
- free_pending_updates(self);
-
- nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id);
+ NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(object);
+ NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self);
- nm_clear_g_cancellable(&priv->cancellable);
-
- nm_clear_g_source_inst(&priv->try_start_timeout_source);
+ stop(NM_DNS_PLUGIN(self));
g_clear_object(&priv->dbus_connection);
- nm_clear_pointer(&priv->dirty_interfaces, g_hash_table_unref);
+ nm_clear_pointer(&priv->dirty_interfaces, g_hash_table_destroy);
G_OBJECT_CLASS(nm_dns_systemd_resolved_parent_class)->dispose(object);
-
- nm_clear_g_free(&priv->dbus_owner);
}
static void
@@ -1035,7 +1208,9 @@ nm_dns_systemd_resolved_class_init(NMDnsSystemdResolvedClass *dns_class)
object_class->dispose = dispose;
- plugin_class->plugin_name = "systemd-resolved";
- plugin_class->is_caching = TRUE;
- plugin_class->update = update;
+ plugin_class->plugin_name = "systemd-resolved";
+ plugin_class->is_caching = TRUE;
+ plugin_class->stop = stop;
+ plugin_class->update = update;
+ plugin_class->get_update_pending = get_update_pending;
}
diff --git a/src/core/dns/nm-dns-unbound.c b/src/core/dns/nm-dns-unbound.c
deleted file mode 100644
index 8a75cf08f0..0000000000
--- a/src/core/dns/nm-dns-unbound.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2014 Red Hat, Inc.
- * Author: Pavel Å imerda <psimerda@redhat.com>
- */
-
-#include "src/core/nm-default-daemon.h"
-
-#include "nm-dns-unbound.h"
-
-#include "NetworkManagerUtils.h"
-
-/*****************************************************************************/
-
-struct _NMDnsUnbound {
- NMDnsPlugin parent;
-};
-
-struct _NMDnsUnboundClass {
- NMDnsPluginClass parent;
-};
-
-G_DEFINE_TYPE(NMDnsUnbound, nm_dns_unbound, NM_TYPE_DNS_PLUGIN)
-
-/*****************************************************************************/
-
-static gboolean
-update(NMDnsPlugin *plugin,
- const NMGlobalDnsConfig *global_config,
- const CList *ip_config_lst_head,
- const char *hostdomain,
- GError **error)
-{
- char *argv[] = {DNSSEC_TRIGGER_PATH, "--async", "--update", NULL};
- gs_free_error GError *local = NULL;
- int status;
-
- /* TODO: We currently call a script installed with the dnssec-trigger
- * package that queries all information itself. Later, the dependency
- * on that package will be optional and the only hard dependency will
- * be unbound.
- *
- * Unbound configuration should be later handled by this plugin directly,
- * without calling custom scripts. The dnssec-trigger functionality
- * may be eventually merged into NetworkManager.
- */
- if (!g_spawn_sync("/", argv, NULL, 0, NULL, NULL, NULL, NULL, &status, &local)) {
- nm_utils_error_set(error,
- NM_UTILS_ERROR_UNKNOWN,
- "error spawning dns-trigger: %s",
- local->message);
- return FALSE;
- }
- if (status != 0) {
- nm_utils_error_set(error,
- NM_UTILS_ERROR_UNKNOWN,
- "dns-trigger exited with error code %d",
- status);
- return FALSE;
- }
- return TRUE;
-}
-
-/*****************************************************************************/
-
-static void
-nm_dns_unbound_init(NMDnsUnbound *unbound)
-{}
-
-NMDnsPlugin *
-nm_dns_unbound_new(void)
-{
- return g_object_new(NM_TYPE_DNS_UNBOUND, NULL);
-}
-
-static void
-nm_dns_unbound_class_init(NMDnsUnboundClass *klass)
-{
- NMDnsPluginClass *plugin_class = NM_DNS_PLUGIN_CLASS(klass);
-
- plugin_class->plugin_name = "unbound";
- plugin_class->is_caching = TRUE;
- plugin_class->update = update;
-}
diff --git a/src/core/dns/nm-dns-unbound.h b/src/core/dns/nm-dns-unbound.h
deleted file mode 100644
index feb3309913..0000000000
--- a/src/core/dns/nm-dns-unbound.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2014 Red Hat, Inc.
- */
-
-#ifndef __NETWORKMANAGER_DNS_UNBOUND_H__
-#define __NETWORKMANAGER_DNS_UNBOUND_H__
-
-#include "nm-dns-plugin.h"
-
-#define NM_TYPE_DNS_UNBOUND (nm_dns_unbound_get_type())
-#define NM_DNS_UNBOUND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNS_UNBOUND, NMDnsUnbound))
-#define NM_DNS_UNBOUND_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DNS_UNBOUND, NMDnsUnboundClass))
-#define NM_IS_DNS_UNBOUND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DNS_UNBOUND))
-#define NM_IS_DNS_UNBOUND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DNS_UNBOUND))
-#define NM_DNS_UNBOUND_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DNS_UNBOUND, NMDnsUnboundClass))
-
-typedef struct _NMDnsUnbound NMDnsUnbound;
-typedef struct _NMDnsUnboundClass NMDnsUnboundClass;
-
-GType nm_dns_unbound_get_type(void);
-
-NMDnsPlugin *nm_dns_unbound_new(void);
-
-#endif /* __NETWORKMANAGER_DNS_UNBOUND_H__ */
diff --git a/src/core/meson.build b/src/core/meson.build
index 2148d23b76..f3359ad0f5 100644
--- a/src/core/meson.build
+++ b/src/core/meson.build
@@ -123,7 +123,6 @@ libNetworkManager = static_library(
'dns/nm-dns-manager.c',
'dns/nm-dns-plugin.c',
'dns/nm-dns-systemd-resolved.c',
- 'dns/nm-dns-unbound.c',
'dnsmasq/nm-dnsmasq-manager.c',
'dnsmasq/nm-dnsmasq-utils.c',
'ppp/nm-ppp-manager-call.c',
diff --git a/src/core/nm-config.c b/src/core/nm-config.c
index ea1c2ab300..cdc070900f 100644
--- a/src/core/nm-config.c
+++ b/src/core/nm-config.c
@@ -11,7 +11,9 @@
#include <stdio.h>
#include "nm-utils.h"
+#include "nm-dhcp-config.h"
#include "devices/nm-device.h"
+#include "dhcp/nm-dhcp-options.h"
#include "NetworkManagerUtils.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "libnm-core-intern/nm-keyfile-internal.h"
@@ -2573,13 +2575,16 @@ nm_config_device_state_write(int ifindex,
NMTernary nm_owned,
guint32 route_metric_default_aspired,
guint32 route_metric_default_effective,
- const char *next_server,
- const char *root_path,
- const char *dhcp_bootfile)
+ NMDhcpConfig *dhcp4_config,
+ NMDhcpConfig *dhcp6_config)
{
char path[NM_STRLEN(NM_CONFIG_DEVICE_STATE_DIR "/") + DEVICE_STATE_FILENAME_LEN_MAX + 1];
- GError *local = NULL;
- nm_auto_unref_keyfile GKeyFile *kf = NULL;
+ GError *local = NULL;
+ nm_auto_unref_keyfile GKeyFile *kf = NULL;
+ const char *root_path = NULL;
+ const char *next_server = NULL;
+ const char *dhcp_bootfile = NULL;
+ int IS_IPv4;
g_return_val_if_fail(ifindex > 0, FALSE);
g_return_val_if_fail(!connection_uuid || *connection_uuid, FALSE);
@@ -2630,6 +2635,15 @@ nm_config_device_state_write(int ifindex,
route_metric_default_aspired);
}
}
+
+ if (dhcp4_config) {
+ next_server = nm_dhcp_config_get_option(dhcp4_config, "next_server");
+ root_path = nm_dhcp_config_get_option(dhcp4_config, "root_path");
+ dhcp_bootfile = nm_dhcp_config_get_option(dhcp4_config, "filename");
+ if (!dhcp_bootfile)
+ dhcp_bootfile = nm_dhcp_config_get_option(dhcp4_config, "bootfile_name");
+ }
+
if (next_server) {
g_key_file_set_string(kf,
DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE,
@@ -2649,6 +2663,28 @@ nm_config_device_state_write(int ifindex,
dhcp_bootfile);
}
+ for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
+ NMDhcpConfig *dhcp_config = IS_IPv4 ? dhcp4_config : dhcp6_config;
+ gs_free NMUtilsNamedValue *values = NULL;
+ guint i;
+ guint num;
+
+ if (!dhcp_config)
+ continue;
+
+ values = nm_dhcp_config_get_option_values(dhcp_config, &num);
+ for (i = 0; i < num; i++) {
+ gs_free char *name_full = NULL;
+ const char *prefix = IS_IPv4 ? "dhcp4" : "dhcp6";
+
+ if (NM_STR_HAS_PREFIX(values[i].name, NM_DHCP_OPTION_REQPREFIX))
+ continue;
+
+ name_full = g_strdup_printf("%s.%s", prefix, values[i].name);
+ g_key_file_set_string(kf, prefix, name_full, values[i].value_str);
+ }
+ }
+
if (!g_key_file_save_to_file(kf, path, &local)) {
_LOGW("device-state: write #%d (%s) failed: %s", ifindex, path, local->message);
g_error_free(local);
diff --git a/src/core/nm-config.h b/src/core/nm-config.h
index 2c23ff200e..d7498f92be 100644
--- a/src/core/nm-config.h
+++ b/src/core/nm-config.h
@@ -183,9 +183,8 @@ gboolean nm_config_device_state_write(int
NMTernary nm_owned,
guint32 route_metric_default_aspired,
guint32 route_metric_default_effective,
- const char *next_server,
- const char *root_path,
- const char *dhcp_bootfile);
+ NMDhcpConfig *dhcp4_config,
+ NMDhcpConfig *dhcp6_config);
void nm_config_device_state_prune_stale(GHashTable *preserve_ifindexes,
NMPlatform *preserve_in_platform);
diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c
index c8b789b30a..b2ebe30c25 100644
--- a/src/core/nm-core-utils.c
+++ b/src/core/nm-core-utils.c
@@ -30,7 +30,6 @@
#include "libnm-glib-aux/nm-secret-utils.h"
#include "libnm-glib-aux/nm-time-utils.h"
#include "libnm-glib-aux/nm-str-buf.h"
-#include "libnm-systemd-shared/nm-sd-utils-shared.h"
#include "nm-utils.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "nm-setting-connection.h"
@@ -5114,7 +5113,7 @@ nm_utils_spawn_helper(const char *const *args,
fcntl(info->child_stdout, F_SETFL, fd_flags | O_NONBLOCK);
/* Watch process stdin */
- nm_str_buf_init(&info->out_buffer, 32, TRUE);
+ info->out_buffer = NM_STR_BUF_INIT(32, TRUE);
for (arg = args; *arg; arg++) {
nm_str_buf_append(&info->out_buffer, *arg);
nm_str_buf_append_c(&info->out_buffer, '\0');
@@ -5128,7 +5127,7 @@ nm_utils_spawn_helper(const char *const *args,
g_source_attach(info->output_source, g_main_context_get_thread_default());
/* Watch process stdout */
- nm_str_buf_init(&info->in_buffer, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
+ info->in_buffer = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
info->input_source = nm_g_unix_fd_source_new(info->child_stdout,
G_IO_IN | G_IO_ERR | G_IO_HUP,
G_PRIORITY_DEFAULT,
@@ -5223,7 +5222,7 @@ again:
* @shortened: (out) (transfer full): on return, the shortened hostname
*
* Checks whether the input hostname is valid. If not, tries to shorten it
- * to HOST_NAME_MAX or to the first dot, whatever comes earlier.
+ * to HOST_NAME_MAX (64) or to the first dot, whatever comes earlier.
* The new hostname is returned in @shortened.
*
* Returns: %TRUE if the input hostname was already valid or if was shortened
@@ -5239,7 +5238,7 @@ nm_utils_shorten_hostname(const char *hostname, char **shortened)
nm_assert(hostname);
nm_assert(shortened);
- if (nm_sd_hostname_is_valid(hostname, FALSE)) {
+ if (nm_hostname_is_valid(hostname, FALSE)) {
*shortened = NULL;
return TRUE;
}
@@ -5249,11 +5248,11 @@ nm_utils_shorten_hostname(const char *hostname, char **shortened)
l = (dot - hostname);
else
l = strlen(hostname);
- l = MIN(l, (gsize) HOST_NAME_MAX);
+ l = MIN(l, (gsize) NM_HOST_NAME_MAX);
s = g_strndup(hostname, l);
- if (!nm_sd_hostname_is_valid(s, FALSE)) {
+ if (!nm_hostname_is_valid(s, FALSE)) {
*shortened = NULL;
return FALSE;
}
diff --git a/src/core/nm-dhcp-config.c b/src/core/nm-dhcp-config.c
index b32c9b7056..394a3a4924 100644
--- a/src/core/nm-dhcp-config.c
+++ b/src/core/nm-dhcp-config.c
@@ -125,6 +125,29 @@ nm_dhcp_config_set_lease(NMDhcpConfig *self, const NML3ConfigData *l3cd)
_notify(self, PROP_OPTIONS);
}
+NMUtilsNamedValue *
+nm_dhcp_config_get_option_values(NMDhcpConfig *self, guint *num)
+{
+ NMDhcpConfigPrivate *priv = NM_DHCP_CONFIG_GET_PRIVATE(self);
+ NMDhcpLease *lease;
+ NMUtilsNamedValue *buffer = NULL;
+
+ if (!priv->l3cd) {
+ NM_SET_OUT(num, 0);
+ return NULL;
+ }
+
+ lease = nm_l3_config_data_get_dhcp_lease(priv->l3cd, nm_dhcp_config_get_addr_family(self));
+ nm_utils_named_values_from_strdict_full(nm_dhcp_lease_get_options(lease),
+ num,
+ nm_strcmp_p_with_data,
+ NULL,
+ NULL,
+ 0,
+ &buffer);
+ return buffer;
+}
+
const char *
nm_dhcp_config_get_option(NMDhcpConfig *self, const char *key)
{
diff --git a/src/core/nm-dhcp-config.h b/src/core/nm-dhcp-config.h
index cae0e11aa2..cdca4ef1fb 100644
--- a/src/core/nm-dhcp-config.h
+++ b/src/core/nm-dhcp-config.h
@@ -30,7 +30,8 @@ int nm_dhcp_config_get_addr_family(NMDhcpConfig *self);
void nm_dhcp_config_set_lease(NMDhcpConfig *self, const NML3ConfigData *l3cd);
-const char *nm_dhcp_config_get_option(NMDhcpConfig *self, const char *option);
+NMUtilsNamedValue *nm_dhcp_config_get_option_values(NMDhcpConfig *self, guint *num);
+const char *nm_dhcp_config_get_option(NMDhcpConfig *self, const char *option);
GVariant *nm_dhcp_config_get_options(NMDhcpConfig *self);
diff --git a/src/core/nm-firewall-utils.c b/src/core/nm-firewall-utils.c
index 8fa8059e00..1311f50399 100644
--- a/src/core/nm-firewall-utils.c
+++ b/src/core/nm-firewall-utils.c
@@ -679,8 +679,7 @@ _fw_nft_set(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen)
NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL,
&ss1));
- stdin_buf = g_bytes_new_static(nm_str_buf_get_str(&strbuf), strbuf.len);
-
+ stdin_buf = nm_str_buf_finalize_to_gbytes(&strbuf);
_fw_nft_call_sync(stdin_buf, NULL);
}
diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c
index 521536979f..ee661e499e 100644
--- a/src/core/nm-manager.c
+++ b/src/core/nm-manager.c
@@ -20,6 +20,7 @@
#include "devices/nm-device-factory.h"
#include "devices/nm-device-generic.h"
#include "devices/nm-device.h"
+#include "dns/nm-dns-manager.h"
#include "dhcp/nm-dhcp-manager.h"
#include "libnm-core-aux-intern/nm-common-macros.h"
#include "libnm-core-intern/nm-core-internal.h"
@@ -144,6 +145,9 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMManager,
typedef struct {
NMPlatform *platform;
+ NMDnsManager *dns_mgr;
+ gulong dns_mgr_update_pending_signal_id;
+
GArray *capabilities;
CList active_connections_lst_head; /* Oldest ACs at the beginning */
@@ -346,6 +350,9 @@ static NMActiveConnection *_new_active_connection(NMManager *self,
static void policy_activating_ac_changed(GObject *object, GParamSpec *pspec, gpointer user_data);
+static void device_has_pending_action_changed(NMDevice *device, GParamSpec *pspec, NMManager *self);
+static void check_if_startup_complete(NMManager *self);
+
static gboolean find_master(NMManager *self,
NMConnection *connection,
NMDevice *device,
@@ -1601,7 +1608,11 @@ manager_device_state_changed(NMDevice *device,
nm_settings_device_added(priv->settings, device);
}
-static void device_has_pending_action_changed(NMDevice *device, GParamSpec *pspec, NMManager *self);
+static void
+_dns_mgr_update_pending_cb(NMDevice *device, GParamSpec *pspec, NMManager *self)
+{
+ check_if_startup_complete(self);
+}
static void
check_if_startup_complete(NMManager *self)
@@ -1616,6 +1627,20 @@ check_if_startup_complete(NMManager *self)
if (!priv->devices_inited)
return;
+ if (nm_dns_manager_get_update_pending(nm_manager_get_dns_manager(self))) {
+ if (priv->dns_mgr_update_pending_signal_id == 0) {
+ priv->dns_mgr_update_pending_signal_id =
+ g_signal_connect(nm_manager_get_dns_manager(self),
+ "notify::" NM_DNS_MANAGER_UPDATE_PENDING,
+ G_CALLBACK(_dns_mgr_update_pending_cb),
+ self);
+ }
+ return;
+ }
+
+ nm_clear_g_signal_handler(nm_manager_get_dns_manager(self),
+ &priv->dns_mgr_update_pending_signal_id);
+
c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
reason = nm_device_has_pending_action_reason(device);
if (reason) {
@@ -7014,10 +7039,6 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde
guint32 route_metric_default_aspired;
guint32 route_metric_default_effective;
NMTernary nm_owned;
- NMDhcpConfig *dhcp_config;
- const char *next_server = NULL;
- const char *root_path = NULL;
- const char *dhcp_bootfile = NULL;
NM_SET_OUT(out_ifindex, 0);
@@ -7059,15 +7080,6 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde
TRUE,
&route_metric_default_aspired);
- dhcp_config = nm_device_get_dhcp_config(device, AF_INET);
- if (dhcp_config) {
- root_path = nm_dhcp_config_get_option(dhcp_config, "root_path");
- next_server = nm_dhcp_config_get_option(dhcp_config, "next_server");
- dhcp_bootfile = nm_dhcp_config_get_option(dhcp_config, "filename");
- if (!dhcp_bootfile)
- dhcp_bootfile = nm_dhcp_config_get_option(dhcp_config, "bootfile_name");
- }
-
if (!nm_config_device_state_write(ifindex,
managed_type,
perm_hw_addr_fake,
@@ -7075,9 +7087,8 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde
nm_owned,
route_metric_default_aspired,
route_metric_default_effective,
- next_server,
- root_path,
- dhcp_bootfile))
+ nm_device_get_dhcp_config(device, AF_INET),
+ nm_device_get_dhcp_config(device, AF_INET6)))
return FALSE;
NM_SET_OUT(out_ifindex, ifindex);
@@ -7790,6 +7801,28 @@ impl_manager_checkpoint_adjust_rollback_timeout(NMDBusObject
/*****************************************************************************/
+NMDnsManager *
+nm_manager_get_dns_manager(NMManager *self)
+{
+ NMManagerPrivate *priv;
+
+ g_return_val_if_fail(NM_IS_MANAGER(self), NULL);
+
+ priv = NM_MANAGER_GET_PRIVATE(self);
+
+ if (G_UNLIKELY(!priv->dns_mgr)) {
+ /* Initialize lazily on first use.
+ *
+ * But keep a reference. This is to ensure proper lifetimes between
+ * singleton instances (i.e. nm_dns_manager_get() outlives NMManager). */
+ priv->dns_mgr = g_object_ref(nm_dns_manager_get());
+ }
+
+ return priv->dns_mgr;
+}
+
+/*****************************************************************************/
+
static void
auth_mgr_changed(NMAuthManager *auth_manager, gpointer user_data)
{
@@ -8250,6 +8283,9 @@ dispose(GObject *object)
g_clear_object(&priv->concheck_mgr);
}
+ nm_clear_g_signal_handler(priv->dns_mgr, &priv->dns_mgr_update_pending_signal_id);
+ g_clear_object(&priv->dns_mgr);
+
if (priv->auth_mgr) {
g_signal_handlers_disconnect_by_func(priv->auth_mgr, G_CALLBACK(auth_mgr_changed), self);
g_clear_object(&priv->auth_mgr);
diff --git a/src/core/nm-manager.h b/src/core/nm-manager.h
index f8563c3aa1..fcb0022720 100644
--- a/src/core/nm-manager.h
+++ b/src/core/nm-manager.h
@@ -200,6 +200,10 @@ NMMetered nm_manager_get_metered(NMManager *self);
void nm_manager_notify_device_availability_maybe_changed(NMManager *self);
+struct _NMDnsManager;
+
+struct _NMDnsManager *nm_manager_get_dns_manager(NMManager *self);
+
/*****************************************************************************/
void nm_manager_device_auth_request(NMManager *self,
diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c
index 1ff66e25de..2b988527e9 100644
--- a/src/core/settings/nm-settings.c
+++ b/src/core/settings/nm-settings.c
@@ -389,15 +389,15 @@ typedef struct {
gint64 startup_complete_start_timestamp_msec;
GHashTable *startup_complete_idx;
CList startup_complete_scd_lst_head;
- guint startup_complete_timeout_id;
+ GSource *startup_complete_timeout_source;
+
+ GSource *kf_db_flush_idle_source_timestamps;
+ GSource *kf_db_flush_idle_source_seen_bssids;
guint connections_len;
guint connections_generation;
- guint kf_db_flush_idle_id_timestamps;
- guint kf_db_flush_idle_id_seen_bssids;
-
bool kf_db_pruned_timestamps;
bool kf_db_pruned_seen_bssid;
@@ -541,9 +541,9 @@ _startup_complete_timeout_cb(gpointer user_data)
NMSettings *self = user_data;
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self);
- priv->startup_complete_timeout_id = 0;
+ nm_clear_g_source_inst(&priv->startup_complete_timeout_source);
_startup_complete_check(self, 0);
- return G_SOURCE_REMOVE;
+ return G_SOURCE_CONTINUE;
}
static void
@@ -567,7 +567,7 @@ _startup_complete_check(NMSettings *self, gint64 now_msec)
return;
}
- nm_clear_g_source(&priv->startup_complete_timeout_id);
+ nm_clear_g_source_inst(&priv->startup_complete_timeout_source);
if (c_list_is_empty(&priv->startup_complete_scd_lst_head))
goto ready;
@@ -609,8 +609,10 @@ next_with_ready:
timeout_msec = priv->startup_complete_start_timestamp_msec + scd_not_ready->timeout_msec
- nm_utils_get_monotonic_timestamp_msec();
- priv->startup_complete_timeout_id =
- g_timeout_add(NM_CLAMP(0, timeout_msec, 60000), _startup_complete_timeout_cb, self);
+ priv->startup_complete_timeout_source =
+ nm_g_timeout_add_source(NM_CLAMP(0, timeout_msec, 60000),
+ _startup_complete_timeout_cb,
+ self);
_LOGT("startup-complete: wait for suitable device for connection \"%s\" (%s) which has "
"\"connection.wait-device-timeout\" set",
nm_settings_connection_get_id(scd_not_ready->sett_conn),
@@ -637,7 +639,7 @@ ready:
_LOGT("startup-complete: ready, no more profiles to wait for");
priv->startup_complete_start_timestamp_msec = 0;
nm_assert(!priv->startup_complete_idx);
- nm_assert(priv->startup_complete_timeout_id == 0);
+ nm_assert(!priv->startup_complete_timeout_source);
_notify(self, PROP_STARTUP_COMPLETE);
}
@@ -3842,13 +3844,13 @@ _kf_db_got_dirty_flush(NMSettings *self, gboolean is_timestamps)
NMKeyFileDB *kf_db;
if (is_timestamps) {
- prefix = "timestamps";
- kf_db = priv->kf_db_timestamps;
- priv->kf_db_flush_idle_id_timestamps = 0;
+ prefix = "timestamps";
+ kf_db = priv->kf_db_timestamps;
+ nm_clear_g_source_inst(&priv->kf_db_flush_idle_source_timestamps);
} else {
- prefix = "seen-bssids";
- kf_db = priv->kf_db_seen_bssids;
- priv->kf_db_flush_idle_id_seen_bssids = 0;
+ prefix = "seen-bssids";
+ kf_db = priv->kf_db_seen_bssids;
+ nm_clear_g_source_inst(&priv->kf_db_flush_idle_source_seen_bssids);
}
if (nm_key_file_db_is_dirty(kf_db))
@@ -3859,7 +3861,7 @@ _kf_db_got_dirty_flush(NMSettings *self, gboolean is_timestamps)
nm_key_file_db_get_filename(kf_db));
}
- return G_SOURCE_REMOVE;
+ return G_SOURCE_CONTINUE;
}
static gboolean
@@ -3880,26 +3882,27 @@ _kf_db_got_dirty_fcn(NMKeyFileDB *kf_db, gpointer user_data)
NMSettings *self = user_data;
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self);
GSourceFunc idle_func;
- guint *p_id;
+ GSource **p_source;
const char *prefix;
if (priv->kf_db_timestamps == kf_db) {
prefix = "timestamps";
- p_id = &priv->kf_db_flush_idle_id_timestamps;
+ p_source = &priv->kf_db_flush_idle_source_timestamps;
idle_func = _kf_db_got_dirty_flush_timestamps_cb;
} else if (priv->kf_db_seen_bssids == kf_db) {
prefix = "seen-bssids";
- p_id = &priv->kf_db_flush_idle_id_seen_bssids;
+ p_source = &priv->kf_db_flush_idle_source_seen_bssids;
idle_func = _kf_db_got_dirty_flush_seen_bssids_cb;
} else {
nm_assert_not_reached();
return;
}
- if (*p_id != 0)
+ if (*p_source)
return;
_LOGT("[%s-keyfile]: schedule flushing changes to disk", prefix);
- *p_id = g_idle_add_full(G_PRIORITY_LOW, idle_func, self, NULL);
+ *p_source =
+ nm_g_source_attach(nm_g_idle_source_new(G_PRIORITY_LOW, idle_func, self, NULL), NULL);
}
void
@@ -4100,7 +4103,7 @@ dispose(GObject *object)
nm_assert(c_list_is_empty(&priv->sce_dirty_lst_head));
nm_assert(g_hash_table_size(priv->sce_idx) == 0);
- nm_clear_g_source(&priv->startup_complete_timeout_id);
+ nm_clear_g_source_inst(&priv->startup_complete_timeout_source);
nm_clear_pointer(&priv->startup_complete_idx, g_hash_table_destroy);
nm_assert(c_list_is_empty(&priv->startup_complete_scd_lst_head));
@@ -4154,8 +4157,8 @@ finalize(GObject *object)
g_clear_object(&priv->agent_mgr);
- nm_clear_g_source(&priv->kf_db_flush_idle_id_timestamps);
- nm_clear_g_source(&priv->kf_db_flush_idle_id_seen_bssids);
+ nm_clear_g_source_inst(&priv->kf_db_flush_idle_source_timestamps);
+ nm_clear_g_source_inst(&priv->kf_db_flush_idle_source_seen_bssids);
_kf_db_to_file(self, TRUE, FALSE);
_kf_db_to_file(self, FALSE, FALSE);
nm_key_file_db_destroy(priv->kf_db_timestamps);
diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c
index efb9bfce4f..1d7de8d24b 100644
--- a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c
+++ b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c
@@ -26,8 +26,6 @@
#include "libnm-core-intern/nm-core-internal.h"
#include "libnm-core-intern/nm-keyfile-internal.h"
-#include "libnm-systemd-shared/nm-sd-utils-shared.h"
-
#include "settings/nm-settings-plugin.h"
#include "settings/nm-settings-storage.h"
#include "settings/nm-settings-utils.h"
@@ -1247,9 +1245,9 @@ nms_keyfile_plugin_init(NMSKeyfilePlugin *plugin)
/* dirname_libs are a set of read-only directories with lower priority than /etc or /run.
* There is nothing complicated about having multiple of such directories, so dirname_libs
* is a list (which currently only has at most one directory). */
- priv->dirname_libs[0] = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_LIB));
+ priv->dirname_libs[0] = nm_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_LIB));
priv->dirname_libs[1] = NULL;
- priv->dirname_run = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_RUN));
+ priv->dirname_run = nm_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_RUN));
priv->dirname_etc = nm_config_data_get_value(NM_CONFIG_GET_DATA_ORIG,
NM_CONFIG_KEYFILE_GROUP_KEYFILE,
NM_CONFIG_KEYFILE_KEY_KEYFILE_PATH,
@@ -1262,9 +1260,9 @@ nms_keyfile_plugin_init(NMSKeyfilePlugin *plugin)
} else if (!priv->dirname_etc || priv->dirname_etc[0] != '/') {
/* either invalid path or unspecified. Use the default. */
g_free(priv->dirname_etc);
- priv->dirname_etc = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_ETC_DEFAULT));
+ priv->dirname_etc = nm_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_ETC_DEFAULT));
} else
- nm_sd_utils_path_simplify(priv->dirname_etc);
+ nm_path_simplify(priv->dirname_etc);
/* no duplicates */
if (NM_IN_STRSET(priv->dirname_libs[0], priv->dirname_etc, priv->dirname_run))
diff --git a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c
index 11a8e4169c..b24acc45af 100644
--- a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c
+++ b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c
@@ -1924,6 +1924,7 @@ test_write_bridge_main(void)
gs_unref_object NMConnection *connection = NULL;
NMSettingConnection *s_con;
NMSettingBridge *s_bridge;
+ NMSettingWired *s_wired;
NMSettingIPConfig *s_ip4;
NMSettingIPConfig *s_ip6;
@@ -1953,6 +1954,11 @@ test_write_bridge_main(void)
g_assert(s_bridge);
nm_connection_add_setting(connection, NM_SETTING(s_bridge));
+ /* Ethernet setting */
+ s_wired = (NMSettingWired *) nm_setting_wired_new();
+ g_assert(s_wired);
+ nm_connection_add_setting(connection, NM_SETTING(s_wired));
+
/* IP4 setting */
s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new();
g_assert(s_ip4);
diff --git a/src/core/tests/test-core.c b/src/core/tests/test-core.c
index b4e1c4d5f3..11a7f32349 100644
--- a/src/core/tests/test-core.c
+++ b/src/core/tests/test-core.c
@@ -15,7 +15,6 @@
#include "NetworkManagerUtils.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "nm-core-utils.h"
-#include "libnm-systemd-core/nm-sd-utils-core.h"
#include "dns/nm-dns-manager.h"
#include "nm-connectivity.h"
@@ -2314,7 +2313,6 @@ test_dns_create_resolv_conf(void)
static void
test_machine_id_read(void)
{
- NMUuid machine_id_sd;
const NMUuid *machine_id;
char machine_id_str[33];
gpointer logstate;
@@ -2346,27 +2344,6 @@ test_machine_id_read(void)
== machine_id_str);
g_assert(strlen(machine_id_str) == 32);
g_assert_cmpstr(machine_id_str, ==, nm_utils_machine_id_str());
-
- /* double check with systemd's implementation... */
- if (!nm_sd_utils_id128_get_machine(&machine_id_sd)) {
- /* if systemd failed to read /etc/machine-id, the file likely
- * is invalid. Our machine-id is fake, and we have nothing to
- * compare against. */
-
- if (g_file_test(LOCALSTATEDIR "/lib/dbus/machine-id", G_FILE_TEST_EXISTS)) {
- /* Hm. So systemd failed to read /etc/machine-id, but we may have the one from D-Bus.
- * With LOCALSTATEDIR"/lib/dbus/machine-id", we don't really know whether we
- * parsed that file. Assume we don't know and skip the test on this system. */
- g_assert(!nm_utils_machine_id_is_fake());
- return;
- }
-
- /* OK, in this case, our function should have generated a random machine ID. */
- g_assert(nm_utils_machine_id_is_fake());
- } else {
- g_assert(!nm_utils_machine_id_is_fake());
- g_assert_cmpmem(&machine_id_sd, sizeof(NMUuid), machine_id, 16);
- }
}
/*****************************************************************************/
diff --git a/src/core/tests/test-systemd.c b/src/core/tests/test-systemd.c
index 71a6a60df1..cf31ec33cc 100644
--- a/src/core/tests/test-systemd.c
+++ b/src/core/tests/test-systemd.c
@@ -13,27 +13,6 @@
/*****************************************************************************/
static void
-test_dhcp_create(void)
-{
- sd_dhcp_client *client4 = NULL;
- int r;
-
- r = sd_dhcp_client_new(&client4, FALSE);
- g_assert(r == 0);
- g_assert(client4);
-
- if (/* never true */ client4 == (gpointer) &r) {
- /* we don't want to call this, but ensure that the linker
- * includes all these symbols. */
- sd_dhcp_client_start(client4);
- }
-
- sd_dhcp_client_unref(client4);
-}
-
-/*****************************************************************************/
-
-static void
test_lldp_create(void)
{
sd_lldp_rx *lldp = NULL;
@@ -119,141 +98,6 @@ test_sd_event(void)
/*****************************************************************************/
-static void
-test_path_equal(void)
-{
-#define _path_equal_check(path, expected) \
- G_STMT_START \
- { \
- const char *_path0 = (path); \
- const char *_expected = (expected); \
- gs_free char *_path = g_strdup(_path0); \
- const char *_path_result; \
- \
- _path_result = nm_sd_utils_path_simplify(_path); \
- g_assert(_path_result == _path); \
- g_assert_cmpstr(_path, ==, _expected); \
- } \
- G_STMT_END
-
- _path_equal_check("", "");
- _path_equal_check(".", ".");
- _path_equal_check("..", "..");
- _path_equal_check("/..", "/..");
- _path_equal_check("//..", "/..");
- _path_equal_check("/.", "/");
- _path_equal_check("./", ".");
- _path_equal_check("./.", ".");
- _path_equal_check(".///.", ".");
- _path_equal_check(".///./", ".");
- _path_equal_check(".////", ".");
- _path_equal_check("//..//foo/", "/../foo");
- _path_equal_check("///foo//./bar/.", "/foo/bar");
- _path_equal_check(".//./foo//./bar/.", "foo/bar");
-}
-
-/*****************************************************************************/
-
-static void
-_test_unbase64char(char ch, gboolean maybe_invalid)
-{
- int r;
-
- r = nm_sd_utils_unbase64char(ch, FALSE);
-
- if (ch == '=') {
- g_assert(!maybe_invalid);
- g_assert_cmpint(r, <, 0);
- g_assert_cmpint(nm_sd_utils_unbase64char(ch, TRUE), ==, G_MAXINT);
- } else {
- g_assert_cmpint(r, ==, nm_sd_utils_unbase64char(ch, TRUE));
- if (r >= 0)
- g_assert_cmpint(r, <=, 255);
- if (!maybe_invalid)
- g_assert_cmpint(r, >=, 0);
- }
-}
-
-static void
-_test_unbase64mem_mem(const char *base64, const guint8 *expected_arr, gsize expected_len)
-{
- gs_free char *expected_base64 = NULL;
- int r;
- nm_auto_free guint8 *exp2_arr = NULL;
- nm_auto_free guint8 *exp3_arr = NULL;
- gsize exp2_len;
- gsize exp3_len;
- gsize i;
-
- expected_base64 = g_base64_encode(expected_arr, expected_len);
-
- for (i = 0; expected_base64[i]; i++)
- _test_unbase64char(expected_base64[i], FALSE);
-
- r = nm_sd_utils_unbase64mem(expected_base64,
- strlen(expected_base64),
- TRUE,
- &exp2_arr,
- &exp2_len);
- g_assert_cmpint(r, ==, 0);
- g_assert_cmpmem(expected_arr, expected_len, exp2_arr, exp2_len);
-
- if (!nm_streq(base64, expected_base64)) {
- r = nm_sd_utils_unbase64mem(base64, strlen(base64), TRUE, &exp3_arr, &exp3_len);
- g_assert_cmpint(r, ==, 0);
- g_assert_cmpmem(expected_arr, expected_len, exp3_arr, exp3_len);
- }
-}
-
-#define _test_unbase64mem(base64, expected_str) \
- _test_unbase64mem_mem(base64, (const guint8 *) "" expected_str "", NM_STRLEN(expected_str))
-
-static void
-_test_unbase64mem_inval(const char *base64)
-{
- gs_free guint8 *exp_arr = NULL;
- gsize exp_len = 0;
- int r;
-
- r = nm_sd_utils_unbase64mem(base64, strlen(base64), TRUE, &exp_arr, &exp_len);
- g_assert_cmpint(r, <, 0);
- g_assert(!exp_arr);
- g_assert(exp_len == 0);
-}
-
-static void
-test_nm_sd_utils_unbase64mem(void)
-{
- gs_free char *rnd_base64 = NULL;
- guint8 rnd_buf[30];
- guint i, rnd_len;
-
- _test_unbase64mem("", "");
- _test_unbase64mem(" ", "");
- _test_unbase64mem(" Y Q == ", "a");
- _test_unbase64mem(" Y WJjZGV mZ 2g = ", "abcdefgh");
- _test_unbase64mem_inval(" Y %WJjZGV mZ 2g = ");
- _test_unbase64mem_inval(" Y %WJjZGV mZ 2g = a");
- _test_unbase64mem("YQ==", "a");
- _test_unbase64mem_inval("YQ==a");
-
- rnd_len = nmtst_get_rand_uint32() % sizeof(rnd_buf);
- for (i = 0; i < rnd_len; i++)
- rnd_buf[i] = nmtst_get_rand_uint32() % 256;
- rnd_base64 = g_base64_encode(rnd_buf, rnd_len);
- _test_unbase64mem_mem(rnd_base64, rnd_buf, rnd_len);
-
- _test_unbase64char('=', FALSE);
- for (i = 0; i < 10; i++) {
- char ch = nmtst_get_rand_uint32() % 256;
-
- if (ch != '=')
- _test_unbase64char(ch, TRUE);
- }
-}
-
-/*****************************************************************************/
-
NMTST_DEFINE();
int
@@ -261,11 +105,8 @@ main(int argc, char **argv)
{
nmtst_init(&argc, &argv, TRUE);
- g_test_add_func("/systemd/dhcp/create", test_dhcp_create);
g_test_add_func("/systemd/lldp/create", test_lldp_create);
g_test_add_func("/systemd/sd-event", test_sd_event);
- g_test_add_func("/systemd/test_path_equal", test_path_equal);
- g_test_add_func("/systemd/test_nm_sd_utils_unbase64mem", test_nm_sd_utils_unbase64mem);
return g_test_run();
}
diff --git a/src/core/tests/test-utils.c b/src/core/tests/test-utils.c
index ad9950ddb4..2bcb6f6946 100644
--- a/src/core/tests/test-utils.c
+++ b/src/core/tests/test-utils.c
@@ -234,8 +234,10 @@ test_shorten_hostname(void)
* system configuration (`getconf HOST_NAME_MAX`). On Linux
* it's typically 64 characters, but POSIX allows up to
* 255 characters.
+ *
+ * We use our own define NM_HOST_NAME_MAX, which is always 64.
*/
- maxhost = g_strnfill(HOST_NAME_MAX, 'a');
+ maxhost = g_strnfill(NM_HOST_NAME_MAX, 'a');
do_test_shorten_hostname("name1", TRUE, NULL);
diff --git a/src/libnm-client-impl/nm-client.c b/src/libnm-client-impl/nm-client.c
index b18f47be32..f7bd2db545 100644
--- a/src/libnm-client-impl/nm-client.c
+++ b/src/libnm-client-impl/nm-client.c
@@ -20,6 +20,7 @@
#include "nm-checkpoint.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "nm-dbus-helpers.h"
+#include "nm-wifi-p2p-peer.h"
#include "nm-device-6lowpan.h"
#include "nm-device-adsl.h"
#include "nm-device-bond.h"
@@ -33,7 +34,6 @@
#include "nm-device-macsec.h"
#include "nm-device-macvlan.h"
#include "nm-device-modem.h"
-#include "nm-device-olpc-mesh.h"
#include "nm-device-ovs-bridge.h"
#include "nm-device-ovs-interface.h"
#include "nm-device-ovs-port.h"
@@ -46,6 +46,7 @@
#include "nm-device-wifi.h"
#include "nm-device-wireguard.h"
#include "nm-device-wpan.h"
+#include "nm-device-olpc-mesh.h"
#include "nm-dhcp-config.h"
#include "nm-dhcp4-config.h"
#include "nm-dhcp6-config.h"
@@ -56,7 +57,6 @@
#include "nm-remote-connection.h"
#include "nm-utils.h"
#include "nm-vpn-connection.h"
-#include "nm-wifi-p2p-peer.h"
/*****************************************************************************/
@@ -8399,9 +8399,9 @@ nm_client_class_init(NMClientClass *client_class)
*
* Whether a connectivity checking service has been enabled.
*
- * Since: 1.10
- *
* The property setter is a synchronous D-Bus call. This is deprecated since 1.22.
+ *
+ * Since: 1.10
*/
obj_properties[PROP_CONNECTIVITY_CHECK_ENABLED] =
g_param_spec_boolean(NM_CLIENT_CONNECTIVITY_CHECK_ENABLED,
@@ -8729,7 +8729,7 @@ nm_client_class_init(NMClientClass *client_class)
G_TYPE_UINT);
/**
* NMClient::connection-added:
- * @client: the settings object that received the signal
+ * @client: the client that received the signal
* @connection: the new connection
*
* Notifies that a #NMConnection has been added.
@@ -8747,7 +8747,7 @@ nm_client_class_init(NMClientClass *client_class)
/**
* NMClient::connection-removed:
- * @client: the settings object that received the signal
+ * @client: the client that received the signal
* @connection: the removed connection
*
* Notifies that a #NMConnection has been removed.
@@ -8765,7 +8765,7 @@ nm_client_class_init(NMClientClass *client_class)
/**
* NMClient::active-connection-added:
- * @client: the settings object that received the signal
+ * @client: the client that received the signal
* @active_connection: the new active connection
*
* Notifies that a #NMActiveConnection has been added.
@@ -8783,7 +8783,7 @@ nm_client_class_init(NMClientClass *client_class)
/**
* NMClient::active-connection-removed:
- * @client: the settings object that received the signal
+ * @client: the client that received the signal
* @active_connection: the removed active connection
*
* Notifies that a #NMActiveConnection has been removed.
diff --git a/src/libnm-client-impl/nm-default-libnm.h b/src/libnm-client-impl/nm-default-libnm.h
index 5b3a8e5179..859766a301 100644
--- a/src/libnm-client-impl/nm-default-libnm.h
+++ b/src/libnm-client-impl/nm-default-libnm.h
@@ -16,6 +16,16 @@
/*****************************************************************************/
#include "nm-version.h"
+#include "nm-dbus-interface.h"
+#include "nm-dhcp-config.h"
+#include "nm-ip-config.h"
+#include "nm-connection.h"
+#include "nm-remote-connection.h"
+#include "nm-active-connection.h"
+#include "nm-device.h"
+#include "nm-checkpoint.h"
+#include "nm-client.h"
+#include "nm-vpn-connection.h"
#include "nm-libnm-utils.h"
/*****************************************************************************/
diff --git a/src/libnm-client-impl/nm-device-macvlan.c b/src/libnm-client-impl/nm-device-macvlan.c
index a8363c930c..be6d56e44c 100644
--- a/src/libnm-client-impl/nm-device-macvlan.c
+++ b/src/libnm-client-impl/nm-device-macvlan.c
@@ -120,11 +120,11 @@ nm_device_macvlan_get_tap(NMDeviceMacvlan *device)
* Returns: the hardware address. This is the internal string used by the
* device, and must not be modified.
*
- * Since: 1.2
- *
* This property is not implemented yet, and the function always return NULL.
*
* Deprecated: 1.24: Use nm_device_get_hw_address() instead.
+ *
+ * Since: 1.2
**/
const char *
nm_device_macvlan_get_hw_address(NMDeviceMacvlan *device)
diff --git a/src/libnm-client-impl/nm-device-olpc-mesh.c b/src/libnm-client-impl/nm-device-olpc-mesh.c
index 26fceb3bd5..38f9e472c8 100644
--- a/src/libnm-client-impl/nm-device-olpc-mesh.c
+++ b/src/libnm-client-impl/nm-device-olpc-mesh.c
@@ -5,12 +5,13 @@
#include "libnm-client-impl/nm-default-libnm.h"
+#include "nm-access-point.h"
+#include "nm-device-wifi.h"
#include "nm-device-olpc-mesh.h"
#include "nm-setting-connection.h"
#include "nm-setting-olpc-mesh.h"
#include "nm-object-private.h"
-#include "nm-device-wifi.h"
/*****************************************************************************/
diff --git a/src/libnm-client-impl/nm-device-vxlan.c b/src/libnm-client-impl/nm-device-vxlan.c
index d7bd9cbe94..d81b551601 100644
--- a/src/libnm-client-impl/nm-device-vxlan.c
+++ b/src/libnm-client-impl/nm-device-vxlan.c
@@ -96,10 +96,10 @@ nm_device_vxlan_get_hw_address(NMDeviceVxlan *device)
*
* Returns: %TRUE if the device has carrier.
*
- * Since: 1.2
- *
* This property is not implemented yet, and the function always returns
* FALSE.
+ *
+ * Since: 1.2
**/
gboolean
nm_device_vxlan_get_carrier(NMDeviceVxlan *device)
@@ -541,9 +541,9 @@ nm_device_vxlan_class_init(NMDeviceVxlanClass *klass)
*
* Whether the device has carrier.
*
- * Since: 1.2
- *
* This property is not implemented yet, and the property is always FALSE.
+ *
+ * Since: 1.2
**/
obj_properties[PROP_CARRIER] = g_param_spec_boolean(NM_DEVICE_VXLAN_CARRIER,
"",
diff --git a/src/libnm-client-impl/nm-device-wifi-p2p.c b/src/libnm-client-impl/nm-device-wifi-p2p.c
index fb72f25052..6e667ac61a 100644
--- a/src/libnm-client-impl/nm-device-wifi-p2p.c
+++ b/src/libnm-client-impl/nm-device-wifi-p2p.c
@@ -5,13 +5,13 @@
#include "libnm-client-impl/nm-default-libnm.h"
+#include "nm-wifi-p2p-peer.h"
#include "nm-device-wifi-p2p.h"
#include "libnm-glib-aux/nm-dbus-aux.h"
#include "nm-setting-connection.h"
#include "nm-setting-wifi-p2p.h"
#include "nm-utils.h"
-#include "nm-wifi-p2p-peer.h"
#include "nm-object-private.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "nm-dbus-helpers.h"
diff --git a/src/libnm-client-impl/nm-device-wifi.c b/src/libnm-client-impl/nm-device-wifi.c
index b062ea9e04..616aca5008 100644
--- a/src/libnm-client-impl/nm-device-wifi.c
+++ b/src/libnm-client-impl/nm-device-wifi.c
@@ -6,6 +6,7 @@
#include "libnm-client-impl/nm-default-libnm.h"
+#include "nm-access-point.h"
#include "nm-device-wifi.h"
#include <linux/if_ether.h>
@@ -15,7 +16,6 @@
#include "nm-setting-wireless.h"
#include "nm-setting-wireless-security.h"
#include "nm-utils.h"
-#include "nm-access-point.h"
#include "nm-object-private.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "nm-dbus-helpers.h"
diff --git a/src/libnm-client-impl/nm-device-wimax.c b/src/libnm-client-impl/nm-device-wimax.c
index b9db20bb67..cdbe7fbc2f 100644
--- a/src/libnm-client-impl/nm-device-wimax.c
+++ b/src/libnm-client-impl/nm-device-wimax.c
@@ -6,9 +6,8 @@
#include "libnm-client-impl/nm-default-libnm.h"
-#include "nm-device-wimax.h"
-
#include "nm-wimax-nsp.h"
+#include "nm-device-wimax.h"
/*****************************************************************************/
diff --git a/src/libnm-client-impl/nm-libnm-utils.h b/src/libnm-client-impl/nm-libnm-utils.h
index db5f31ea5a..9d9cfa2530 100644
--- a/src/libnm-client-impl/nm-libnm-utils.h
+++ b/src/libnm-client-impl/nm-libnm-utils.h
@@ -7,12 +7,8 @@
#define __NM_LIBNM_UTILS_H__
#include "c-list/src/c-list.h"
-#include "nm-device.h"
#include "libnm-glib-aux/nm-ref-string.h"
#include "libnm-glib-aux/nm-logging-fwd.h"
-#include "nm-types.h"
-#include "nm-object.h"
-#include "nm-client.h"
/*****************************************************************************/
diff --git a/src/libnm-client-public/NetworkManager.h b/src/libnm-client-public/NetworkManager.h
index 66f676a111..de3c7821ff 100644
--- a/src/libnm-client-public/NetworkManager.h
+++ b/src/libnm-client-public/NetworkManager.h
@@ -8,48 +8,19 @@
#define __NETWORKMANAGER_H_INSIDE__
-#include "nm-access-point.h"
-#include "nm-active-connection.h"
-#include "nm-client.h"
-#include "nm-connection.h"
-#include "nm-core-enum-types.h"
+#include <gio/gio.h>
+
+#include "nm-version.h"
#include "nm-dbus-interface.h"
-#include "nm-device-6lowpan.h"
-#include "nm-device-adsl.h"
-#include "nm-device-bond.h"
-#include "nm-device-bridge.h"
-#include "nm-device-bt.h"
-#include "nm-device-dummy.h"
-#include "nm-device-ethernet.h"
-#include "nm-device-generic.h"
-#include "nm-device-infiniband.h"
-#include "nm-device-ip-tunnel.h"
-#include "nm-device-macsec.h"
-#include "nm-device-macvlan.h"
-#include "nm-device-modem.h"
-#include "nm-device-olpc-mesh.h"
-#include "nm-device-ovs-bridge.h"
-#include "nm-device-ovs-interface.h"
-#include "nm-device-ovs-port.h"
-#include "nm-device-ppp.h"
-#include "nm-device-team.h"
-#include "nm-device-tun.h"
-#include "nm-device-veth.h"
-#include "nm-device-vlan.h"
-#include "nm-device-vxlan.h"
-#include "nm-device-wifi-p2p.h"
-#include "nm-device-wifi.h"
-#include "nm-device-wimax.h"
-#include "nm-device-wireguard.h"
-#include "nm-device-wpan.h"
-#include "nm-device.h"
-#include "nm-dhcp-config.h"
-#include "nm-enum-types.h"
-#include "nm-ethtool-utils.h"
-#include "nm-ip-config.h"
+
+#include "nm-core-enum-types.h"
+
+#include "nm-connection.h"
+#include "nm-simple-connection.h"
#include "nm-keyfile.h"
-#include "nm-object.h"
-#include "nm-remote-connection.h"
+#include "nm-setting.h"
+#include "nm-utils.h"
+
#include "nm-setting-6lowpan.h"
#include "nm-setting-8021x.h"
#include "nm-setting-adsl.h"
@@ -102,18 +73,59 @@
#include "nm-setting-wireless.h"
#include "nm-setting-wireless-security.h"
#include "nm-setting-wpan.h"
-#include "nm-setting.h"
-#include "nm-simple-connection.h"
-#include "nm-utils.h"
-#include "nm-version.h"
-#include "nm-vpn-connection.h"
+
#include "nm-vpn-dbus-interface.h"
-#include "nm-vpn-editor.h"
-#include "nm-vpn-editor-plugin.h"
#include "nm-vpn-plugin-info.h"
-#include "nm-vpn-service-plugin.h"
+#include "nm-vpn-editor-plugin.h"
+
+#include "nm-enum-types.h"
+
+#include "nm-ethtool-utils.h"
+
+#include "nm-object.h"
+#include "nm-dhcp-config.h"
+#include "nm-ip-config.h"
+#include "nm-remote-connection.h"
+#include "nm-active-connection.h"
+#include "nm-checkpoint.h"
+#include "nm-access-point.h"
#include "nm-wifi-p2p-peer.h"
#include "nm-wimax-nsp.h"
+#include "nm-device.h"
+#include "nm-vpn-connection.h"
+#include "nm-vpn-editor.h"
+#include "nm-vpn-service-plugin.h"
+
+#include "nm-client.h"
+
+#include "nm-device-6lowpan.h"
+#include "nm-device-adsl.h"
+#include "nm-device-bond.h"
+#include "nm-device-bridge.h"
+#include "nm-device-bt.h"
+#include "nm-device-dummy.h"
+#include "nm-device-ethernet.h"
+#include "nm-device-generic.h"
+#include "nm-device-infiniband.h"
+#include "nm-device-ip-tunnel.h"
+#include "nm-device-macsec.h"
+#include "nm-device-macvlan.h"
+#include "nm-device-modem.h"
+#include "nm-device-ovs-bridge.h"
+#include "nm-device-ovs-interface.h"
+#include "nm-device-ovs-port.h"
+#include "nm-device-ppp.h"
+#include "nm-device-team.h"
+#include "nm-device-tun.h"
+#include "nm-device-veth.h"
+#include "nm-device-vlan.h"
+#include "nm-device-vxlan.h"
+#include "nm-device-wifi.h"
+#include "nm-device-wifi-p2p.h"
+#include "nm-device-olpc-mesh.h"
+#include "nm-device-wimax.h"
+#include "nm-device-wireguard.h"
+#include "nm-device-wpan.h"
#include "nm-autoptr.h"
diff --git a/src/libnm-client-public/meson.build b/src/libnm-client-public/meson.build
index 3ae4e8d83f..f76fd1868f 100644
--- a/src/libnm-client-public/meson.build
+++ b/src/libnm-client-public/meson.build
@@ -45,7 +45,6 @@ libnm_client_headers = files(
'nm-object.h',
'nm-remote-connection.h',
'nm-secret-agent-old.h',
- 'nm-types.h',
'nm-vpn-connection.h',
'nm-vpn-editor.h',
'nm-vpn-plugin-old.h',
diff --git a/src/libnm-client-public/nm-access-point.h b/src/libnm-client-public/nm-access-point.h
index 9f9216bb59..5a78e34f73 100644
--- a/src/libnm-client-public/nm-access-point.h
+++ b/src/libnm-client-public/nm-access-point.h
@@ -42,6 +42,7 @@ G_BEGIN_DECLS
/**
* NMAccessPoint:
*/
+typedef struct _NMAccessPoint NMAccessPoint;
typedef struct _NMAccessPointClass NMAccessPointClass;
GType nm_access_point_get_type(void);
diff --git a/src/libnm-client-public/nm-active-connection.h b/src/libnm-client-public/nm-active-connection.h
index a65b4f20f7..5c3148269a 100644
--- a/src/libnm-client-public/nm-active-connection.h
+++ b/src/libnm-client-public/nm-active-connection.h
@@ -46,6 +46,7 @@ G_BEGIN_DECLS
/**
* NMActiveConnection:
*/
+typedef struct _NMActiveConnection NMActiveConnection;
typedef struct _NMActiveConnectionClass NMActiveConnectionClass;
GType nm_active_connection_get_type(void);
@@ -61,14 +62,18 @@ NM_AVAILABLE_IN_1_10
NMActivationStateFlags nm_active_connection_get_state_flags(NMActiveConnection *connection);
NM_AVAILABLE_IN_1_8
NMActiveConnectionStateReason nm_active_connection_get_state_reason(NMActiveConnection *connection);
-NMDevice *nm_active_connection_get_master(NMActiveConnection *connection);
-gboolean nm_active_connection_get_default(NMActiveConnection *connection);
-NMIPConfig *nm_active_connection_get_ip4_config(NMActiveConnection *connection);
-NMDhcpConfig *nm_active_connection_get_dhcp4_config(NMActiveConnection *connection);
-gboolean nm_active_connection_get_default6(NMActiveConnection *connection);
-NMIPConfig *nm_active_connection_get_ip6_config(NMActiveConnection *connection);
-NMDhcpConfig *nm_active_connection_get_dhcp6_config(NMActiveConnection *connection);
-gboolean nm_active_connection_get_vpn(NMActiveConnection *connection);
+
+struct _NMDevice;
+
+struct _NMDevice *nm_active_connection_get_master(NMActiveConnection *connection);
+
+gboolean nm_active_connection_get_default(NMActiveConnection *connection);
+NMIPConfig *nm_active_connection_get_ip4_config(NMActiveConnection *connection);
+NMDhcpConfig *nm_active_connection_get_dhcp4_config(NMActiveConnection *connection);
+gboolean nm_active_connection_get_default6(NMActiveConnection *connection);
+NMIPConfig *nm_active_connection_get_ip6_config(NMActiveConnection *connection);
+NMDhcpConfig *nm_active_connection_get_dhcp6_config(NMActiveConnection *connection);
+gboolean nm_active_connection_get_vpn(NMActiveConnection *connection);
G_END_DECLS
diff --git a/src/libnm-client-public/nm-checkpoint.h b/src/libnm-client-public/nm-checkpoint.h
index def1f5544c..456d7f6bdc 100644
--- a/src/libnm-client-public/nm-checkpoint.h
+++ b/src/libnm-client-public/nm-checkpoint.h
@@ -30,6 +30,7 @@ G_BEGIN_DECLS
/**
* NMCheckpoint:
*/
+typedef struct _NMCheckpoint NMCheckpoint;
typedef struct _NMCheckpointClass NMCheckpointClass;
GType nm_checkpoint_get_type(void);
diff --git a/src/libnm-client-public/nm-client.h b/src/libnm-client-public/nm-client.h
index 2e3e77c43c..6307f11217 100644
--- a/src/libnm-client-public/nm-client.h
+++ b/src/libnm-client-public/nm-client.h
@@ -11,8 +11,6 @@
#error "Only <NetworkManager.h> can be included directly."
#endif
-#include "nm-types.h"
-
G_BEGIN_DECLS
/**
@@ -148,6 +146,7 @@ gboolean nm_dns_entry_get_vpn(NMDnsEntry *entry);
* D-Bus signals gets processed and the #NMClient instance updates and
* emits #GObject signals.
*/
+typedef struct _NMClient NMClient;
typedef struct _NMClientClass NMClientClass;
GType nm_client_get_type(void);
diff --git a/src/libnm-client-public/nm-device-6lowpan.h b/src/libnm-client-public/nm-device-6lowpan.h
index 2388bf3816..d5f8a7a5c1 100644
--- a/src/libnm-client-public/nm-device-6lowpan.h
+++ b/src/libnm-client-public/nm-device-6lowpan.h
@@ -30,6 +30,7 @@ G_BEGIN_DECLS
/**
* NMDevice6Lowpan:
*/
+typedef struct _NMDevice6Lowpan NMDevice6Lowpan;
typedef struct _NMDevice6LowpanClass NMDevice6LowpanClass;
NM_AVAILABLE_IN_1_14
diff --git a/src/libnm-client-public/nm-device-adsl.h b/src/libnm-client-public/nm-device-adsl.h
index fa8a127899..a4fbec51db 100644
--- a/src/libnm-client-public/nm-device-adsl.h
+++ b/src/libnm-client-public/nm-device-adsl.h
@@ -28,6 +28,7 @@ G_BEGIN_DECLS
/**
* NMDeviceAdsl:
*/
+typedef struct _NMDeviceAdsl NMDeviceAdsl;
typedef struct _NMDeviceAdslClass NMDeviceAdslClass;
GType nm_device_adsl_get_type(void);
diff --git a/src/libnm-client-public/nm-device-bond.h b/src/libnm-client-public/nm-device-bond.h
index 19e0e04638..6edc6106f6 100644
--- a/src/libnm-client-public/nm-device-bond.h
+++ b/src/libnm-client-public/nm-device-bond.h
@@ -30,6 +30,7 @@ G_BEGIN_DECLS
/**
* NMDeviceBond:
*/
+typedef struct _NMDeviceBond NMDeviceBond;
typedef struct _NMDeviceBondClass NMDeviceBondClass;
GType nm_device_bond_get_type(void);
diff --git a/src/libnm-client-public/nm-device-bridge.h b/src/libnm-client-public/nm-device-bridge.h
index 07905195b7..e37400221b 100644
--- a/src/libnm-client-public/nm-device-bridge.h
+++ b/src/libnm-client-public/nm-device-bridge.h
@@ -31,6 +31,7 @@ G_BEGIN_DECLS
/**
* NMDeviceBridge:
*/
+typedef struct _NMDeviceBridge NMDeviceBridge;
typedef struct _NMDeviceBridgeClass NMDeviceBridgeClass;
GType nm_device_bridge_get_type(void);
diff --git a/src/libnm-client-public/nm-device-bt.h b/src/libnm-client-public/nm-device-bt.h
index c277bae99b..fa8d730815 100644
--- a/src/libnm-client-public/nm-device-bt.h
+++ b/src/libnm-client-public/nm-device-bt.h
@@ -31,6 +31,7 @@ G_BEGIN_DECLS
/**
* NMDeviceBt:
*/
+typedef struct _NMDeviceBt NMDeviceBt;
typedef struct _NMDeviceBtClass NMDeviceBtClass;
GType nm_device_bt_get_type(void);
diff --git a/src/libnm-client-public/nm-device-dummy.h b/src/libnm-client-public/nm-device-dummy.h
index d5b8cb2428..8b2f748577 100644
--- a/src/libnm-client-public/nm-device-dummy.h
+++ b/src/libnm-client-public/nm-device-dummy.h
@@ -29,6 +29,7 @@ G_BEGIN_DECLS
/**
* NMDeviceDummy:
*/
+typedef struct _NMDeviceDummy NMDeviceDummy;
typedef struct _NMDeviceDummyClass NMDeviceDummyClass;
GType nm_device_dummy_get_type(void);
diff --git a/src/libnm-client-public/nm-device-ethernet.h b/src/libnm-client-public/nm-device-ethernet.h
index 636e5eb57a..828865c7f9 100644
--- a/src/libnm-client-public/nm-device-ethernet.h
+++ b/src/libnm-client-public/nm-device-ethernet.h
@@ -35,6 +35,7 @@ G_BEGIN_DECLS
/**
* NMDeviceEthernet:
*/
+typedef struct _NMDeviceEthernet NMDeviceEthernet;
typedef struct _NMDeviceEthernetClass NMDeviceEthernetClass;
GType nm_device_ethernet_get_type(void);
diff --git a/src/libnm-client-public/nm-device-generic.h b/src/libnm-client-public/nm-device-generic.h
index 7b543b2ff6..ff24c6f10c 100644
--- a/src/libnm-client-public/nm-device-generic.h
+++ b/src/libnm-client-public/nm-device-generic.h
@@ -30,6 +30,7 @@ G_BEGIN_DECLS
/**
* NMDeviceGeneric:
*/
+typedef struct _NMDeviceGeneric NMDeviceGeneric;
typedef struct _NMDeviceGenericClass NMDeviceGenericClass;
GType nm_device_generic_get_type(void);
diff --git a/src/libnm-client-public/nm-device-infiniband.h b/src/libnm-client-public/nm-device-infiniband.h
index 3999b2d560..53b16176ec 100644
--- a/src/libnm-client-public/nm-device-infiniband.h
+++ b/src/libnm-client-public/nm-device-infiniband.h
@@ -31,6 +31,7 @@ G_BEGIN_DECLS
/**
* NMDeviceInfiniband:
*/
+typedef struct _NMDeviceInfiniband NMDeviceInfiniband;
typedef struct _NMDeviceInfinibandClass NMDeviceInfinibandClass;
GType nm_device_infiniband_get_type(void);
diff --git a/src/libnm-client-public/nm-device-ip-tunnel.h b/src/libnm-client-public/nm-device-ip-tunnel.h
index d79127298b..4f55dc0bd4 100644
--- a/src/libnm-client-public/nm-device-ip-tunnel.h
+++ b/src/libnm-client-public/nm-device-ip-tunnel.h
@@ -42,6 +42,7 @@ G_BEGIN_DECLS
/**
* NMDeviceIPTunnel:
*/
+typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel;
typedef struct _NMDeviceIPTunnelClass NMDeviceIPTunnelClass;
NM_AVAILABLE_IN_1_2
diff --git a/src/libnm-client-public/nm-device-macsec.h b/src/libnm-client-public/nm-device-macsec.h
index e468344fbb..b1ec363713 100644
--- a/src/libnm-client-public/nm-device-macsec.h
+++ b/src/libnm-client-public/nm-device-macsec.h
@@ -42,6 +42,7 @@ G_BEGIN_DECLS
/**
* NMDeviceMacsec:
*/
+typedef struct _NMDeviceMacsec NMDeviceMacsec;
typedef struct _NMDeviceMacsecClass NMDeviceMacsecClass;
NM_AVAILABLE_IN_1_6
diff --git a/src/libnm-client-public/nm-device-macvlan.h b/src/libnm-client-public/nm-device-macvlan.h
index ec7eb640a7..9569933418 100644
--- a/src/libnm-client-public/nm-device-macvlan.h
+++ b/src/libnm-client-public/nm-device-macvlan.h
@@ -33,6 +33,7 @@ G_BEGIN_DECLS
/**
* NMDeviceMacvlan:
*/
+typedef struct _NMDeviceMacvlan NMDeviceMacvlan;
typedef struct _NMDeviceMacvlanClass NMDeviceMacvlanClass;
NM_AVAILABLE_IN_1_2
diff --git a/src/libnm-client-public/nm-device-modem.h b/src/libnm-client-public/nm-device-modem.h
index f9dfc34815..4ef175728a 100644
--- a/src/libnm-client-public/nm-device-modem.h
+++ b/src/libnm-client-public/nm-device-modem.h
@@ -34,6 +34,7 @@ G_BEGIN_DECLS
/**
* NMDeviceModem:
*/
+typedef struct _NMDeviceModem NMDeviceModem;
typedef struct _NMDeviceModemClass NMDeviceModemClass;
GType nm_device_modem_get_type(void);
diff --git a/src/libnm-client-public/nm-device-olpc-mesh.h b/src/libnm-client-public/nm-device-olpc-mesh.h
index 86ac2ce706..ea3a309619 100644
--- a/src/libnm-client-public/nm-device-olpc-mesh.h
+++ b/src/libnm-client-public/nm-device-olpc-mesh.h
@@ -32,6 +32,7 @@ G_BEGIN_DECLS
/**
* NMDeviceOlpcMesh:
*/
+typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh;
typedef struct _NMDeviceOlpcMeshClass NMDeviceOlpcMeshClass;
GType nm_device_olpc_mesh_get_type(void);
diff --git a/src/libnm-client-public/nm-device-ovs-bridge.h b/src/libnm-client-public/nm-device-ovs-bridge.h
index f0ef154728..8c45405776 100644
--- a/src/libnm-client-public/nm-device-ovs-bridge.h
+++ b/src/libnm-client-public/nm-device-ovs-bridge.h
@@ -30,6 +30,7 @@ G_BEGIN_DECLS
/**
* NMDeviceOvsBridge:
*/
+typedef struct _NMDeviceOvsBridge NMDeviceOvsBridge;
typedef struct _NMDeviceOvsBridgeClass NMDeviceOvsBridgeClass;
NM_AVAILABLE_IN_1_10
diff --git a/src/libnm-client-public/nm-device-ovs-interface.h b/src/libnm-client-public/nm-device-ovs-interface.h
index 12b30a75b5..1ba7ac3a4c 100644
--- a/src/libnm-client-public/nm-device-ovs-interface.h
+++ b/src/libnm-client-public/nm-device-ovs-interface.h
@@ -29,6 +29,7 @@ G_BEGIN_DECLS
/**
* NMDeviceOvsInterface:
*/
+typedef struct _NMDeviceOvsInterface NMDeviceOvsInterface;
typedef struct _NMDeviceOvsInterfaceClass NMDeviceOvsInterfaceClass;
NM_AVAILABLE_IN_1_10
diff --git a/src/libnm-client-public/nm-device-ovs-port.h b/src/libnm-client-public/nm-device-ovs-port.h
index 170067f9cc..7524cacb55 100644
--- a/src/libnm-client-public/nm-device-ovs-port.h
+++ b/src/libnm-client-public/nm-device-ovs-port.h
@@ -30,6 +30,7 @@ G_BEGIN_DECLS
/**
* NMDeviceOvsPort:
*/
+typedef struct _NMDeviceOvsPort NMDeviceOvsPort;
typedef struct _NMDeviceOvsPortClass NMDeviceOvsPortClass;
NM_AVAILABLE_IN_1_10
diff --git a/src/libnm-client-public/nm-device-ppp.h b/src/libnm-client-public/nm-device-ppp.h
index ff99d9f974..4003f901c8 100644
--- a/src/libnm-client-public/nm-device-ppp.h
+++ b/src/libnm-client-public/nm-device-ppp.h
@@ -24,6 +24,7 @@ G_BEGIN_DECLS
/**
* NMDevicePpp:
*/
+typedef struct _NMDevicePpp NMDevicePpp;
typedef struct _NMDevicePppClass NMDevicePppClass;
GType nm_device_ppp_get_type(void);
diff --git a/src/libnm-client-public/nm-device-team.h b/src/libnm-client-public/nm-device-team.h
index eab5e4e6b4..406949a109 100644
--- a/src/libnm-client-public/nm-device-team.h
+++ b/src/libnm-client-public/nm-device-team.h
@@ -31,6 +31,7 @@ G_BEGIN_DECLS
/**
* NMDeviceTeam:
*/
+typedef struct _NMDeviceTeam NMDeviceTeam;
typedef struct _NMDeviceTeamClass NMDeviceTeamClass;
GType nm_device_team_get_type(void);
diff --git a/src/libnm-client-public/nm-device-tun.h b/src/libnm-client-public/nm-device-tun.h
index cc05b0c16f..e1e7310d37 100644
--- a/src/libnm-client-public/nm-device-tun.h
+++ b/src/libnm-client-public/nm-device-tun.h
@@ -34,6 +34,7 @@ G_BEGIN_DECLS
/**
* NMDeviceTun:
*/
+typedef struct _NMDeviceTun NMDeviceTun;
typedef struct _NMDeviceTunClass NMDeviceTunClass;
NM_AVAILABLE_IN_1_2
diff --git a/src/libnm-client-public/nm-device-veth.h b/src/libnm-client-public/nm-device-veth.h
index 41b419156e..8f61ae2052 100644
--- a/src/libnm-client-public/nm-device-veth.h
+++ b/src/libnm-client-public/nm-device-veth.h
@@ -28,6 +28,7 @@ G_BEGIN_DECLS
/**
* NMDeviceVeth:
*/
+typedef struct _NMDeviceVeth NMDeviceVeth;
typedef struct _NMDeviceVethClass NMDeviceVethClass;
NM_AVAILABLE_IN_1_30
diff --git a/src/libnm-client-public/nm-device-vlan.h b/src/libnm-client-public/nm-device-vlan.h
index c392058695..c74453fdbd 100644
--- a/src/libnm-client-public/nm-device-vlan.h
+++ b/src/libnm-client-public/nm-device-vlan.h
@@ -31,6 +31,7 @@ G_BEGIN_DECLS
/**
* NMDeviceVlan:
*/
+typedef struct _NMDeviceVlan NMDeviceVlan;
typedef struct _NMDeviceVlanClass NMDeviceVlanClass;
GType nm_device_vlan_get_type(void);
diff --git a/src/libnm-client-public/nm-device-vrf.h b/src/libnm-client-public/nm-device-vrf.h
index 3b59023acc..fbc8b20224 100644
--- a/src/libnm-client-public/nm-device-vrf.h
+++ b/src/libnm-client-public/nm-device-vrf.h
@@ -25,6 +25,7 @@ G_BEGIN_DECLS
/**
* NMDeviceVrf:
*/
+typedef struct _NMDeviceVrf NMDeviceVrf;
typedef struct _NMDeviceVrfClass NMDeviceVrfClass;
NM_AVAILABLE_IN_1_24
diff --git a/src/libnm-client-public/nm-device-vxlan.h b/src/libnm-client-public/nm-device-vxlan.h
index 5264e9caf5..7939539d61 100644
--- a/src/libnm-client-public/nm-device-vxlan.h
+++ b/src/libnm-client-public/nm-device-vxlan.h
@@ -46,6 +46,7 @@ G_BEGIN_DECLS
/**
* NMDeviceVxlan:
*/
+typedef struct _NMDeviceVxlan NMDeviceVxlan;
typedef struct _NMDeviceVxlanClass NMDeviceVxlanClass;
NM_AVAILABLE_IN_1_2
diff --git a/src/libnm-client-public/nm-device-wifi-p2p.h b/src/libnm-client-public/nm-device-wifi-p2p.h
index cf68b496b9..ad0ca43664 100644
--- a/src/libnm-client-public/nm-device-wifi-p2p.h
+++ b/src/libnm-client-public/nm-device-wifi-p2p.h
@@ -34,6 +34,7 @@ G_BEGIN_DECLS
*
* Since: 1.16
*/
+typedef struct _NMDeviceWifiP2P NMDeviceWifiP2P;
typedef struct _NMDeviceWifiP2PClass NMDeviceWifiP2PClass;
NM_AVAILABLE_IN_1_16
diff --git a/src/libnm-client-public/nm-device-wifi.h b/src/libnm-client-public/nm-device-wifi.h
index 1c767316ae..287b792e80 100644
--- a/src/libnm-client-public/nm-device-wifi.h
+++ b/src/libnm-client-public/nm-device-wifi.h
@@ -36,6 +36,7 @@ G_BEGIN_DECLS
/**
* NMDeviceWifi:
*/
+typedef struct _NMDeviceWifi NMDeviceWifi;
typedef struct _NMDeviceWifiClass NMDeviceWifiClass;
GType nm_device_wifi_get_type(void);
diff --git a/src/libnm-client-public/nm-device-wimax.h b/src/libnm-client-public/nm-device-wimax.h
index 123b95b26c..e62288192c 100644
--- a/src/libnm-client-public/nm-device-wimax.h
+++ b/src/libnm-client-public/nm-device-wimax.h
@@ -39,6 +39,7 @@ G_BEGIN_DECLS
*
* Deprecated: 1.22: WiMAX is no longer supported by NetworkManager since 1.2.0.
*/
+typedef struct _NMDeviceWimax NMDeviceWimax;
typedef struct _NMDeviceWimaxClass NMDeviceWimaxClass;
NM_DEPRECATED_IN_1_2
diff --git a/src/libnm-client-public/nm-device-wireguard.h b/src/libnm-client-public/nm-device-wireguard.h
index 4a18bd8117..756dfb4e46 100644
--- a/src/libnm-client-public/nm-device-wireguard.h
+++ b/src/libnm-client-public/nm-device-wireguard.h
@@ -28,6 +28,7 @@ G_BEGIN_DECLS
/**
* NMDeviceWireGuard:
*/
+typedef struct _NMDeviceWireGuard NMDeviceWireGuard;
typedef struct _NMDeviceWireGuardClass NMDeviceWireGuardClass;
#define NM_DEVICE_WIREGUARD_PUBLIC_KEY "public-key"
diff --git a/src/libnm-client-public/nm-device-wpan.h b/src/libnm-client-public/nm-device-wpan.h
index b8a7a3bf85..8b011851b1 100644
--- a/src/libnm-client-public/nm-device-wpan.h
+++ b/src/libnm-client-public/nm-device-wpan.h
@@ -28,6 +28,7 @@ G_BEGIN_DECLS
/**
* NMDeviceWpan:
*/
+typedef struct _NMDeviceWpan NMDeviceWpan;
typedef struct _NMDeviceWpanClass NMDeviceWpanClass;
NM_AVAILABLE_IN_1_14
diff --git a/src/libnm-client-public/nm-device.h b/src/libnm-client-public/nm-device.h
index 9e9dbea64d..f58d3ddba8 100644
--- a/src/libnm-client-public/nm-device.h
+++ b/src/libnm-client-public/nm-device.h
@@ -62,6 +62,7 @@ _NM_DEPRECATED_SYNC_WRITABLE_PROPERTY
/**
* NMDevice:
*/
+typedef struct _NMDevice NMDevice;
typedef struct _NMDeviceClass NMDeviceClass;
/**
diff --git a/src/libnm-client-public/nm-dhcp-config.h b/src/libnm-client-public/nm-dhcp-config.h
index 0188f9c23e..625efb5844 100644
--- a/src/libnm-client-public/nm-dhcp-config.h
+++ b/src/libnm-client-public/nm-dhcp-config.h
@@ -25,6 +25,7 @@ G_BEGIN_DECLS
/**
* NMDhcpConfig:
*/
+typedef struct _NMDhcpConfig NMDhcpConfig;
typedef struct _NMDhcpConfigClass NMDhcpConfigClass;
#define NM_DHCP_CONFIG_FAMILY "family"
diff --git a/src/libnm-client-public/nm-enum-types.c.template b/src/libnm-client-public/nm-enum-types.c.template
index c2627f447d..5d693fe3e6 100644
--- a/src/libnm-client-public/nm-enum-types.c.template
+++ b/src/libnm-client-public/nm-enum-types.c.template
@@ -5,45 +5,9 @@
#include "nm-version-macros.h"
#include "NetworkManager.h"
-#include "nm-access-point.h"
-#include "nm-active-connection.h"
-#include "nm-checkpoint.h"
-#include "nm-client.h"
-#include "nm-device-adsl.h"
-#include "nm-device-bond.h"
-#include "nm-device-bridge.h"
-#include "nm-device-bt.h"
-#include "nm-device-dummy.h"
-#include "nm-device-ethernet.h"
-#include "nm-device-generic.h"
-#include "nm-device-infiniband.h"
-#include "nm-device-ip-tunnel.h"
-#include "nm-device-macsec.h"
-#include "nm-device-macvlan.h"
-#include "nm-device-modem.h"
-#include "nm-device-olpc-mesh.h"
-#include "nm-device-ovs-interface.h"
-#include "nm-device-ovs-port.h"
-#include "nm-device-ovs-bridge.h"
-#include "nm-device-ppp.h"
-#include "nm-device-team.h"
-#include "nm-device-tun.h"
-#include "nm-device-vlan.h"
-#include "nm-device-vxlan.h"
-#include "nm-device-wifi.h"
-#include "nm-device-wimax.h"
-#include "nm-device.h"
-#include "nm-dhcp-config.h"
-#include "nm-ip-config.h"
-#include "nm-object.h"
-#include "nm-remote-connection.h"
-#include "nm-types.h"
-#include "nm-vpn-connection.h"
-#include "nm-vpn-editor.h"
-#include "nm-wimax-nsp.h"
#include "nm-secret-agent-old.h"
#include "nm-vpn-plugin-old.h"
-#include "nm-vpn-service-plugin.h"
+
/*** END file-header ***/
/*** BEGIN value-header ***/
diff --git a/src/libnm-client-public/nm-ip-config.h b/src/libnm-client-public/nm-ip-config.h
index 99b1948dbe..9ad15d30dc 100644
--- a/src/libnm-client-public/nm-ip-config.h
+++ b/src/libnm-client-public/nm-ip-config.h
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
/**
* NMIPConfig:
*/
+typedef struct _NMIPConfig NMIPConfig;
typedef struct _NMIPConfigClass NMIPConfigClass;
#define NM_IP_CONFIG_FAMILY "family"
diff --git a/src/libnm-client-public/nm-object.h b/src/libnm-client-public/nm-object.h
index efa3aa536a..c6daf1e6ca 100644
--- a/src/libnm-client-public/nm-object.h
+++ b/src/libnm-client-public/nm-object.h
@@ -11,8 +11,6 @@
#error "Only <NetworkManager.h> can be included directly."
#endif
-#include "nm-types.h"
-
G_BEGIN_DECLS
#define NM_TYPE_OBJECT (nm_object_get_type())
@@ -28,14 +26,17 @@ G_BEGIN_DECLS
/**
* NMObject:
*/
+typedef struct _NMObject NMObject;
typedef struct _NMObjectClass NMObjectClass;
GType nm_object_get_type(void);
const char *nm_object_get_path(NMObject *object);
+struct _NMClient;
+
NM_AVAILABLE_IN_1_24
-NMClient *nm_object_get_client(NMObject *object);
+struct _NMClient *nm_object_get_client(NMObject *object);
G_END_DECLS
diff --git a/src/libnm-client-public/nm-remote-connection.h b/src/libnm-client-public/nm-remote-connection.h
index 6104ecb817..f00b25d613 100644
--- a/src/libnm-client-public/nm-remote-connection.h
+++ b/src/libnm-client-public/nm-remote-connection.h
@@ -37,6 +37,7 @@ G_BEGIN_DECLS
/**
* NMRemoteConnection:
*/
+typedef struct _NMRemoteConnection NMRemoteConnection;
typedef struct _NMRemoteConnectionClass NMRemoteConnectionClass;
GType nm_remote_connection_get_type(void);
diff --git a/src/libnm-client-public/nm-secret-agent-old.h b/src/libnm-client-public/nm-secret-agent-old.h
index b45b12bb6a..ca7bfa4cc9 100644
--- a/src/libnm-client-public/nm-secret-agent-old.h
+++ b/src/libnm-client-public/nm-secret-agent-old.h
@@ -6,8 +6,6 @@
#ifndef __NM_SECRET_AGENT_OLD_H__
#define __NM_SECRET_AGENT_OLD_H__
-#include "nm-types.h"
-
G_BEGIN_DECLS
#define NM_TYPE_SECRET_AGENT_OLD (nm_secret_agent_old_get_type())
diff --git a/src/libnm-client-public/nm-types.h b/src/libnm-client-public/nm-types.h
deleted file mode 100644
index 81ffe790d5..0000000000
--- a/src/libnm-client-public/nm-types.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2014 - 2018 Red Hat, Inc.
- */
-
-#ifndef __NM_TYPES_H__
-#define __NM_TYPES_H__
-
-#include <gio/gio.h>
-
-#include "nm-dbus-interface.h"
-#include "nm-connection.h"
-
-typedef struct _NMAccessPoint NMAccessPoint;
-typedef struct _NMActiveConnection NMActiveConnection;
-typedef struct _NMCheckpoint NMCheckpoint;
-typedef struct _NMClient NMClient;
-typedef struct _NMDevice NMDevice;
-typedef struct _NMDevice6Lowpan NMDevice6Lowpan;
-typedef struct _NMDeviceAdsl NMDeviceAdsl;
-typedef struct _NMDeviceBond NMDeviceBond;
-typedef struct _NMDeviceBridge NMDeviceBridge;
-typedef struct _NMDeviceBt NMDeviceBt;
-typedef struct _NMDeviceDummy NMDeviceDummy;
-typedef struct _NMDeviceEthernet NMDeviceEthernet;
-typedef struct _NMDeviceGeneric NMDeviceGeneric;
-typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel;
-typedef struct _NMDeviceInfiniband NMDeviceInfiniband;
-typedef struct _NMDeviceMacsec NMDeviceMacsec;
-typedef struct _NMDeviceMacvlan NMDeviceMacvlan;
-typedef struct _NMDeviceModem NMDeviceModem;
-typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh;
-typedef struct _NMDeviceOvsBridge NMDeviceOvsBridge;
-typedef struct _NMDeviceOvsInterface NMDeviceOvsInterface;
-typedef struct _NMDeviceOvsPort NMDeviceOvsPort;
-typedef struct _NMDevicePpp NMDevicePpp;
-typedef struct _NMDeviceTeam NMDeviceTeam;
-typedef struct _NMDeviceTun NMDeviceTun;
-typedef struct _NMDeviceVeth NMDeviceVeth;
-typedef struct _NMDeviceVlan NMDeviceVlan;
-typedef struct _NMDeviceVrf NMDeviceVrf;
-typedef struct _NMDeviceVxlan NMDeviceVxlan;
-typedef struct _NMDeviceWifi NMDeviceWifi;
-typedef struct _NMDeviceWifiP2P NMDeviceWifiP2P;
-typedef struct _NMDeviceWimax NMDeviceWimax;
-typedef struct _NMDeviceWireGuard NMDeviceWireGuard;
-typedef struct _NMDeviceWpan NMDeviceWpan;
-typedef struct _NMDhcpConfig NMDhcpConfig;
-typedef struct _NMIPConfig NMIPConfig;
-typedef struct _NMObject NMObject;
-typedef struct _NMRemoteConnection NMRemoteConnection;
-typedef struct _NMVpnConnection NMVpnConnection;
-typedef struct _NMWifiP2PPeer NMWifiP2PPeer;
-typedef struct _NMWimaxNsp NMWimaxNsp;
-
-#endif /* NM_TYPES_H */
diff --git a/src/libnm-client-public/nm-vpn-connection.h b/src/libnm-client-public/nm-vpn-connection.h
index 33ca139d20..578c033349 100644
--- a/src/libnm-client-public/nm-vpn-connection.h
+++ b/src/libnm-client-public/nm-vpn-connection.h
@@ -32,6 +32,7 @@ G_BEGIN_DECLS
/**
* NMVpnConnection:
*/
+typedef struct _NMVpnConnection NMVpnConnection;
typedef struct _NMVpnConnectionClass NMVpnConnectionClass;
GType nm_vpn_connection_get_type(void);
diff --git a/src/libnm-client-public/nm-vpn-editor.h b/src/libnm-client-public/nm-vpn-editor.h
index f89617a897..9c4facb2b1 100644
--- a/src/libnm-client-public/nm-vpn-editor.h
+++ b/src/libnm-client-public/nm-vpn-editor.h
@@ -13,7 +13,6 @@
#include <glib.h>
#include <glib-object.h>
-#include "nm-types.h"
#include "nm-vpn-editor-plugin.h"
diff --git a/src/libnm-client-public/nm-vpn-plugin-old.h b/src/libnm-client-public/nm-vpn-plugin-old.h
index 7704c1539e..fe0d4bc2cd 100644
--- a/src/libnm-client-public/nm-vpn-plugin-old.h
+++ b/src/libnm-client-public/nm-vpn-plugin-old.h
@@ -32,7 +32,7 @@ G_BEGIN_DECLS
typedef struct {
NM_DEPRECATED_IN_1_2
GObject parent;
-} NMVpnPluginOld NM_DEPRECATED_IN_1_2;
+} NMVpnPluginOld;
typedef struct {
NM_DEPRECATED_IN_1_2
@@ -85,7 +85,7 @@ typedef struct {
/*< private >*/
NM_DEPRECATED_IN_1_2
gpointer padding[8];
-} NMVpnPluginOldClass NM_DEPRECATED_IN_1_2;
+} NMVpnPluginOldClass;
NM_DEPRECATED_IN_1_2
GType nm_vpn_plugin_old_get_type(void);
diff --git a/src/libnm-client-public/nm-vpn-service-plugin.h b/src/libnm-client-public/nm-vpn-service-plugin.h
index 81fb6730ae..5187d93d43 100644
--- a/src/libnm-client-public/nm-vpn-service-plugin.h
+++ b/src/libnm-client-public/nm-vpn-service-plugin.h
@@ -39,7 +39,7 @@ G_BEGIN_DECLS
typedef struct {
NM_AVAILABLE_IN_1_2
GObject parent;
-} NMVpnServicePlugin NM_AVAILABLE_IN_1_2;
+} NMVpnServicePlugin;
typedef struct {
NM_AVAILABLE_IN_1_2
@@ -92,7 +92,7 @@ typedef struct {
/*< private >*/
NM_AVAILABLE_IN_1_2
gpointer padding[8];
-} NMVpnServicePluginClass NM_AVAILABLE_IN_1_2;
+} NMVpnServicePluginClass;
NM_AVAILABLE_IN_1_2
GType nm_vpn_service_plugin_get_type(void);
diff --git a/src/libnm-client-public/nm-wifi-p2p-peer.h b/src/libnm-client-public/nm-wifi-p2p-peer.h
index 73e6995cd2..eff27bcbb9 100644
--- a/src/libnm-client-public/nm-wifi-p2p-peer.h
+++ b/src/libnm-client-public/nm-wifi-p2p-peer.h
@@ -38,6 +38,7 @@ G_BEGIN_DECLS
/**
* NMWifiP2PPeer:
*/
+typedef struct _NMWifiP2PPeer NMWifiP2PPeer;
typedef struct _NMWifiP2PPeerClass NMWifiP2PPeerClass;
NM_AVAILABLE_IN_1_16
diff --git a/src/libnm-client-public/nm-wimax-nsp.h b/src/libnm-client-public/nm-wimax-nsp.h
index f19272db5a..9cd4153ccb 100644
--- a/src/libnm-client-public/nm-wimax-nsp.h
+++ b/src/libnm-client-public/nm-wimax-nsp.h
@@ -33,6 +33,7 @@ G_BEGIN_DECLS
*
* Deprecated: 1.22: WiMAX is no longer supported by NetworkManager since 1.2.0.
*/
+typedef struct _NMWimaxNsp NMWimaxNsp;
typedef struct _NMWimaxNspClass NMWimaxNspClass;
GType nm_wimax_nsp_get_type(void);
diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c
index 27cea2cb2b..aed4be2113 100644
--- a/src/libnm-core-impl/nm-connection.c
+++ b/src/libnm-core-impl/nm-connection.c
@@ -1708,7 +1708,7 @@ _normalize_required_settings(NMConnection *self)
NMSetting *s_bridge;
gboolean changed = FALSE;
- if (nm_connection_get_setting_vlan(self)) {
+ if (nm_connection_get_setting_vlan(self) || nm_connection_get_setting_bridge(self)) {
if (!nm_connection_get_setting_wired(self)) {
nm_connection_add_setting(self, nm_setting_wired_new());
changed = TRUE;
@@ -3168,22 +3168,24 @@ nm_connection_get_virtual_device_description(NMConnection *connection)
iface = nm_connection_get_interface_name(connection);
- if (!strcmp(type, NM_SETTING_BOND_SETTING_NAME))
+ if (nm_streq(type, NM_SETTING_BOND_SETTING_NAME))
display_type = _("Bond");
- else if (!strcmp(type, NM_SETTING_TEAM_SETTING_NAME))
+ else if (nm_streq(type, NM_SETTING_TEAM_SETTING_NAME))
display_type = _("Team");
- else if (!strcmp(type, NM_SETTING_BRIDGE_SETTING_NAME))
+ else if (nm_streq(type, NM_SETTING_BRIDGE_SETTING_NAME))
display_type = _("Bridge");
- else if (!strcmp(type, NM_SETTING_VLAN_SETTING_NAME))
+ else if (nm_streq(type, NM_SETTING_VLAN_SETTING_NAME))
display_type = _("VLAN");
- else if (!strcmp(type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
+ else if (nm_streq(type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
display_type = _("InfiniBand");
iface = nm_setting_infiniband_get_virtual_interface_name(
nm_connection_get_setting_infiniband(connection));
- } else if (!strcmp(type, NM_SETTING_IP_TUNNEL_SETTING_NAME))
+ } else if (nm_streq(type, NM_SETTING_IP_TUNNEL_SETTING_NAME))
display_type = _("IP Tunnel");
- else if (!strcmp(type, NM_SETTING_WIREGUARD_SETTING_NAME))
+ else if (nm_streq(type, NM_SETTING_WIREGUARD_SETTING_NAME))
display_type = _("WireGuard");
+ else if (nm_streq(type, NM_SETTING_TUN_SETTING_NAME))
+ display_type = _("TUN/TAP");
if (!iface || !display_type)
return NULL;
diff --git a/src/libnm-core-impl/nm-keyfile-utils.c b/src/libnm-core-impl/nm-keyfile-utils.c
index c599aefa7b..95073bcc93 100644
--- a/src/libnm-core-impl/nm-keyfile-utils.c
+++ b/src/libnm-core-impl/nm-keyfile-utils.c
@@ -210,7 +210,7 @@ nm_keyfile_plugin_kf_set_integer_list_uint(GKeyFile *kf,
g_return_if_fail(group && group[0]);
g_return_if_fail(key && key[0]);
- nm_str_buf_init(&strbuf, length * 4u + 2u, FALSE);
+ strbuf = NM_STR_BUF_INIT(length * 4u + 2u, FALSE);
for (i = 0; i < length; i++)
nm_str_buf_append_printf(&strbuf, "%u;", data[i]);
nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf));
@@ -231,7 +231,7 @@ nm_keyfile_plugin_kf_set_integer_list_uint8(GKeyFile *kf,
g_return_if_fail(group && group[0]);
g_return_if_fail(key && key[0]);
- nm_str_buf_init(&strbuf, length * 4u + 2u, FALSE);
+ strbuf = NM_STR_BUF_INIT(length * 4u + 2u, FALSE);
for (i = 0; i < length; i++)
nm_str_buf_append_printf(&strbuf, "%u;", (guint) data[i]);
nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf));
@@ -542,7 +542,7 @@ _keyfile_key_encode(const char *name, char **out_to_free)
len = i + strlen(&name[i]);
nm_assert(len == strlen(name));
- nm_str_buf_init(&str, len + 15u, FALSE);
+ str = NM_STR_BUF_INIT(len + 15u, FALSE);
if (name[0] == ' ') {
nm_assert(i == 0);
diff --git a/src/libnm-core-impl/nm-keyfile.c b/src/libnm-core-impl/nm-keyfile.c
index 00fb8a335d..76d15cb1a0 100644
--- a/src/libnm-core-impl/nm-keyfile.c
+++ b/src/libnm-core-impl/nm-keyfile.c
@@ -21,7 +21,6 @@
#include "libnm-glib-aux/nm-uuid.h"
#include "libnm-glib-aux/nm-str-buf.h"
#include "libnm-glib-aux/nm-secret-utils.h"
-#include "libnm-systemd-shared/nm-sd-utils-shared.h"
#include "libnm-core-aux-intern/nm-common-macros.h"
#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
#include "libnm-core-intern/nm-core-internal.h"
@@ -4062,7 +4061,7 @@ _write_setting_wireguard(NMSetting *setting, KeyfileWriterInfo *info)
public_key = nm_wireguard_peer_get_public_key(peer);
if (!public_key || !public_key[0]
- || !NM_STRCHAR_ALL(public_key, ch, nm_sd_utils_unbase64char(ch, TRUE) >= 0)) {
+ || !NM_STRCHAR_ALL(public_key, ch, nm_unbase64char(ch) != -EINVAL)) {
/* invalid peer. Skip it */
continue;
}
@@ -4375,7 +4374,7 @@ nm_keyfile_utils_create_filename(const char *name, gboolean with_extension)
g_return_val_if_fail(name && name[0], NULL);
- nm_str_buf_init(&str, 0, FALSE);
+ str = NM_STR_BUF_INIT(0, FALSE);
len = strlen(name);
diff --git a/src/libnm-core-impl/nm-setting-bond.c b/src/libnm-core-impl/nm-setting-bond.c
index ae2fe051b2..2984e6fc22 100644
--- a/src/libnm-core-impl/nm-setting-bond.c
+++ b/src/libnm-core-impl/nm-setting-bond.c
@@ -362,15 +362,6 @@ _bond_get_option_normalized(NMSettingBond *self, const char *option, gboolean ge
return _bond_get_option_or_default(self, option);
}
-const char *
-nm_setting_bond_get_option_or_default(NMSettingBond *self, const char *option)
-{
- g_return_val_if_fail(NM_IS_SETTING_BOND(self), NULL);
- g_return_val_if_fail(option, NULL);
-
- return _bond_get_option_normalized(self, option, FALSE);
-}
-
static int
_atoi(const char *value)
{
diff --git a/src/libnm-core-impl/nm-setting-bridge.c b/src/libnm-core-impl/nm-setting-bridge.c
index 41cd6632f2..39a3fb6017 100644
--- a/src/libnm-core-impl/nm-setting-bridge.c
+++ b/src/libnm-core-impl/nm-setting-bridge.c
@@ -435,7 +435,7 @@ nm_bridge_vlan_to_str(const NMBridgeVlan *vlan, GError **error)
* future if more parameters are added to the object that could
* make it invalid. */
- nm_str_buf_init(&string, NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE);
+ string = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE);
if (vlan->vid_start == vlan->vid_end)
nm_str_buf_append_printf(&string, "%u", vlan->vid_start);
@@ -1311,6 +1311,15 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
NM_SETTING_BRIDGE_VLANS))
return NM_SETTING_VERIFY_NORMALIZABLE;
+ if (connection && !nm_connection_get_setting_wired(connection)) {
+ g_set_error_literal(error,
+ NM_CONNECTION_ERROR,
+ NM_CONNECTION_ERROR_SETTING_NOT_FOUND,
+ _("bridge connection should have a ethernet setting as well"));
+ g_prefix_error(error, "%s: ", NM_SETTING_BRIDGE_SETTING_NAME);
+ return NM_SETTING_VERIFY_NORMALIZABLE;
+ }
+
return TRUE;
}
diff --git a/src/libnm-core-impl/nm-setting-ethtool.c b/src/libnm-core-impl/nm-setting-ethtool.c
index 49c0d78097..71179efd39 100644
--- a/src/libnm-core-impl/nm-setting-ethtool.c
+++ b/src/libnm-core-impl/nm-setting-ethtool.c
@@ -45,11 +45,11 @@ get_variant_type_from_ethtool_id(NMEthtoolID ethtool_id)
*
* %Returns: %TRUE, if @optname is valid
*
- * Since: 1.20
- *
* Note that nm_ethtool_optname_is_feature() was first added to the libnm header files
* in 1.14.0 but forgot to actually add to the library. This happened belatedly in 1.20.0 and
* the stable versions 1.18.2, 1.16.4 and 1.14.8 (with linker version "libnm_1_14_8").
+ *
+ * Since: 1.20
*/
gboolean
nm_ethtool_optname_is_feature(const char *optname)
diff --git a/src/libnm-core-impl/nm-setting-ip-config.c b/src/libnm-core-impl/nm-setting-ip-config.c
index cffd5b19ff..1bad2e93b0 100644
--- a/src/libnm-core-impl/nm-setting-ip-config.c
+++ b/src/libnm-core-impl/nm-setting-ip-config.c
@@ -2481,10 +2481,10 @@ nm_ip_routing_rule_set_suppress_prefixlength(NMIPRoutingRule *self, gint32 suppr
*
* Returns: %TRUE if a uid range is set.
*
- * Since: 1.34
- *
* This API was wrongly introduced in the header files for 1.32, but the
* symbols were not exported. The API only works since 1.34 and newer.
+ *
+ * Since: 1.34
*/
gboolean
nm_ip_routing_rule_get_uid_range(const NMIPRoutingRule *self,
@@ -2509,10 +2509,10 @@ nm_ip_routing_rule_get_uid_range(const NMIPRoutingRule *self,
* For a valid range, start must be less or equal to end.
* If set to an invalid range, the range gets unset.
*
- * Since: 1.34
- *
* This API was wrongly introduced in the header files for 1.32, but the
* symbols were not exported. The API only works since 1.34 and newer.
+ *
+ * Since: 1.34
*/
void
nm_ip_routing_rule_set_uid_range(NMIPRoutingRule *self,
@@ -3814,7 +3814,7 @@ nm_ip_routing_rule_to_string(const NMIPRoutingRule *self,
}
}
- nm_str_buf_init(&str, NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE);
+ str = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE);
if (self->priority_has) {
nm_str_buf_append_printf(nm_str_buf_append_required_delimiter(&str, ' '),
diff --git a/src/libnm-core-impl/nm-utils.c b/src/libnm-core-impl/nm-utils.c
index d5d884f2e4..0d3f6a6fda 100644
--- a/src/libnm-core-impl/nm-utils.c
+++ b/src/libnm-core-impl/nm-utils.c
@@ -23,7 +23,6 @@
#include "libnm-glib-aux/nm-enum-utils.h"
#include "libnm-glib-aux/nm-time-utils.h"
#include "libnm-glib-aux/nm-secret-utils.h"
-#include "libnm-systemd-shared/nm-sd-utils-shared.h"
#include "libnm-core-aux-intern/nm-common-macros.h"
#include "nm-utils-private.h"
#include "nm-setting-private.h"
@@ -5356,7 +5355,7 @@ nm_utils_base64secret_decode(const char *base64_key, gsize required_key_len, gui
base64_key_len = strlen(base64_key);
- r = nm_sd_utils_unbase64mem(base64_key, base64_key_len, TRUE, &bin_arr, &bin_len);
+ r = nm_unbase64mem_full(base64_key, base64_key_len, TRUE, &bin_arr, &bin_len);
if (r < 0)
return FALSE;
if (bin_len != required_key_len) {
diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h
index 032f6a9a4c..f669bf8d80 100644
--- a/src/libnm-core-intern/nm-core-internal.h
+++ b/src/libnm-core-intern/nm-core-internal.h
@@ -491,8 +491,6 @@ typedef enum {
NMBondOptionType _nm_setting_bond_get_option_type(NMSettingBond *setting, const char *name);
-const char *nm_setting_bond_get_option_or_default(NMSettingBond *self, const char *option);
-
#define NM_BOND_AD_ACTOR_SYSTEM_DEFAULT "00:00:00:00:00:00"
/*****************************************************************************/
diff --git a/src/libnm-core-intern/nm-keyfile-utils.h b/src/libnm-core-intern/nm-keyfile-utils.h
index f79f020f67..08f169ac94 100644
--- a/src/libnm-core-intern/nm-keyfile-utils.h
+++ b/src/libnm-core-intern/nm-keyfile-utils.h
@@ -12,10 +12,6 @@
/*****************************************************************************/
-#include "libnm-glib-aux/nm-shared-utils.h"
-
-/*****************************************************************************/
-
#define NM_KEYFILE_GROUP_VPN_SECRETS "vpn-secrets"
#define NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER "wireguard-peer."
diff --git a/src/libnm-core-public/nm-version-macros.h.in b/src/libnm-core-public/nm-version-macros.h.in
index 516aded5e1..07e7989957 100644
--- a/src/libnm-core-public/nm-version-macros.h.in
+++ b/src/libnm-core-public/nm-version-macros.h.in
@@ -71,6 +71,7 @@
#define NM_VERSION_1_34 (NM_ENCODE_VERSION (1, 34, 0))
#define NM_VERSION_1_36 (NM_ENCODE_VERSION (1, 36, 0))
#define NM_VERSION_1_38 (NM_ENCODE_VERSION (1, 38, 0))
+#define NM_VERSION_1_40 (NM_ENCODE_VERSION (1, 40, 0))
/* For releases, NM_API_VERSION is equal to NM_VERSION.
*
diff --git a/src/libnm-core-public/nm-version.h b/src/libnm-core-public/nm-version.h
index ac98f86819..22a79382e0 100644
--- a/src/libnm-core-public/nm-version.h
+++ b/src/libnm-core-public/nm-version.h
@@ -327,6 +327,20 @@
#define NM_AVAILABLE_IN_1_38
#endif
+#if NM_VERSION_MIN_REQUIRED >= NM_VERSION_1_40
+#define NM_DEPRECATED_IN_1_40 G_DEPRECATED
+#define NM_DEPRECATED_IN_1_40_FOR(f) G_DEPRECATED_FOR(f)
+#else
+#define NM_DEPRECATED_IN_1_40
+#define NM_DEPRECATED_IN_1_40_FOR(f)
+#endif
+
+#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_40
+#define NM_AVAILABLE_IN_1_40 G_UNAVAILABLE(1, 40)
+#else
+#define NM_AVAILABLE_IN_1_40
+#endif
+
/*
* Synchronous API for calling D-Bus in libnm is deprecated. See
* https://developer.gnome.org/libnm/stable/usage.html#sync-api
diff --git a/src/libnm-glib-aux/nm-default-glib.h b/src/libnm-glib-aux/nm-default-glib.h
index 9d04ddc407..f39e16cc5b 100644
--- a/src/libnm-glib-aux/nm-default-glib.h
+++ b/src/libnm-glib-aux/nm-default-glib.h
@@ -33,27 +33,27 @@
#if NM_MORE_ASSERTS == 0
#ifndef G_DISABLE_CAST_CHECKS
/* Unless compiling with G_DISABLE_CAST_CHECKS, glib performs type checking
- * during G_VARIANT_TYPE() via g_variant_type_checked_(). This is not necessary
- * because commonly this cast is needed during something like
- *
- * g_variant_builder_init (&props, G_VARIANT_TYPE ("a{sv}"));
- *
- * Note that in if the variant type would be invalid, the check still
- * wouldn't make the buggy code magically work. Instead of passing a
- * bogus type string (bad), it would pass %NULL to g_variant_builder_init()
- * (also bad).
- *
- * Also, a function like g_variant_builder_init() already validates
- * the input type via something like
- *
- * g_return_if_fail (g_variant_type_is_container (type));
- *
- * So, by having G_VARIANT_TYPE() also validate the type, we validate
- * twice, whereas the first validation is rather pointless because it
- * doesn't prevent the function to be called with invalid arguments.
- *
- * Just patch G_VARIANT_TYPE() to perform no check.
- */
+ * during G_VARIANT_TYPE() via g_variant_type_checked_(). This is not necessary
+ * because commonly this cast is needed during something like
+ *
+ * g_variant_builder_init (&props, G_VARIANT_TYPE ("a{sv}"));
+ *
+ * Note that in if the variant type would be invalid, the check still
+ * wouldn't make the buggy code magically work. Instead of passing a
+ * bogus type string (bad), it would pass %NULL to g_variant_builder_init()
+ * (also bad).
+ *
+ * Also, a function like g_variant_builder_init() already validates
+ * the input type via something like
+ *
+ * g_return_if_fail (g_variant_type_is_container (type));
+ *
+ * So, by having G_VARIANT_TYPE() also validate the type, we validate
+ * twice, whereas the first validation is rather pointless because it
+ * doesn't prevent the function to be called with invalid arguments.
+ *
+ * Just patch G_VARIANT_TYPE() to perform no check.
+ */
#undef G_VARIANT_TYPE
#define G_VARIANT_TYPE(type_string) ((const GVariantType *) (type_string))
#endif
@@ -63,8 +63,6 @@
#include "nm-gassert-patch.h"
-#include "libnm-std-aux/nm-std-aux.h"
-#include "libnm-std-aux/nm-std-utils.h"
#include "libnm-glib-aux/nm-macros-internal.h"
#include "libnm-glib-aux/nm-shared-utils.h"
#include "libnm-glib-aux/nm-errno.h"
diff --git a/src/libnm-glib-aux/nm-enum-utils.c b/src/libnm-glib-aux/nm-enum-utils.c
index 3b9b7e8d13..b7f7a3f6cc 100644
--- a/src/libnm-glib-aux/nm-enum-utils.c
+++ b/src/libnm-glib-aux/nm-enum-utils.c
@@ -142,7 +142,7 @@ _nm_utils_enum_to_str_full(GType type,
flags_separator = flags_separator ?: " ";
- nm_str_buf_init(&strbuf, 16, FALSE);
+ strbuf = NM_STR_BUF_INIT(16, FALSE);
for (; value_infos && value_infos->nick; value_infos++) {
nm_assert(_enum_is_valid_flags_nick(value_infos->nick));
diff --git a/src/libnm-glib-aux/nm-io-utils.c b/src/libnm-glib-aux/nm-io-utils.c
index 503f044f30..0823a16c42 100644
--- a/src/libnm-glib-aux/nm-io-utils.c
+++ b/src/libnm-glib-aux/nm-io-utils.c
@@ -723,3 +723,288 @@ nm_sd_notify(const char *state)
return 0;
}
+
+/*****************************************************************************/
+
+#define SHELL_NEED_ESCAPE "\"\\`$"
+
+int
+nm_parse_env_file_full(
+ const char *contents,
+ int (*push)(unsigned line, const char *key, const char *value, void *userdata),
+ void *userdata)
+{
+ gsize last_value_whitespace = G_MAXSIZE;
+ gsize last_key_whitespace = G_MAXSIZE;
+ nm_auto_str_buf NMStrBuf key = NM_STR_BUF_INIT(0, FALSE);
+ nm_auto_str_buf NMStrBuf value = NM_STR_BUF_INIT(0, FALSE);
+ unsigned line = 1;
+ int r;
+ enum {
+ PRE_KEY,
+ KEY,
+ PRE_VALUE,
+ VALUE,
+ VALUE_ESCAPE,
+ SINGLE_QUOTE_VALUE,
+ DOUBLE_QUOTE_VALUE,
+ DOUBLE_QUOTE_VALUE_ESCAPE,
+ COMMENT,
+ COMMENT_ESCAPE
+ } state = PRE_KEY;
+
+ /* Copied and adjusted from systemd's parse_env_file_internal().
+ * https://github.com/systemd/systemd/blob/6247128902ca71ee2ad406cf69af04ea389d3d27/src/basic/env-file.c#L15 */
+
+ nm_assert(push);
+
+ if (!contents)
+ return -ENOENT;
+
+ for (const char *p = contents; *p; p++) {
+ char c = *p;
+
+ switch (state) {
+ case PRE_KEY:
+ if (NM_IN_SET(c, '#', ';'))
+ state = COMMENT;
+ else if (!nm_ascii_is_whitespace(c)) {
+ state = KEY;
+ last_key_whitespace = G_MAXSIZE;
+ nm_str_buf_append_c(&key, c);
+ }
+ break;
+
+ case KEY:
+ if (nm_ascii_is_newline(c)) {
+ state = PRE_KEY;
+ line++;
+ nm_str_buf_reset(&key);
+ } else if (c == '=') {
+ state = PRE_VALUE;
+ last_value_whitespace = G_MAXSIZE;
+ } else {
+ if (!nm_ascii_is_whitespace(c))
+ last_key_whitespace = G_MAXSIZE;
+ else if (last_key_whitespace == G_MAXSIZE)
+ last_key_whitespace = key.len;
+ nm_str_buf_append_c(&key, c);
+ }
+ break;
+
+ case PRE_VALUE:
+ if (nm_ascii_is_newline(c)) {
+ state = PRE_KEY;
+ line++;
+
+ /* strip trailing whitespace from key */
+ if (last_key_whitespace != G_MAXSIZE)
+ nm_str_buf_get_str_unsafe(&key)[last_key_whitespace] = 0;
+
+ r = push(line,
+ nm_str_buf_get_str(&key),
+ nm_str_buf_get_str(&value) ?: "",
+ userdata);
+ if (r < 0)
+ return r;
+
+ nm_str_buf_reset(&key);
+ nm_str_buf_reset(&value);
+ } else if (c == '\'')
+ state = SINGLE_QUOTE_VALUE;
+ else if (c == '"')
+ state = DOUBLE_QUOTE_VALUE;
+ else if (c == '\\')
+ state = VALUE_ESCAPE;
+ else if (!nm_ascii_is_whitespace(c)) {
+ state = VALUE;
+ nm_str_buf_append_c(&value, c);
+ }
+
+ break;
+
+ case VALUE:
+ if (nm_ascii_is_newline(c)) {
+ state = PRE_KEY;
+ line++;
+
+ /* Chomp off trailing whitespace from value */
+ if (last_value_whitespace != G_MAXSIZE)
+ nm_str_buf_get_str_unsafe(&value)[last_value_whitespace] = 0;
+
+ /* strip trailing whitespace from key */
+ if (last_key_whitespace != G_MAXSIZE)
+ nm_str_buf_get_str_unsafe(&key)[last_key_whitespace] = 0;
+
+ r = push(line,
+ nm_str_buf_get_str(&key),
+ nm_str_buf_get_str(&value) ?: "",
+ userdata);
+ if (r < 0)
+ return r;
+
+ nm_str_buf_reset(&key);
+ nm_str_buf_reset(&value);
+ } else if (c == '\\') {
+ state = VALUE_ESCAPE;
+ last_value_whitespace = G_MAXSIZE;
+ } else {
+ if (!nm_ascii_is_whitespace(c))
+ last_value_whitespace = G_MAXSIZE;
+ else if (last_value_whitespace == G_MAXSIZE)
+ last_value_whitespace = value.len;
+ nm_str_buf_append_c(&value, c);
+ }
+ break;
+
+ case VALUE_ESCAPE:
+ state = VALUE;
+ if (!nm_ascii_is_newline(c)) {
+ /* Escaped newlines we eat up entirely */
+ nm_str_buf_append_c(&value, c);
+ }
+ break;
+
+ case SINGLE_QUOTE_VALUE:
+ if (c == '\'')
+ state = PRE_VALUE;
+ else
+ nm_str_buf_append_c(&value, c);
+ break;
+
+ case DOUBLE_QUOTE_VALUE:
+ if (c == '"')
+ state = PRE_VALUE;
+ else if (c == '\\')
+ state = DOUBLE_QUOTE_VALUE_ESCAPE;
+ else
+ nm_str_buf_append_c(&value, c);
+ break;
+
+ case DOUBLE_QUOTE_VALUE_ESCAPE:
+ state = DOUBLE_QUOTE_VALUE;
+ if (strchr(SHELL_NEED_ESCAPE, c)) {
+ /* If this is a char that needs escaping, just unescape it. */
+ nm_str_buf_append_c(&value, c);
+ } else if (c != '\n') {
+ /* If other char than what needs escaping, keep the "\" in place, like the
+ * real shell does. */
+ nm_str_buf_append_c(&value, '\\', c);
+ }
+ /* Escaped newlines (aka "continuation lines") are eaten up entirely */
+ break;
+
+ case COMMENT:
+ if (c == '\\')
+ state = COMMENT_ESCAPE;
+ else if (nm_ascii_is_newline(c)) {
+ state = PRE_KEY;
+ line++;
+ }
+ break;
+
+ case COMMENT_ESCAPE:
+ state = COMMENT;
+ break;
+ }
+ }
+
+ if (NM_IN_SET(state,
+ PRE_VALUE,
+ VALUE,
+ VALUE_ESCAPE,
+ SINGLE_QUOTE_VALUE,
+ DOUBLE_QUOTE_VALUE,
+ DOUBLE_QUOTE_VALUE_ESCAPE)) {
+ if (state == VALUE)
+ if (last_value_whitespace != G_MAXSIZE)
+ nm_str_buf_get_str_unsafe(&value)[last_value_whitespace] = 0;
+
+ /* strip trailing whitespace from key */
+ if (last_key_whitespace != G_MAXSIZE)
+ nm_str_buf_get_str_unsafe(&key)[last_key_whitespace] = 0;
+
+ r = push(line, nm_str_buf_get_str(&key), nm_str_buf_get_str(&value) ?: "", userdata);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+
+static int
+check_utf8ness_and_warn(const char *key, const char *value)
+{
+ /* Taken from systemd's check_utf8ness_and_warn()
+ * https://github.com/systemd/systemd/blob/6247128902ca71ee2ad406cf69af04ea389d3d27/src/basic/env-file.c#L273 */
+
+ if (!g_utf8_validate(key, -1, NULL))
+ return -EINVAL;
+
+ if (!g_utf8_validate(value, -1, NULL))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
+parse_env_file_push(unsigned line, const char *key, const char *value, void *userdata)
+{
+ const char *k;
+ va_list *ap = userdata;
+ va_list aq;
+ int r;
+
+ r = check_utf8ness_and_warn(key, value);
+ if (r < 0)
+ return r;
+
+ va_copy(aq, *ap);
+
+ while ((k = va_arg(aq, const char *))) {
+ char **v;
+
+ v = va_arg(aq, char **);
+ if (nm_streq(key, k)) {
+ va_end(aq);
+ g_free(*v);
+ *v = g_strdup(value);
+ return 1;
+ }
+ }
+
+ va_end(aq);
+ return 0;
+}
+
+int
+nm_parse_env_filev(const char *contents, va_list ap)
+{
+ va_list aq;
+ int r;
+
+ /* Copied from systemd's parse_env_filev().
+ * https://github.com/systemd/systemd/blob/6247128902ca71ee2ad406cf69af04ea389d3d27/src/basic/env-file.c#L333 */
+
+ va_copy(aq, ap);
+ r = nm_parse_env_file_full(contents, parse_env_file_push, &aq);
+ va_end(aq);
+ return r;
+}
+
+int
+nm_parse_env_file_sentinel(const char *contents, ...)
+{
+ va_list ap;
+ int r;
+
+ /* Copied from systemd's parse_env_file_sentinel().
+ * https://github.com/systemd/systemd/blob/6247128902ca71ee2ad406cf69af04ea389d3d27/src/basic/env-file.c#L347 */
+
+ va_start(ap, contents);
+ r = nm_parse_env_filev(contents, ap);
+ va_end(ap);
+ return r;
+}
diff --git a/src/libnm-glib-aux/nm-io-utils.h b/src/libnm-glib-aux/nm-io-utils.h
index a850398679..ef015153ca 100644
--- a/src/libnm-glib-aux/nm-io-utils.h
+++ b/src/libnm-glib-aux/nm-io-utils.h
@@ -77,4 +77,15 @@ int nm_io_sockaddr_un_set(struct sockaddr_un *ret, NMOptionBool is_abstract, con
int nm_sd_notify(const char *state);
+/*****************************************************************************/
+
+int nm_parse_env_file_full(
+ const char *contents,
+ int (*push)(unsigned line, const char *key, const char *value, void *userdata),
+ void *userdata);
+
+int nm_parse_env_filev(const char *contents, va_list ap);
+int nm_parse_env_file_sentinel(const char *contents, ...) G_GNUC_NULL_TERMINATED;
+#define nm_parse_env_file(contents, ...) nm_parse_env_file_sentinel((contents), __VA_ARGS__, NULL)
+
#endif /* __NM_IO_UTILS_H__ */
diff --git a/src/libnm-glib-aux/nm-macros-internal.h b/src/libnm-glib-aux/nm-macros-internal.h
index 7cc8ac9797..6f6aeff106 100644
--- a/src/libnm-glib-aux/nm-macros-internal.h
+++ b/src/libnm-glib-aux/nm-macros-internal.h
@@ -1053,6 +1053,24 @@ nm_g_variant_equal(GVariant *a, GVariant *b)
* the kernel command line. */
#define NM_ASCII_WHITESPACES " \n\t\r"
+static inline gboolean
+nm_ascii_is_whitespace(char ch)
+{
+ /* Checks whether @ch is in NM_ASCII_WHITESPACES.
+ * Similar to g_ascii_isspace(), however this one does not accept '\f'.
+ * This is the same as systemd's strchr(WHITESPACE, ch). */
+ return NM_IN_SET(ch, ' ', '\n', '\t', '\r');
+}
+
+#define NM_ASCII_NEWLINE "\n\r"
+
+static inline gboolean
+nm_ascii_is_newline(char ch)
+{
+ /* This is the same as systemd's (!!strchr(NEWLINE, ch)). */
+ return NM_IN_SET(ch, '\n', '\t');
+}
+
#define nm_str_skip_leading_spaces(str) \
({ \
typeof(*(str)) *_str_sls = (str); \
diff --git a/src/libnm-glib-aux/nm-shared-utils.c b/src/libnm-glib-aux/nm-shared-utils.c
index ad99a6b929..b8102cc8bc 100644
--- a/src/libnm-glib-aux/nm-shared-utils.c
+++ b/src/libnm-glib-aux/nm-shared-utils.c
@@ -37,6 +37,13 @@ const void *const _NM_PTRARRAY_EMPTY[1] = {NULL};
const NMIPAddr nm_ip_addr_zero = {};
+/* We use _nm_alignas(NMIPAddr). Ensure that this struct has the same
+ * alignment as in_addr_t and struct in6_addr. */
+G_STATIC_ASSERT(_nm_alignof(NMIPAddr) == 4);
+G_STATIC_ASSERT(_nm_alignof(in_addr_t) == 4);
+G_STATIC_ASSERT(_nm_alignof(struct in_addr) == 4);
+G_STATIC_ASSERT(_nm_alignof(struct in6_addr) == 4);
+
/* this initializes a struct in_addr/in6_addr and allows for untrusted
* arguments (like unsuitable @addr_family or @src_len). It's almost safe
* in the sense that it verifies input arguments strictly. Also, it
@@ -2998,7 +3005,7 @@ nm_utils_buf_utf8safe_unescape(const char *str,
return str;
}
- nm_str_buf_init(&strbuf, len + 1u, FALSE);
+ strbuf = NM_STR_BUF_INIT(len + 1u, FALSE);
nm_str_buf_append_len(&strbuf, str, s - str);
str = s;
@@ -3165,7 +3172,7 @@ nm_utils_buf_utf8safe_escape(gconstpointer buf,
return str;
}
- nm_str_buf_init(&strbuf, buflen + 5, NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET));
+ strbuf = NM_STR_BUF_INIT(buflen + 5, NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET));
s = str;
do {
@@ -3432,51 +3439,6 @@ nm_utils_named_value_clear_with_g_free(NMUtilsNamedValue *val)
G_STATIC_ASSERT(G_STRUCT_OFFSET(NMUtilsNamedValue, name) == 0);
-NMUtilsNamedValue *
-nm_utils_named_values_from_strdict_full(GHashTable *hash,
- guint *out_len,
- GCompareDataFunc compare_func,
- gpointer user_data,
- NMUtilsNamedValue *provided_buffer,
- guint provided_buffer_len,
- NMUtilsNamedValue **out_allocated_buffer)
-{
- GHashTableIter iter;
- NMUtilsNamedValue *values;
- guint i, len;
-
- nm_assert(provided_buffer_len == 0 || provided_buffer);
- nm_assert(!out_allocated_buffer || !*out_allocated_buffer);
-
- if (!hash || !(len = g_hash_table_size(hash))) {
- NM_SET_OUT(out_len, 0);
- return NULL;
- }
-
- if (provided_buffer_len >= len + 1) {
- /* the buffer provided by the caller is large enough. Use it. */
- values = provided_buffer;
- } else {
- /* allocate a new buffer. */
- values = g_new(NMUtilsNamedValue, len + 1);
- NM_SET_OUT(out_allocated_buffer, values);
- }
-
- i = 0;
- g_hash_table_iter_init(&iter, hash);
- while (g_hash_table_iter_next(&iter, (gpointer *) &values[i].name, &values[i].value_ptr))
- i++;
- nm_assert(i == len);
- values[i].name = NULL;
- values[i].value_ptr = NULL;
-
- if (compare_func)
- nm_utils_named_value_list_sort(values, len, compare_func, user_data);
-
- NM_SET_OUT(out_len, len);
- return values;
-}
-
gssize
nm_utils_named_value_list_find(const NMUtilsNamedValue *arr,
gsize len,
@@ -3626,6 +3588,52 @@ nm_utils_hash_values_to_array(GHashTable *hash,
return arr;
}
+NMUtilsNamedValue *
+nm_utils_hash_to_array_full(GHashTable *hash,
+ guint *out_len,
+ GCompareDataFunc compare_func,
+ gpointer user_data,
+ NMUtilsNamedValue *provided_buffer,
+ guint provided_buffer_len,
+ NMUtilsNamedValue **out_allocated_buffer)
+{
+ GHashTableIter iter;
+ NMUtilsNamedValue *values;
+ guint len;
+ guint i;
+
+ nm_assert(provided_buffer_len == 0 || provided_buffer);
+ nm_assert(!out_allocated_buffer || !*out_allocated_buffer);
+
+ if (!hash || ((len = g_hash_table_size(hash)) == 0)) {
+ NM_SET_OUT(out_len, 0);
+ return NULL;
+ }
+
+ if (provided_buffer_len >= len + 1) {
+ /* the buffer provided by the caller is large enough. Use it. */
+ values = provided_buffer;
+ } else {
+ /* allocate a new buffer. */
+ values = g_new(NMUtilsNamedValue, len + 1);
+ NM_SET_OUT(out_allocated_buffer, values);
+ }
+
+ i = 0;
+ g_hash_table_iter_init(&iter, hash);
+ while (g_hash_table_iter_next(&iter, &values[i].name_ptr, &values[i].value_ptr))
+ i++;
+ nm_assert(i == len);
+ values[i].name_ptr = NULL;
+ values[i].value_ptr = NULL;
+
+ if (compare_func && len > 1)
+ g_qsort_with_data(values, len, sizeof(NMUtilsNamedValue), compare_func, user_data);
+
+ NM_SET_OUT(out_len, len);
+ return values;
+}
+
/*****************************************************************************/
/**
@@ -5840,10 +5848,22 @@ _nm_str_buf_ensure_size(NMStrBuf *strbuf, gsize new_size, gboolean reserve_exact
new_size = nm_utils_get_next_realloc_size(!strbuf->_priv_do_bzero_mem, new_size);
}
- strbuf->_priv_str = nm_secret_mem_realloc(strbuf->_priv_str,
- strbuf->_priv_do_bzero_mem,
- strbuf->_priv_allocated,
- new_size);
+ if (strbuf->_priv_malloced) {
+ strbuf->_priv_str = nm_secret_mem_realloc(strbuf->_priv_str,
+ strbuf->_priv_do_bzero_mem,
+ strbuf->_priv_allocated,
+ new_size);
+ } else {
+ char *old = strbuf->_priv_str;
+
+ strbuf->_priv_str = g_malloc(new_size);
+ if (strbuf->_priv_len > 0) {
+ memcpy(strbuf->_priv_str, old, strbuf->_priv_len);
+ if (strbuf->_priv_do_bzero_mem)
+ nm_explicit_bzero(old, strbuf->_priv_len);
+ }
+ strbuf->_priv_malloced = TRUE;
+ }
strbuf->_priv_allocated = new_size;
}
@@ -6584,7 +6604,7 @@ nm_utils_validate_hostname(const char *hostname)
if (dot)
return FALSE;
- return (p - hostname <= HOST_NAME_MAX);
+ return (p - hostname <= NM_HOST_NAME_MAX);
}
/*****************************************************************************/
@@ -6713,3 +6733,540 @@ nm_g_main_context_can_acquire(GMainContext *context)
g_main_context_release(context);
return TRUE;
}
+
+/*****************************************************************************/
+
+int
+nm_unbase64char(char c)
+{
+ /* copied from systemd's unbase64char():
+ * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/basic/hexdecoct.c#L539 */
+
+ switch (c) {
+ case 'A' ... 'Z':
+ return c - 'A';
+ case 'a' ... 'z':
+ return (c - 'a') + ('Z' - 'A' + 1);
+ case '0' ... '9':
+ return (c - '0') + (('Z' - 'A' + 1) + ('z' - 'a' + 1));
+ case '+':
+ return ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 1);
+ case '/':
+ return ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 1) + 1;
+ case '=':
+ /* The padding is a different kind of base64 character. Return
+ * a special error code for it. */
+ return -ERANGE;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int
+unbase64_next(const char **p, size_t *l)
+{
+ int ret;
+
+ nm_assert(p);
+ nm_assert(l);
+
+ /* copied from systemd's unbase64_next():
+ * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/basic/hexdecoct.c#L709 */
+
+ /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We
+ * greedily skip all preceding and all following whitespace. */
+
+ for (;;) {
+ if (*l == 0)
+ return -EPIPE;
+
+ if (!nm_ascii_is_whitespace(**p))
+ break;
+
+ /* Skip leading whitespace */
+ (*p)++;
+ (*l)--;
+ }
+
+ ret = nm_unbase64char(**p);
+ if (ret < 0) {
+ nm_assert(NM_IN_SET(ret, -EINVAL, -ERANGE));
+ if (ret != -ERANGE)
+ return ret;
+ }
+
+ for (;;) {
+ (*p)++;
+ (*l)--;
+
+ if (*l == 0)
+ break;
+ if (!nm_ascii_is_whitespace(**p))
+ break;
+
+ /* Skip following whitespace */
+ }
+
+ nm_assert(ret == -ERANGE || ret >= 0);
+ return ret;
+}
+
+/**
+ * nm_unbase64mem_full:
+ * @p: a valid base64 string. Whitespace is ignored, but invalid encodings
+ * will cause the function to fail.
+ * @l: the length of @p. @p is not treated as NUL terminated string but
+ * merely as a buffer of ascii characters.
+ * @secure: whether the temporary memory will be cleared to avoid leaving
+ * secrets in memory (see also nm_explicit_bzero()).
+ * @mem: (transfer full): the decoded buffer on success.
+ * @len: the length of @mem on success.
+ *
+ * glib provides g_base64_decode(), but that does not report any errors
+ * from invalid encodings. Our own implementation (based on systemd code)
+ * rejects invalid inputs.
+ *
+ * Returns: a non-negative code on success. Invalid encoding let the
+ * function fail.
+ */
+int
+nm_unbase64mem_full(const char *p, gsize l, gboolean secure, guint8 **ret, gsize *ret_size)
+{
+ gs_free uint8_t *buf = NULL;
+ const char *x;
+ guint8 *z;
+ gsize len;
+ int r;
+
+ /* copied from systemd's unbase64mem_full():
+ * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/basic/hexdecoct.c#L751 */
+
+ nm_assert(p || l == 0);
+
+ if (l == G_MAXSIZE)
+ l = strlen(p);
+
+ /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra
+ * bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */
+ len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0);
+
+ buf = g_malloc(len + 1);
+
+ for (x = p, z = buf;;) {
+ int a; /* a == 00XXXXXX */
+ int b; /* b == 00YYYYYY */
+ int c; /* c == 00ZZZZZZ */
+ int d; /* d == 00WWWWWW */
+
+ a = unbase64_next(&x, &l);
+ if (a < 0) {
+ if (a == -EPIPE) /* End of string */
+ break;
+ if (a == -ERANGE) { /* Padding is not allowed at the beginning of a 4ch block */
+ r = -EINVAL;
+ goto on_failure;
+ }
+ r = a;
+ goto on_failure;
+ }
+
+ b = unbase64_next(&x, &l);
+ if (b < 0) {
+ if (b == -ERANGE) {
+ /* Padding is not allowed at the second character of a 4ch block either */
+ r = -EINVAL;
+ goto on_failure;
+ }
+ r = b;
+ goto on_failure;
+ }
+
+ c = unbase64_next(&x, &l);
+ if (c < 0) {
+ if (c != -ERANGE) {
+ r = c;
+ goto on_failure;
+ }
+ }
+
+ d = unbase64_next(&x, &l);
+ if (d < 0) {
+ if (d != -ERANGE) {
+ r = d;
+ goto on_failure;
+ }
+ }
+
+ if (c == -ERANGE) { /* Padding at the third character */
+
+ if (d != -ERANGE) { /* If the third character is padding, the fourth must be too */
+ r = -EINVAL;
+ goto on_failure;
+ }
+
+ /* b == 00YY0000 */
+ if (b & 15) {
+ r = -EINVAL;
+ goto on_failure;
+ }
+
+ if (l > 0) { /* Trailing rubbish? */
+ r = -ENAMETOOLONG;
+ goto on_failure;
+ }
+
+ *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
+ break;
+ }
+
+ if (d == -ERANGE) {
+ /* c == 00ZZZZ00 */
+ if (c & 3) {
+ r = -EINVAL;
+ goto on_failure;
+ }
+
+ if (l > 0) { /* Trailing rubbish? */
+ r = -ENAMETOOLONG;
+ goto on_failure;
+ }
+
+ *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
+ *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
+ break;
+ }
+
+ *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
+ *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
+ *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
+ }
+
+ *z = '\0';
+
+ NM_SET_OUT(ret_size, (gsize) (z - buf));
+ NM_SET_OUT(ret, g_steal_pointer(&buf));
+ return 0;
+
+on_failure:
+ if (secure)
+ nm_explicit_bzero(buf, len);
+ return r;
+}
+
+/*****************************************************************************/
+
+static const char *
+skip_slash_or_dot(const char *p)
+{
+ for (; !nm_str_is_empty(p);) {
+ if (p[0] == '/') {
+ p += 1;
+ continue;
+ }
+ if (p[0] == '.' && p[1] == '/') {
+ p += 2;
+ continue;
+ }
+ break;
+ }
+ return p;
+}
+
+int
+nm_path_find_first_component(const char **p, gboolean accept_dot_dot, const char **ret)
+{
+ const char *q, *first, *end_first, *next;
+ size_t len;
+
+ /* Copied from systemd's path_compare()
+ * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.c#L809 */
+
+ nm_assert(p);
+
+ /* When a path is input, then returns the pointer to the first component and its length, and
+ * move the input pointer to the next component or nul. This skips both over any '/'
+ * immediately *before* and *after* the first component before returning.
+ *
+ * Examples
+ * Input: p: "//.//aaa///bbbbb/cc"
+ * Output: p: "bbbbb///cc"
+ * ret: "aaa///bbbbb/cc"
+ * return value: 3 (== strlen("aaa"))
+ *
+ * Input: p: "aaa//"
+ * Output: p: (pointer to NUL)
+ * ret: "aaa//"
+ * return value: 3 (== strlen("aaa"))
+ *
+ * Input: p: "/", ".", ""
+ * Output: p: (pointer to NUL)
+ * ret: NULL
+ * return value: 0
+ *
+ * Input: p: NULL
+ * Output: p: NULL
+ * ret: NULL
+ * return value: 0
+ *
+ * Input: p: "(too long component)"
+ * Output: return value: -EINVAL
+ *
+ * (when accept_dot_dot is false)
+ * Input: p: "//..//aaa///bbbbb/cc"
+ * Output: return value: -EINVAL
+ */
+
+ q = *p;
+
+ first = skip_slash_or_dot(q);
+ if (nm_str_is_empty(first)) {
+ *p = first;
+ if (ret)
+ *ret = NULL;
+ return 0;
+ }
+ if (nm_streq(first, ".")) {
+ *p = first + 1;
+ if (ret)
+ *ret = NULL;
+ return 0;
+ }
+
+ end_first = strchrnul(first, '/');
+ len = end_first - first;
+
+ if (len > NAME_MAX)
+ return -EINVAL;
+ if (!accept_dot_dot && len == 2 && first[0] == '.' && first[1] == '.')
+ return -EINVAL;
+
+ next = skip_slash_or_dot(end_first);
+
+ *p = next + (nm_streq(next, ".") ? 1 : 0);
+ if (ret)
+ *ret = first;
+ return len;
+}
+
+int
+nm_path_compare(const char *a, const char *b)
+{
+ /* Copied from systemd's path_compare()
+ * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.c#L415 */
+
+ /* Order NULL before non-NULL */
+ NM_CMP_SELF(a, b);
+
+ /* A relative path and an absolute path must not compare as equal.
+ * Which one is sorted before the other does not really matter.
+ * Here a relative path is ordered before an absolute path. */
+ NM_CMP_DIRECT(nm_path_is_absolute(a), nm_path_is_absolute(b));
+
+ for (;;) {
+ const char *aa, *bb;
+ int j, k;
+
+ j = nm_path_find_first_component(&a, TRUE, &aa);
+ k = nm_path_find_first_component(&b, TRUE, &bb);
+
+ if (j < 0 || k < 0) {
+ /* When one of paths is invalid, order invalid path after valid one. */
+ NM_CMP_DIRECT(j < 0, k < 0);
+
+ /* fallback to use strcmp() if both paths are invalid. */
+ NM_CMP_DIRECT_STRCMP(a, b);
+ return 0;
+ }
+
+ /* Order prefixes first: "/foo" before "/foo/bar" */
+ if (j == 0) {
+ if (k == 0)
+ return 0;
+ return -1;
+ }
+ if (k == 0)
+ return 1;
+
+ /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
+ NM_CMP_DIRECT_MEMCMP(aa, bb, NM_MIN(j, k));
+
+ /* Sort "/foo/a" before "/foo/aaa" */
+ NM_CMP_DIRECT(j, k);
+ }
+}
+
+char *
+nm_path_startswith_full(const char *path, const char *prefix, gboolean accept_dot_dot)
+{
+ /* Copied from systemd's path_startswith_full()
+ * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.c#L375 */
+
+ nm_assert(path);
+ nm_assert(prefix);
+
+ /* Returns a pointer to the start of the first component after the parts matched by
+ * the prefix, iff
+ * - both paths are absolute or both paths are relative,
+ * and
+ * - each component in prefix in turn matches a component in path at the same position.
+ * An empty string will be returned when the prefix and path are equivalent.
+ *
+ * Returns NULL otherwise.
+ */
+
+ if ((path[0] == '/') != (prefix[0] == '/'))
+ return NULL;
+
+ for (;;) {
+ const char *p, *q;
+ int r, k;
+
+ r = nm_path_find_first_component(&path, accept_dot_dot, &p);
+ if (r < 0)
+ return NULL;
+
+ k = nm_path_find_first_component(&prefix, accept_dot_dot, &q);
+ if (k < 0)
+ return NULL;
+
+ if (k == 0)
+ return (char *) (p ?: path);
+
+ if (r != k)
+ return NULL;
+
+ if (strncmp(p, q, r) != 0)
+ return NULL;
+ }
+}
+
+char *
+nm_path_simplify(char *path)
+{
+ bool add_slash = false;
+ char *f = path;
+ int r;
+
+ /* Copied from systemd's path_simplify()
+ * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.c#L325 */
+
+ nm_assert(path);
+
+ /* Removes redundant inner and trailing slashes. Also removes unnecessary dots.
+ * Modifies the passed string in-place.
+ *
+ * ///foo//./bar/. becomes /foo/bar
+ * .//./foo//./bar/. becomes foo/bar
+ */
+
+ if (path[0] == '\0')
+ return path;
+
+ if (nm_path_is_absolute(path))
+ f++;
+
+ for (const char *p = f;;) {
+ const char *e;
+
+ r = nm_path_find_first_component(&p, TRUE, &e);
+ if (r == 0)
+ break;
+
+ if (add_slash)
+ *f++ = '/';
+
+ if (r < 0) {
+ /* if path is invalid, then refuse to simplify remaining part. */
+ memmove(f, p, strlen(p) + 1);
+ return path;
+ }
+
+ memmove(f, e, r);
+ f += r;
+
+ add_slash = TRUE;
+ }
+
+ /* Special rule, if we stripped everything, we need a "." for the current directory. */
+ if (f == path)
+ *f++ = '.';
+
+ *f = '\0';
+ return path;
+}
+
+/*****************************************************************************/
+
+static gboolean
+valid_ldh_char(char c)
+{
+ /* "LDH" ā†’ "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */
+
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-';
+}
+
+/**
+ * nm_hostname_is_valid:
+ * @s: the hostname to check.
+ * @trailing_dot: Accept trailing dot on multi-label names.
+ *
+ * Return: %TRUE if valid.
+ */
+gboolean
+nm_hostname_is_valid(const char *s, gboolean trailing_dot)
+{
+ unsigned n_dots = 0;
+ const char *p;
+ gboolean dot;
+ gboolean hyphen;
+
+ /* Copied from systemd's hostname_is_valid()
+ * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/hostname-util.c#L85 */
+
+ /* Check if s looks like a valid hostname or FQDN. This does not do full DNS validation, but only
+ * checks if the name is composed of allowed characters and the length is not above the maximum
+ * allowed by Linux (c.f. dns_name_is_valid()). A trailing dot is allowed if
+ * VALID_HOSTNAME_TRAILING_DOT flag is set and at least two components are present in the name. Note
+ * that due to the restricted charset and length this call is substantially more conservative than
+ * dns_name_is_valid(). Doesn't accept empty hostnames, hostnames with leading dots, and hostnames
+ * with multiple dots in a sequence. Doesn't allow hyphens at the beginning or end of label. */
+
+ if (nm_str_is_empty(s))
+ return FALSE;
+
+ for (p = s, dot = hyphen = TRUE; *p; p++)
+ if (*p == '.') {
+ if (dot || hyphen)
+ return FALSE;
+
+ dot = TRUE;
+ hyphen = FALSE;
+ n_dots++;
+
+ } else if (*p == '-') {
+ if (dot)
+ return FALSE;
+
+ dot = FALSE;
+ hyphen = TRUE;
+
+ } else {
+ if (!valid_ldh_char(*p))
+ return FALSE;
+
+ dot = FALSE;
+ hyphen = FALSE;
+ }
+
+ if (dot && (n_dots < 2 || !trailing_dot))
+ return FALSE;
+ if (hyphen)
+ return FALSE;
+
+ /* Note that HOST_NAME_MAX is 64 on Linux, but DNS allows domain names up to
+ * 255 characters */
+ if (p - s > NM_HOST_NAME_MAX)
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h
index daefa068c9..0e123cf1c0 100644
--- a/src/libnm-glib-aux/nm-shared-utils.h
+++ b/src/libnm-glib-aux/nm-shared-utils.h
@@ -216,7 +216,7 @@ nm_ether_addr_equal(const NMEtherAddr *a, const NMEtherAddr *b)
typedef struct {
union {
- guint8 addr_ptr[1];
+ guint8 addr_ptr[sizeof(struct in6_addr)];
in_addr_t addr4;
struct in_addr addr4_struct;
struct in6_addr addr6;
@@ -1977,6 +1977,7 @@ typedef struct {
NMUtilsNamedEntry named_entry;
const char *name;
char *name_mutable;
+ gpointer name_ptr;
};
union {
const char *value_str;
@@ -1990,14 +1991,28 @@ typedef struct {
.name = (n), .value_ptr = (v) \
}
-NMUtilsNamedValue *
-nm_utils_named_values_from_strdict_full(GHashTable *hash,
- guint *out_len,
- GCompareDataFunc compare_func,
- gpointer user_data,
- NMUtilsNamedValue *provided_buffer,
- guint provided_buffer_len,
- NMUtilsNamedValue **out_allocated_buffer);
+NMUtilsNamedValue *nm_utils_hash_to_array_full(GHashTable *hash,
+ guint *out_len,
+ GCompareDataFunc compare_func,
+ gpointer user_data,
+ NMUtilsNamedValue *provided_buffer,
+ guint provided_buffer_len,
+ NMUtilsNamedValue **out_allocated_buffer);
+
+#define nm_utils_named_values_from_strdict_full(hash, \
+ out_len, \
+ compare_func, \
+ user_data, \
+ provided_buffer, \
+ provided_buffer_len, \
+ out_allocated_buffer) \
+ nm_utils_hash_to_array_full((hash), \
+ (out_len), \
+ (compare_func), \
+ (user_data), \
+ (provided_buffer), \
+ (provided_buffer_len), \
+ (out_allocated_buffer))
#define nm_utils_named_values_from_strdict(hash, out_len, array, out_allocated_buffer) \
nm_utils_named_values_from_strdict_full((hash), \
@@ -2038,6 +2053,29 @@ gpointer *nm_utils_hash_values_to_array(GHashTable *hash,
gpointer user_data,
guint *out_len);
+static inline NMUtilsNamedValue *
+nm_utils_hash_to_array(GHashTable *hash,
+ GCompareDataFunc compare_func,
+ gpointer user_data,
+ guint *out_len)
+{
+ return nm_utils_hash_to_array_full(hash, out_len, compare_func, user_data, NULL, 0, NULL);
+}
+
+#define nm_utils_hash_to_array_with_buffer(hash, \
+ out_len, \
+ compare_func, \
+ user_data, \
+ array, \
+ out_allocated_buffer) \
+ nm_utils_hash_to_array_full((hash), \
+ (out_len), \
+ (compare_func), \
+ (user_data), \
+ (array), \
+ G_N_ELEMENTS(array), \
+ (out_allocated_buffer))
+
static inline const char **
nm_strdict_get_keys(const GHashTable *hash, gboolean sorted, guint *out_length)
{
@@ -3224,6 +3262,12 @@ char *_nm_utils_format_variant_attributes(GHashTable *a
/*****************************************************************************/
+/* glibc defines HOST_NAME_MAX as 64. Also Linux' sethostname() enforces
+ * that (__NEW_UTS_LEN). However, musl sets this to 255.
+ *
+ * At some places, we want to follow Linux. Hardcode our own define. */
+#define NM_HOST_NAME_MAX 64
+
gboolean nm_utils_is_localhost(const char *name);
gboolean nm_utils_is_specific_hostname(const char *name);
@@ -3276,4 +3320,46 @@ gboolean nm_utils_validate_hostname(const char *hostname);
void nm_utils_thread_local_register_destroy(gpointer tls_data, GDestroyNotify destroy_notify);
+/*****************************************************************************/
+
+int nm_unbase64char(char c);
+int nm_unbase64mem_full(const char *p, gsize l, gboolean secure, guint8 **ret, gsize *ret_size);
+
+/*****************************************************************************/
+
+static inline gboolean
+nm_path_is_absolute(const char *p)
+{
+ /* Copied from systemd's path_is_absolute()
+ * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.h#L50 */
+
+ nm_assert(p);
+ return p[0] == '/';
+}
+
+int nm_path_find_first_component(const char **p, gboolean accept_dot_dot, const char **ret);
+
+int nm_path_compare(const char *a, const char *b);
+
+static inline gboolean
+nm_path_equal(const char *a, const char *b)
+{
+ return nm_path_compare(a, b) == 0;
+}
+
+char *nm_path_simplify(char *path);
+
+char *
+nm_path_startswith_full(const char *path, const char *prefix, gboolean accept_dot_dot) _nm_pure;
+
+static inline char *
+nm_path_startswith(const char *path, const char *prefix)
+{
+ return nm_path_startswith_full(path, prefix, TRUE);
+}
+
+/*****************************************************************************/
+
+gboolean nm_hostname_is_valid(const char *s, gboolean trailing_dot);
+
#endif /* __NM_SHARED_UTILS_H__ */
diff --git a/src/libnm-glib-aux/nm-str-buf.h b/src/libnm-glib-aux/nm-str-buf.h
index 47d1f055be..9a3c5baf42 100644
--- a/src/libnm-glib-aux/nm-str-buf.h
+++ b/src/libnm-glib-aux/nm-str-buf.h
@@ -26,6 +26,7 @@ typedef struct _NMStrBuf {
};
bool _priv_do_bzero_mem;
+ bool _priv_malloced;
} NMStrBuf;
/*****************************************************************************/
@@ -36,29 +37,56 @@ _nm_str_buf_assert(const NMStrBuf *strbuf)
nm_assert(strbuf);
nm_assert((!!strbuf->_priv_str) == (strbuf->_priv_allocated > 0));
nm_assert(strbuf->_priv_len <= strbuf->_priv_allocated);
+ nm_assert(!strbuf->_priv_malloced || strbuf->_priv_str);
}
static inline NMStrBuf
-NM_STR_BUF_INIT(gsize allocated, gboolean do_bzero_mem)
+NM_STR_BUF_INIT_FULL(char *str,
+ gsize len,
+ gsize allocated,
+ gboolean malloced,
+ gboolean do_bzero_mem)
{
NMStrBuf strbuf = {
- ._priv_str = allocated ? g_malloc(allocated) : NULL,
+ ._priv_str = allocated > 0 ? str : NULL,
._priv_allocated = allocated,
- ._priv_len = 0,
+ ._priv_len = len,
._priv_do_bzero_mem = do_bzero_mem,
+ ._priv_malloced = allocated > 0 && malloced,
};
+ _nm_str_buf_assert(&strbuf);
+
return strbuf;
}
-static inline void
-nm_str_buf_init(NMStrBuf *strbuf, gsize len, bool do_bzero_mem)
+static inline NMStrBuf
+NM_STR_BUF_INIT(gsize allocated, gboolean do_bzero_mem)
{
- nm_assert(strbuf);
- *strbuf = NM_STR_BUF_INIT(len, do_bzero_mem);
- _nm_str_buf_assert(strbuf);
+ return NM_STR_BUF_INIT_FULL(allocated > 0 ? g_malloc(allocated) : NULL,
+ 0,
+ allocated,
+ allocated > 0,
+ do_bzero_mem);
}
+#define NM_STR_BUF_INIT_A(size, do_bzero_mem) \
+ NM_STR_BUF_INIT_FULL( \
+ g_alloca(size), \
+ 0, \
+ NM_STATIC_ASSERT_EXPR_1((size) > 0 && (size) <= NM_UTILS_GET_NEXT_REALLOC_SIZE_488) \
+ ? (size) \
+ : 0, \
+ FALSE, \
+ (do_bzero_mem));
+
+#define NM_STR_BUF_INIT_ARR(arr, do_bzero_mem) \
+ NM_STR_BUF_INIT_FULL((arr), \
+ 0, \
+ NM_STATIC_ASSERT_EXPR_1(sizeof(arr) > sizeof(char *)) ? sizeof(arr) : 0, \
+ FALSE, \
+ (do_bzero_mem));
+
void _nm_str_buf_ensure_size(NMStrBuf *strbuf, gsize new_size, gboolean reserve_exact);
static inline void
@@ -359,10 +387,10 @@ static inline gboolean
nm_str_buf_is_initalized(NMStrBuf *strbuf)
{
nm_assert(strbuf);
-#if NM_MORE_ASSERTS
- if (strbuf->_priv_str)
- _nm_str_buf_assert(strbuf);
-#endif
+ if (NM_MORE_ASSERTS > 0) {
+ if (strbuf->_priv_str)
+ _nm_str_buf_assert(strbuf);
+ }
return !!strbuf->_priv_str;
}
@@ -399,6 +427,29 @@ nm_str_buf_get_str(NMStrBuf *strbuf)
return strbuf->_priv_str;
}
+/**
+ * nm_str_buf_get_str_unsafe:
+ * @strbuf: the buffer
+ *
+ * Usually, NMStrBuf is used to construct NUL terminated strings. But
+ * while constructing the buffer (nm_str_buf_append*()), it does
+ * not NUL terminate the buffer yet. Only nm_str_buf_get_str()
+ * and nm_str_buf_finalize() ensure that the returned string is
+ * actually NUL terminated.
+ *
+ * NMStrBuf can also be used for binary data, or you might not
+ * require the NUL termination. In that case, nm_str_buf_get_str_unsafe()
+ * will give you the pointer, but you must not rely on it being NUL
+ * terminated. This is the "unsafe" part of it.
+ *
+ * The returned string is of course initialized up to length "strbuf->len"
+ * and allocated with "strbuf->allocated" bytes.
+ *
+ * If currently no buffer is allocated, %NULL is returned.
+ *
+ * Returns: (transfer none): very similar to nm_str_buf_get_str(),
+ * except that the result is no guaranteed to be NUL terminated.
+ */
static inline char *
nm_str_buf_get_str_unsafe(NMStrBuf *strbuf)
{
@@ -440,9 +491,11 @@ nm_str_buf_get_char(const NMStrBuf *strbuf, gsize index)
* Returns: (transfer full): the string of the buffer
* which must be freed by the caller. The @strbuf
* is afterwards in undefined state, though it can be
- * reused after nm_str_buf_init().
- * Note that if no string is allocated yet (after nm_str_buf_init() with
- * length zero), this will return %NULL. */
+ * reused after resetting with NM_STR_BUF_INIT().
+ * Note that if no string is allocated yet (after NM_STR_BUF_INIT() with
+ * length zero), this will return %NULL.
+ *
+ * If the buffer was not malloced before, it will be malloced now. */
static inline char *
nm_str_buf_finalize(NMStrBuf *strbuf, gsize *out_len)
{
@@ -453,6 +506,16 @@ nm_str_buf_finalize(NMStrBuf *strbuf, gsize *out_len)
if (!strbuf->_priv_str)
return NULL;
+ if (!strbuf->_priv_malloced) {
+ char *str = g_steal_pointer(&strbuf->_priv_str);
+ char *result;
+
+ result = g_strndup(str, strbuf->_priv_len);
+ if (strbuf->_priv_do_bzero_mem)
+ nm_explicit_bzero(str, strbuf->_priv_len);
+ return result;
+ }
+
nm_str_buf_maybe_expand(strbuf, 1, TRUE);
strbuf->_priv_str[strbuf->_priv_len] = '\0';
@@ -484,7 +547,7 @@ nm_str_buf_finalize_to_gbytes(NMStrBuf *strbuf)
*
* Frees the associated memory of @strbuf. The buffer
* afterwards is in undefined state, but can be re-initialized
- * with nm_str_buf_init().
+ * with NM_STR_BUF_INIT().
*/
static inline void
nm_str_buf_destroy(NMStrBuf *strbuf)
@@ -494,7 +557,8 @@ nm_str_buf_destroy(NMStrBuf *strbuf)
_nm_str_buf_assert(strbuf);
if (strbuf->_priv_do_bzero_mem)
nm_explicit_bzero(strbuf->_priv_str, strbuf->_priv_len);
- g_free(strbuf->_priv_str);
+ if (strbuf->_priv_malloced)
+ g_free(strbuf->_priv_str);
/* the buffer is in invalid state afterwards, however, we clear it
* so far, that nm_auto_str_buf is happy when calling
diff --git a/src/libnm-glib-aux/nm-test-utils.h b/src/libnm-glib-aux/nm-test-utils.h
index 2dfe9e323e..83702070b8 100644
--- a/src/libnm-glib-aux/nm-test-utils.h
+++ b/src/libnm-glib-aux/nm-test-utils.h
@@ -185,7 +185,7 @@
#define nmtst_assert_strv(strv, ...) \
G_STMT_START \
{ \
- const char *const *const _strv = (strv); \
+ const char *const *const _strv = NM_CAST_STRV_CC(strv); \
const char *const _exp[] = {__VA_ARGS__, NULL}; \
const gsize _n = G_N_ELEMENTS(_exp) - 1; \
gsize _i; \
@@ -196,6 +196,7 @@
g_assert(_exp[_i]); \
g_assert_cmpstr(_strv[_i], ==, _exp[_i]); \
} \
+ g_assert(!_strv[_n]); \
} \
G_STMT_END
diff --git a/src/libnm-glib-aux/tests/test-shared-general.c b/src/libnm-glib-aux/tests/test-shared-general.c
index 46689947e1..5e9310f5ac 100644
--- a/src/libnm-glib-aux/tests/test-shared-general.c
+++ b/src/libnm-glib-aux/tests/test-shared-general.c
@@ -10,6 +10,7 @@
#include "libnm-glib-aux/nm-str-buf.h"
#include "libnm-glib-aux/nm-time-utils.h"
#include "libnm-glib-aux/nm-ref-string.h"
+#include "libnm-glib-aux/nm-io-utils.h"
#include "libnm-glib-aux/nm-test-utils.h"
@@ -781,6 +782,9 @@ test_nm_utils_get_next_realloc_size(void)
{NM_UTILS_GET_NEXT_REALLOC_SIZE_232,
NM_UTILS_GET_NEXT_REALLOC_SIZE_232,
NM_UTILS_GET_NEXT_REALLOC_SIZE_232},
+ {NM_UTILS_GET_NEXT_REALLOC_SIZE_488,
+ NM_UTILS_GET_NEXT_REALLOC_SIZE_488,
+ NM_UTILS_GET_NEXT_REALLOC_SIZE_488},
{NM_UTILS_GET_NEXT_REALLOC_SIZE_1000,
NM_UTILS_GET_NEXT_REALLOC_SIZE_1000,
NM_UTILS_GET_NEXT_REALLOC_SIZE_1000},
@@ -913,27 +917,58 @@ test_nm_str_buf(void)
{
guint i_run;
- for (i_run = 0; TRUE; i_run++) {
- nm_auto_str_buf NMStrBuf strbuf = {};
- nm_auto_free_gstring GString *gstr = NULL;
+ for (i_run = 0; i_run < 1000; i_run++) {
+ char stack_buf[1024];
+ nm_auto_str_buf NMStrBuf strbuf;
+ nm_auto_free_gstring GString *gstr = NULL;
int i, j, k;
int c;
- nm_str_buf_init(&strbuf, nmtst_get_rand_uint32() % 200u + 1u, nmtst_get_rand_bool());
+ switch (nmtst_get_rand_uint32() % 10) {
+ case 0:
+ memset(&strbuf, 0, sizeof(strbuf));
+ break;
+ case 1 ... 4:
+ strbuf = NM_STR_BUF_INIT_FULL(stack_buf,
+ 0,
+ nmtst_get_rand_uint32() % sizeof(stack_buf),
+ FALSE,
+ nmtst_get_rand_bool());
+ break;
+ default:
+ strbuf = NM_STR_BUF_INIT(nmtst_get_rand_uint32() % 200u + 1u, nmtst_get_rand_bool());
+ break;
+ }
- if (i_run < 1000) {
- c = nmtst_get_rand_word_length(NULL);
- for (i = 0; i < c; i++)
- nm_str_buf_append_c(&strbuf, '0' + (i % 10));
- gstr = g_string_new(nm_str_buf_get_str(&strbuf));
- j = nmtst_get_rand_uint32() % (strbuf.len + 1);
- k = nmtst_get_rand_uint32() % (strbuf.len - j + 2) - 1;
+ c = nmtst_get_rand_word_length(NULL);
+ for (i = 0; i < c; i++)
+ nm_str_buf_append_c(&strbuf, '0' + (i % 10));
+ gstr = g_string_new(nm_str_buf_get_str(&strbuf));
+ j = nmtst_get_rand_uint32() % (strbuf.len + 1);
+ k = nmtst_get_rand_uint32() % (strbuf.len - j + 2) - 1;
- nm_str_buf_erase(&strbuf, j, k, nmtst_get_rand_bool());
- g_string_erase(gstr, j, k);
+ nm_str_buf_erase(&strbuf, j, k, nmtst_get_rand_bool());
+ g_string_erase(gstr, j, k);
+ if (gstr->str[0])
g_assert_cmpstr(gstr->str, ==, nm_str_buf_get_str(&strbuf));
+ else
+ g_assert(NM_IN_STRSET(nm_str_buf_get_str(&strbuf), NULL, ""));
+ }
+
+ for (i_run = 0; i_run < 50; i_run++) {
+ char stack_buf[20];
+ nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT_ARR(stack_buf, nmtst_get_rand_bool());
+
+ nm_str_buf_append_c_len(&strbuf, 'a', nmtst_get_rand_uint32() % (sizeof(stack_buf) * 2));
+ if (strbuf.len <= sizeof(stack_buf)) {
+ g_assert(stack_buf == nm_str_buf_get_str_unsafe(&strbuf));
} else
- return;
+ g_assert(stack_buf != nm_str_buf_get_str_unsafe(&strbuf));
+
+ if (strbuf.len < sizeof(stack_buf)) {
+ g_assert(stack_buf == nm_str_buf_get_str(&strbuf));
+ } else
+ g_assert(stack_buf != nm_str_buf_get_str(&strbuf));
}
}
@@ -1417,6 +1452,755 @@ test_nm_ascii(void)
/*****************************************************************************/
+static int
+_env_file_push_cb(unsigned line, const char *key, const char *value, void *user_data)
+{
+ char ***strv = user_data;
+ char *s_line;
+ gsize key_l;
+ gsize strv_l;
+ gsize i;
+
+ g_assert(strv);
+ g_assert(key);
+ g_assert(key[0]);
+ g_assert(!strchr(key, '='));
+ g_assert(value);
+
+ key_l = strlen(key);
+
+ s_line = g_strconcat(key, "=", value, NULL);
+
+ strv_l = 0;
+ if (*strv) {
+ const char *s;
+
+ for (i = 0; (s = (*strv)[i]); i++) {
+ if (g_str_has_prefix(s, key) && s[key_l] == '=') {
+ g_free((*strv)[i]);
+ (*strv)[i] = s_line;
+ return 0;
+ }
+ }
+ strv_l = i;
+ }
+
+ *strv = g_realloc(*strv, sizeof(char *) * (strv_l + 2));
+ (*strv)[strv_l] = s_line;
+ (*strv)[strv_l + 1] = NULL;
+
+ return 0;
+}
+
+static void
+test_parse_env_file(void)
+{
+ gs_strfreev char **data = NULL;
+ gs_free char *arg1 = NULL;
+ gs_free char *arg2 = NULL;
+ int r;
+
+#define env_file_1 \
+ "a=a\n" \
+ "a=b\n" \
+ "a=b\n" \
+ "a=a\n" \
+ "b=b\\\n" \
+ "c\n" \
+ "d= d\\\n" \
+ "e \\\n" \
+ "f \n" \
+ "g=g\\ \n" \
+ "h= Ä…Ä™Ć³Å‚\\ śćńÅŗżĀµ \n" \
+ "i=i\\"
+ r = nm_parse_env_file_full(env_file_1, _env_file_push_cb, &data);
+ g_assert_cmpint(r, ==, 0);
+ nmtst_assert_strv(data, "a=a", "b=bc", "d=de f", "g=g ", "h=Ä…Ä™Ć³Å‚ śćńÅŗżĀµ", "i=i");
+ nm_clear_pointer(&data, g_strfreev);
+
+ r = nm_parse_env_file(env_file_1, "a", &arg1);
+ g_assert_cmpint(r, ==, 0);
+ g_assert_cmpstr(arg1, ==, "a");
+ nm_clear_g_free(&arg1);
+
+ r = nm_parse_env_file(env_file_1, "a", &arg1, "d", &arg2);
+ g_assert_cmpint(r, ==, 0);
+ g_assert_cmpstr(arg1, ==, "a");
+ g_assert_cmpstr(arg2, ==, "de f");
+ nm_clear_g_free(&arg1);
+ nm_clear_g_free(&arg2);
+
+#define env_file_2 "a=a\\\n"
+ r = nm_parse_env_file_full(env_file_2, _env_file_push_cb, &data);
+ g_assert_cmpint(r, ==, 0);
+ nmtst_assert_strv(data, "a=a");
+ nm_clear_pointer(&data, g_strfreev);
+
+#define env_file_3 \
+ "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \
+ "#--nouser-config \\\n" \
+ "normal=line \\\n" \
+ ";normal=ignored \\\n" \
+ "normal_ignored \\\n" \
+ "normal ignored \\\n"
+ r = nm_parse_env_file_full(env_file_3, _env_file_push_cb, &data);
+ g_assert_cmpint(r, ==, 0);
+ g_assert(!data);
+
+#define env_file_4 \
+ "# Generated\n" \
+ "\n" \
+ "HWMON_MODULES=\"coretemp f71882fg\"\n" \
+ "\n" \
+ "# For compatibility reasons\n" \
+ "\n" \
+ "MODULE_0=coretemp\n" \
+ "MODULE_1=f71882fg"
+ r = nm_parse_env_file_full(env_file_4, _env_file_push_cb, &data);
+ g_assert_cmpint(r, ==, 0);
+ nmtst_assert_strv(data,
+ "HWMON_MODULES=coretemp f71882fg",
+ "MODULE_0=coretemp",
+ "MODULE_1=f71882fg");
+ nm_clear_pointer(&data, g_strfreev);
+
+#define env_file_5 \
+ "a=\n" \
+ "b="
+ r = nm_parse_env_file_full(env_file_5, _env_file_push_cb, &data);
+ g_assert_cmpint(r, ==, 0);
+ nmtst_assert_strv(data, "a=", "b=");
+ nm_clear_pointer(&data, g_strfreev);
+
+#define env_file_6 \
+ "a=\\ \\n \\t \\x \\y \\' \n" \
+ "b= \\$' \n" \
+ "c= ' \\n\\t\\$\\`\\\\\n" \
+ "' \n" \
+ "d= \" \\n\\t\\$\\`\\\\\n" \
+ "\" \n"
+ r = nm_parse_env_file_full(env_file_6, _env_file_push_cb, &data);
+ g_assert_cmpint(r, ==, 0);
+ nmtst_assert_strv(data, "a= n t x y '", "b=$'", "c= \\n\\t\\$\\`\\\\\n", "d= \\n\\t$`\\\n");
+ nm_clear_pointer(&data, g_strfreev);
+}
+
+/*****************************************************************************/
+
+static void
+test_unbase64char(void)
+{
+ static const int expected[128] = {
+ [0] = -1, [1] = -1, [2] = -1, [3] = -1, [4] = -1, [5] = -1, [6] = -1,
+ [7] = -1, [8] = -1, [9] = -1, [10] = -1, [11] = -1, [12] = -1, [13] = -1,
+ [14] = -1, [15] = -1, [16] = -1, [17] = -1, [18] = -1, [19] = -1, [20] = -1,
+ [21] = -1, [22] = -1, [23] = -1, [24] = -1, [25] = -1, [26] = -1, [27] = -1,
+ [28] = -1, [29] = -1, [30] = -1, [31] = -1, [32] = -1, [33] = -1, [34] = -1,
+ [35] = -1, [36] = -1, [37] = -1, [38] = -1, [39] = -1, [40] = -1, [41] = -1,
+ [42] = -1, ['+'] = 62, [44] = -1, [45] = -1, [46] = -1, ['/'] = 63, ['0'] = 52,
+ ['1'] = 53, ['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59,
+ ['8'] = 60, ['9'] = 61, [58] = -1, [59] = -1, [60] = -1, [61] = -1, [62] = -1,
+ [63] = -1, [64] = -1, ['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4,
+ ['F'] = 5, ['G'] = 6, ['H'] = 7, ['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11,
+ ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15, ['Q'] = 16, ['R'] = 17, ['S'] = 18,
+ ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25,
+ [91] = -1, [92] = -1, [93] = -1, [94] = -1, [95] = -1, [96] = -1, ['a'] = 26,
+ ['b'] = 27, ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33,
+ ['i'] = 34, ['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39, ['o'] = 40,
+ ['p'] = 41, ['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47,
+ ['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51, [123] = -1, [124] = -1, [125] = -1,
+ [126] = -1, [127] = -1,
+ };
+ int i;
+
+ /* Copied from systemd's TEST(unbase64char)
+ * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/test/test-hexdecoct.c#L44 */
+
+ g_assert_cmpint(nm_unbase64char('A'), ==, 0);
+ g_assert_cmpint(nm_unbase64char('Z'), ==, 25);
+ g_assert_cmpint(nm_unbase64char('a'), ==, 26);
+ g_assert_cmpint(nm_unbase64char('z'), ==, 51);
+ g_assert_cmpint(nm_unbase64char('0'), ==, 52);
+ g_assert_cmpint(nm_unbase64char('9'), ==, 61);
+ g_assert_cmpint(nm_unbase64char('+'), ==, 62);
+ g_assert_cmpint(nm_unbase64char('/'), ==, 63);
+ g_assert_cmpint(nm_unbase64char('='), ==, -ERANGE);
+ g_assert_cmpint(nm_unbase64char('\0'), ==, -EINVAL);
+ g_assert_cmpint(nm_unbase64char('\1'), ==, -EINVAL);
+ g_assert_cmpint(nm_unbase64char('\x7F'), ==, -EINVAL);
+ g_assert_cmpint(nm_unbase64char('\x80'), ==, -EINVAL);
+ g_assert_cmpint(nm_unbase64char('\xFF'), ==, -EINVAL);
+
+ for (i = 0; i < 256; i++) {
+ int base64;
+
+ base64 = nm_unbase64char((char) i);
+
+ if (base64 < 0) {
+ if (((char) i) == '=')
+ g_assert_cmpint(base64, ==, -ERANGE);
+ else
+ g_assert_cmpint(base64, ==, -EINVAL);
+ base64 = -1;
+ }
+
+ if (i >= G_N_ELEMENTS(expected)) {
+ g_assert_cmpint(base64, ==, -1);
+ continue;
+ }
+ g_assert_cmpint(base64, ==, expected[i]);
+ }
+}
+
+/*****************************************************************************/
+
+static void
+test_unbase64mem1(void)
+{
+ nm_auto_str_buf NMStrBuf encoded_wrapped = NM_STR_BUF_INIT(400, FALSE);
+ uint8_t data[4096];
+ int i_run;
+
+ /* Copied from systemd's TEST(base64mem_linebreak)
+ * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/test/test-hexdecoct.c#L280 */
+
+ for (i_run = 0; i_run < 20; i_run++) {
+ gs_free char *encoded = NULL;
+ gs_free guint8 *decoded = NULL;
+ gsize decoded_size;
+ guint64 n;
+ guint64 m;
+ guint64 i;
+ guint64 j;
+ gssize l;
+ int r;
+
+ /* Try a bunch of differently sized blobs */
+ n = nmtst_get_rand_uint64() % sizeof(data);
+ nmtst_rand_buf(NULL, data, n);
+
+ /* Break at various different columns */
+ m = 1 + (nmtst_get_rand_uint64() % (n + 5));
+
+ encoded = g_base64_encode(data, n);
+ g_assert(encoded);
+ l = strlen(encoded);
+
+ nm_str_buf_reset(&encoded_wrapped);
+ for (i = 0, j = 0; i < l; i++, j++) {
+ if (j == m) {
+ nm_str_buf_append_c(&encoded_wrapped, '\n');
+ j = 0;
+ }
+ nm_str_buf_append_c(&encoded_wrapped, encoded[i]);
+ }
+
+ g_assert_cmpint(strlen(nm_str_buf_get_str(&encoded_wrapped)), ==, encoded_wrapped.len);
+
+ r = nm_unbase64mem_full(nm_str_buf_get_str(&encoded_wrapped),
+ nmtst_get_rand_bool() ? SIZE_MAX : encoded_wrapped.len,
+ nmtst_get_rand_bool(),
+ &decoded,
+ &decoded_size);
+ g_assert_cmpint(r, >=, 0);
+ g_assert_cmpmem(data, n, decoded, decoded_size);
+
+ for (j = 0; j < encoded_wrapped.len; j++)
+ g_assert((nm_str_buf_get_str(&encoded_wrapped)[j] == '\n') == (j % (m + 1) == m));
+ }
+}
+
+/*****************************************************************************/
+
+static void
+_assert_unbase64mem(const char *input, const char *output, int ret)
+{
+ gs_free guint8 *buffer = NULL;
+ gsize size = 0;
+ int r;
+
+ r = nm_unbase64mem_full(input, SIZE_MAX, nmtst_get_rand_bool(), &buffer, &size);
+ g_assert_cmpint(r, ==, ret);
+
+ if (ret >= 0) {
+ g_assert_cmpmem(buffer, size, output, strlen(output));
+ g_assert_cmpint(((const char *) buffer)[size], ==, '\0');
+ } else {
+ g_assert(!buffer);
+ g_assert_cmpint(size, ==, 0);
+ }
+}
+
+static void
+test_unbase64mem2(void)
+{
+ /* Copied from systemd's TEST(unbase64mem)
+ * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/test/test-hexdecoct.c#L324 */
+
+ _assert_unbase64mem("", "", 0);
+ _assert_unbase64mem("Zg==", "f", 0);
+ _assert_unbase64mem("Zm8=", "fo", 0);
+ _assert_unbase64mem("Zm9v", "foo", 0);
+ _assert_unbase64mem("Zm9vYg==", "foob", 0);
+ _assert_unbase64mem("Zm9vYmE=", "fooba", 0);
+ _assert_unbase64mem("Zm9vYmFy", "foobar", 0);
+
+ _assert_unbase64mem(" ", "", 0);
+ _assert_unbase64mem(" \n\r ", "", 0);
+ _assert_unbase64mem(" Zg\n== ", "f", 0);
+ _assert_unbase64mem(" Zm 8=\r", "fo", 0);
+ _assert_unbase64mem(" Zm9\n\r\r\nv ", "foo", 0);
+ _assert_unbase64mem(" Z m9vYg==\n\r", "foob", 0);
+ _assert_unbase64mem(" Zm 9vYmE= ", "fooba", 0);
+ _assert_unbase64mem(" Z m9v YmFy ", "foobar", 0);
+
+ _assert_unbase64mem("A", NULL, -EPIPE);
+ _assert_unbase64mem("A====", NULL, -EINVAL);
+ _assert_unbase64mem("AAB==", NULL, -EINVAL);
+ _assert_unbase64mem(" A A A B = ", NULL, -EINVAL);
+ _assert_unbase64mem(" Z m 8 = q u u x ", NULL, -ENAMETOOLONG);
+}
+
+/*****************************************************************************/
+
+static void
+_test_unbase64mem_mem(const char *base64, const guint8 *expected_arr, gsize expected_len)
+{
+ gs_free char *expected_base64 = NULL;
+ int r;
+ nm_auto_free guint8 *exp2_arr = NULL;
+ nm_auto_free guint8 *exp3_arr = NULL;
+ gsize exp2_len;
+ gsize exp3_len;
+
+ expected_base64 = g_base64_encode(expected_arr, expected_len);
+
+ r = nm_unbase64mem_full(expected_base64, strlen(expected_base64), TRUE, &exp2_arr, &exp2_len);
+ g_assert_cmpint(r, ==, 0);
+ g_assert_cmpmem(expected_arr, expected_len, exp2_arr, exp2_len);
+
+ if (!nm_streq(base64, expected_base64)) {
+ r = nm_unbase64mem_full(base64, strlen(base64), TRUE, &exp3_arr, &exp3_len);
+ g_assert_cmpint(r, ==, 0);
+ g_assert_cmpmem(expected_arr, expected_len, exp3_arr, exp3_len);
+ }
+}
+
+#define _test_unbase64mem(base64, expected_str) \
+ _test_unbase64mem_mem(base64, (const guint8 *) "" expected_str "", NM_STRLEN(expected_str))
+
+static void
+_test_unbase64mem_inval(const char *base64)
+{
+ gs_free guint8 *exp_arr = NULL;
+ gsize exp_len = 0;
+ int r;
+
+ r = nm_unbase64mem_full(base64, strlen(base64), TRUE, &exp_arr, &exp_len);
+ g_assert_cmpint(r, <, 0);
+ g_assert(!exp_arr);
+ g_assert(exp_len == 0);
+}
+
+static void
+test_unbase64mem3(void)
+{
+ gs_free char *rnd_base64 = NULL;
+ guint8 rnd_buf[30];
+ guint i, rnd_len;
+
+ _test_unbase64mem("", "");
+ _test_unbase64mem(" ", "");
+ _test_unbase64mem(" Y Q == ", "a");
+ _test_unbase64mem(" Y WJjZGV mZ 2g = ", "abcdefgh");
+ _test_unbase64mem_inval(" Y %WJjZGV mZ 2g = ");
+ _test_unbase64mem_inval(" Y %WJjZGV mZ 2g = a");
+ _test_unbase64mem("YQ==", "a");
+ _test_unbase64mem_inval("YQ==a");
+
+ rnd_len = nmtst_get_rand_uint32() % sizeof(rnd_buf);
+ for (i = 0; i < rnd_len; i++)
+ rnd_buf[i] = nmtst_get_rand_uint32() % 256;
+ rnd_base64 = g_base64_encode(rnd_buf, rnd_len);
+ _test_unbase64mem_mem(rnd_base64, rnd_buf, rnd_len);
+}
+
+/*****************************************************************************/
+
+static void
+assert_path_compare(const char *a, const char *b, int expected)
+{
+ int r;
+
+ g_assert(NM_IN_SET(expected, -1, 0, 1));
+
+ g_assert_cmpint(nm_path_compare(a, a), ==, 0);
+ g_assert_cmpint(nm_path_compare(b, b), ==, 0);
+
+ r = nm_path_compare(a, b);
+ g_assert_cmpint(r, ==, expected);
+ r = nm_path_compare(b, a);
+ g_assert_cmpint(r, ==, -expected);
+
+ g_assert(nm_path_equal(a, a) == 1);
+ g_assert(nm_path_equal(b, b) == 1);
+ g_assert(nm_path_equal(a, b) == (expected == 0));
+ g_assert(nm_path_equal(b, a) == (expected == 0));
+}
+
+static void
+test_path_compare(void)
+{
+ /* Copied from systemd.
+ * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/test/test-path-util.c#L126 */
+
+ assert_path_compare("/goo", "/goo", 0);
+ assert_path_compare("/goo", "/goo", 0);
+ assert_path_compare("//goo", "/goo", 0);
+ assert_path_compare("//goo/////", "/goo", 0);
+ assert_path_compare("goo/////", "goo", 0);
+ assert_path_compare("/goo/boo", "/goo//boo", 0);
+ assert_path_compare("//goo/boo", "/goo/boo//", 0);
+ assert_path_compare("//goo/././//./boo//././//", "/goo/boo//.", 0);
+ assert_path_compare("/.", "//.///", 0);
+ assert_path_compare("/x", "x/", 1);
+ assert_path_compare("x/", "/", -1);
+ assert_path_compare("/x/./y", "x/y", 1);
+ assert_path_compare("/x/./y", "/x/y", 0);
+ assert_path_compare("/x/./././y", "/x/y/././.", 0);
+ assert_path_compare("./x/./././y", "./x/y/././.", 0);
+ assert_path_compare(".", "./.", 0);
+ assert_path_compare(".", "././.", 0);
+ assert_path_compare("./..", ".", 1);
+ assert_path_compare("x/.y", "x/y", -1);
+ assert_path_compare("foo", "/foo", -1);
+ assert_path_compare("/foo", "/foo/bar", -1);
+ assert_path_compare("/foo/aaa", "/foo/b", -1);
+ assert_path_compare("/foo/aaa", "/foo/b/a", -1);
+ assert_path_compare("/foo/a", "/foo/aaa", -1);
+ assert_path_compare("/foo/a/b", "/foo/aaa", -1);
+}
+
+/*****************************************************************************/
+
+static void
+test_path_equal(void)
+{
+#define _path_equal_check(path, expected) \
+ G_STMT_START \
+ { \
+ const char *_path0 = (path); \
+ const char *_expected = (expected); \
+ gs_free char *_path = g_strdup(_path0); \
+ const char *_path_result; \
+ \
+ _path_result = nm_path_simplify(_path); \
+ g_assert(_path_result == _path); \
+ g_assert_cmpstr(_path, ==, _expected); \
+ } \
+ G_STMT_END
+
+ _path_equal_check("", "");
+ _path_equal_check(".", ".");
+ _path_equal_check("..", "..");
+ _path_equal_check("/..", "/..");
+ _path_equal_check("//..", "/..");
+ _path_equal_check("/.", "/");
+ _path_equal_check("./", ".");
+ _path_equal_check("./.", ".");
+ _path_equal_check(".///.", ".");
+ _path_equal_check(".///./", ".");
+ _path_equal_check(".////", ".");
+ _path_equal_check("//..//foo/", "/../foo");
+ _path_equal_check("///foo//./bar/.", "/foo/bar");
+ _path_equal_check(".//./foo//./bar/.", "foo/bar");
+}
+
+/*****************************************************************************/
+
+static void
+assert_path_find_first_component(const char *path,
+ gboolean accept_dot_dot,
+ const char *const *expected,
+ int ret)
+{
+ const char *p;
+
+ for (p = path;;) {
+ const char *e;
+ int r;
+
+ r = nm_path_find_first_component(&p, accept_dot_dot, &e);
+ if (r <= 0) {
+ if (r == 0) {
+ if (path)
+ g_assert(p == path + strlen(path));
+ else
+ g_assert(!p);
+ g_assert(!e);
+ }
+ g_assert(r == ret);
+ g_assert(!expected || !*expected);
+ return;
+ }
+
+ g_assert(e);
+ g_assert(strcspn(e, "/") == (size_t) r);
+ g_assert(strlen(*expected) == (size_t) r);
+ g_assert(strncmp(e, *expected++, r) == 0);
+ }
+}
+
+static void
+test_path_find_first_component(void)
+{
+ gs_free char *hoge = NULL;
+ char foo[NAME_MAX * 2];
+
+ /* Copied from systemd.
+ * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/test/test-path-util.c#L631 */
+
+ assert_path_find_first_component(NULL, false, NULL, 0);
+ assert_path_find_first_component("", false, NULL, 0);
+ assert_path_find_first_component("/", false, NULL, 0);
+ assert_path_find_first_component(".", false, NULL, 0);
+ assert_path_find_first_component("./", false, NULL, 0);
+ assert_path_find_first_component("./.", false, NULL, 0);
+ assert_path_find_first_component("..", false, NULL, -EINVAL);
+ assert_path_find_first_component("/..", false, NULL, -EINVAL);
+ assert_path_find_first_component("./..", false, NULL, -EINVAL);
+ assert_path_find_first_component("////./././//.", false, NULL, 0);
+ assert_path_find_first_component("a/b/c", false, NM_MAKE_STRV("a", "b", "c"), 0);
+ assert_path_find_first_component("././//.///aa/bbb//./ccc",
+ false,
+ NM_MAKE_STRV("aa", "bbb", "ccc"),
+ 0);
+ assert_path_find_first_component("././//.///aa/.../../bbb//./ccc/.",
+ false,
+ NM_MAKE_STRV("aa", "..."),
+ -EINVAL);
+ assert_path_find_first_component("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.",
+ false,
+ NM_MAKE_STRV("aaa", ".bbb"),
+ -EINVAL);
+ assert_path_find_first_component("a/foo./b", false, NM_MAKE_STRV("a", "foo.", "b"), 0);
+
+ assert_path_find_first_component(NULL, true, NULL, 0);
+ assert_path_find_first_component("", true, NULL, 0);
+ assert_path_find_first_component("/", true, NULL, 0);
+ assert_path_find_first_component(".", true, NULL, 0);
+ assert_path_find_first_component("./", true, NULL, 0);
+ assert_path_find_first_component("./.", true, NULL, 0);
+ assert_path_find_first_component("..", true, NM_MAKE_STRV(".."), 0);
+ assert_path_find_first_component("/..", true, NM_MAKE_STRV(".."), 0);
+ assert_path_find_first_component("./..", true, NM_MAKE_STRV(".."), 0);
+ assert_path_find_first_component("////./././//.", true, NULL, 0);
+ assert_path_find_first_component("a/b/c", true, NM_MAKE_STRV("a", "b", "c"), 0);
+ assert_path_find_first_component("././//.///aa/bbb//./ccc",
+ true,
+ NM_MAKE_STRV("aa", "bbb", "ccc"),
+ 0);
+ assert_path_find_first_component("././//.///aa/.../../bbb//./ccc/.",
+ true,
+ NM_MAKE_STRV("aa", "...", "..", "bbb", "ccc"),
+ 0);
+ assert_path_find_first_component("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.",
+ true,
+ NM_MAKE_STRV("aaa", ".bbb", "..", "c.", "d.dd", "..eeee"),
+ 0);
+ assert_path_find_first_component("a/foo./b", true, NM_MAKE_STRV("a", "foo.", "b"), 0);
+
+ memset(foo, 'a', sizeof(foo) - 1);
+ foo[sizeof(foo) - 1] = '\0';
+
+ assert_path_find_first_component(foo, false, NULL, -EINVAL);
+ assert_path_find_first_component(foo, true, NULL, -EINVAL);
+
+ hoge = g_strjoin("", "a/b/c/", foo, "//d/e/.//f/", NULL);
+ g_assert(hoge);
+
+ assert_path_find_first_component(hoge, false, NM_MAKE_STRV("a", "b", "c"), -EINVAL);
+ assert_path_find_first_component(hoge, true, NM_MAKE_STRV("a", "b", "c"), -EINVAL);
+}
+
+/*****************************************************************************/
+
+static void
+assert_path_startswith(const char *path,
+ const char *prefix,
+ const char *skipped,
+ const char *expected)
+{
+ const char *p;
+
+ p = nm_path_startswith(path, prefix);
+ g_assert_cmpstr(p, ==, expected);
+ if (p) {
+ gs_free char *q = NULL;
+
+ g_assert(skipped);
+ q = g_strjoin("", skipped, p, NULL);
+ g_assert_cmpstr(q, ==, path);
+ g_assert(p == path + strlen(skipped));
+ } else
+ g_assert(!skipped);
+}
+
+static void
+test_path_startswith(void)
+{
+ assert_path_startswith("/foo/bar/barfoo/", "/foo", "/foo/", "bar/barfoo/");
+ assert_path_startswith("/foo/bar/barfoo/", "/foo/", "/foo/", "bar/barfoo/");
+ assert_path_startswith("/foo/bar/barfoo/", "/", "/", "foo/bar/barfoo/");
+ assert_path_startswith("/foo/bar/barfoo/", "////", "/", "foo/bar/barfoo/");
+ assert_path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///", "/foo/bar/barfoo/", "");
+ assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo////", "/foo/bar/barfoo/", "");
+ assert_path_startswith("/foo/bar/barfoo/", "/foo/bar///barfoo/", "/foo/bar/barfoo/", "");
+ assert_path_startswith("/foo/bar/barfoo/", "/foo////bar/barfoo/", "/foo/bar/barfoo/", "");
+ assert_path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/", "/foo/bar/barfoo/", "");
+ assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo", "/foo/bar/barfoo/", "");
+
+ assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/", NULL, NULL);
+ assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa", NULL, NULL);
+ assert_path_startswith("/foo/bar/barfoo/", "", NULL, NULL);
+ assert_path_startswith("/foo/bar/barfoo/", "/bar/foo", NULL, NULL);
+ assert_path_startswith("/foo/bar/barfoo/", "/f/b/b/", NULL, NULL);
+ assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfo", NULL, NULL);
+ assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/bar", NULL, NULL);
+ assert_path_startswith("/foo/bar/barfoo/", "/fo", NULL, NULL);
+}
+
+/*****************************************************************************/
+
+static void
+assert_path_simplify(const char *in, const char *out)
+{
+ gs_free char *p = NULL;
+
+ g_assert(in);
+ p = g_strdup(in);
+ nm_path_simplify(p);
+ g_assert_cmpstr(p, ==, out);
+}
+
+static void
+test_path_simplify(void)
+{
+ gs_free char *hoge = NULL;
+ gs_free char *hoge_out = NULL;
+ char foo[NAME_MAX * 2];
+
+ assert_path_simplify("", "");
+ assert_path_simplify("aaa/bbb////ccc", "aaa/bbb/ccc");
+ assert_path_simplify("//aaa/.////ccc", "/aaa/ccc");
+ assert_path_simplify("///", "/");
+ assert_path_simplify("///.//", "/");
+ assert_path_simplify("///.//.///", "/");
+ assert_path_simplify("////.././///../.", "/../..");
+ assert_path_simplify(".", ".");
+ assert_path_simplify("./", ".");
+ assert_path_simplify(".///.//./.", ".");
+ assert_path_simplify(".///.//././/", ".");
+ assert_path_simplify("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.",
+ "/aaa/.bbb/../c./d.dd/..eeee");
+ assert_path_simplify("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
+ "/aaa/.bbb/../c./d.dd/..eeee/..");
+ assert_path_simplify(".//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
+ "aaa/.bbb/../c./d.dd/..eeee/..");
+ assert_path_simplify("..//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
+ "../aaa/.bbb/../c./d.dd/..eeee/..");
+
+ memset(foo, 'a', sizeof(foo) - 1);
+ foo[sizeof(foo) - 1] = '\0';
+
+ assert_path_simplify(foo, foo);
+
+ hoge = g_strjoin("", "/", foo, NULL);
+ g_assert(hoge);
+ assert_path_simplify(hoge, hoge);
+ nm_clear_g_free(&hoge);
+
+ hoge =
+ g_strjoin("", "a////.//././//./b///././/./c/////././//./", foo, "//.//////d/e/.//f/", NULL);
+ g_assert(hoge);
+
+ hoge_out = g_strjoin("", "a/b/c/", foo, "//.//////d/e/.//f/", NULL);
+ g_assert(hoge_out);
+
+ assert_path_simplify(hoge, hoge_out);
+}
+
+/*****************************************************************************/
+
+static void
+test_hostname_is_valid(void)
+{
+ g_assert(nm_hostname_is_valid("foobar", FALSE));
+ g_assert(nm_hostname_is_valid("foobar.com", FALSE));
+ g_assert(!nm_hostname_is_valid("foobar.com.", FALSE));
+ g_assert(nm_hostname_is_valid("fooBAR", FALSE));
+ g_assert(nm_hostname_is_valid("fooBAR.com", FALSE));
+ g_assert(!nm_hostname_is_valid("fooBAR.", FALSE));
+ g_assert(!nm_hostname_is_valid("fooBAR.com.", FALSE));
+ g_assert(!nm_hostname_is_valid("fƶƶbar", FALSE));
+ g_assert(!nm_hostname_is_valid("", FALSE));
+ g_assert(!nm_hostname_is_valid(".", FALSE));
+ g_assert(!nm_hostname_is_valid("..", FALSE));
+ g_assert(!nm_hostname_is_valid("foobar.", FALSE));
+ g_assert(!nm_hostname_is_valid(".foobar", FALSE));
+ g_assert(!nm_hostname_is_valid("foo..bar", FALSE));
+ g_assert(!nm_hostname_is_valid("foo.bar..", FALSE));
+
+ G_STATIC_ASSERT_EXPR(NM_HOST_NAME_MAX <= HOST_NAME_MAX);
+
+#define _assert_hostname_length(n, valid) \
+ G_STMT_START \
+ { \
+ const gsize _n = (n); \
+ gs_free char *_h = g_strnfill(_n, 'x'); \
+ gboolean _valid; \
+ \
+ _valid = nm_hostname_is_valid(_h, FALSE); \
+ g_assert_cmpint(_valid, ==, (valid)); \
+ } \
+ G_STMT_END
+
+ _assert_hostname_length(NM_HOST_NAME_MAX - 10, TRUE);
+ _assert_hostname_length(NM_HOST_NAME_MAX - 1, TRUE);
+ _assert_hostname_length(NM_HOST_NAME_MAX, TRUE);
+ _assert_hostname_length(NM_HOST_NAME_MAX + 1, FALSE);
+ _assert_hostname_length(NM_HOST_NAME_MAX + 10, FALSE);
+
+ g_assert(!nm_hostname_is_valid(
+ "au-xph5-rvgrdsb5hcxc-47et3a5vvkrc-server-wyoz4elpdpe3.openstack.local",
+ FALSE));
+
+ g_assert(nm_hostname_is_valid("foobar", TRUE));
+ g_assert(nm_hostname_is_valid("foobar.com", TRUE));
+ g_assert(nm_hostname_is_valid("foobar.com.", TRUE));
+ g_assert(nm_hostname_is_valid("fooBAR", TRUE));
+ g_assert(nm_hostname_is_valid("fooBAR.com", TRUE));
+ g_assert(!nm_hostname_is_valid("fooBAR.", TRUE));
+ g_assert(nm_hostname_is_valid("fooBAR.com.", TRUE));
+ g_assert(!nm_hostname_is_valid("fƶƶbar", TRUE));
+ g_assert(!nm_hostname_is_valid("", TRUE));
+ g_assert(!nm_hostname_is_valid(".", TRUE));
+ g_assert(!nm_hostname_is_valid("..", TRUE));
+ g_assert(!nm_hostname_is_valid("foobar.", TRUE));
+ g_assert(!nm_hostname_is_valid(".foobar", TRUE));
+ g_assert(!nm_hostname_is_valid("foo..bar", TRUE));
+ g_assert(!nm_hostname_is_valid("foo.bar..", TRUE));
+ g_assert(
+ nm_hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ TRUE));
+ g_assert(
+ !nm_hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ TRUE));
+}
+
+/*****************************************************************************/
+
NMTST_DEFINE();
int
@@ -1450,6 +2234,17 @@ main(int argc, char **argv)
g_test_add_func("/general/test_utils_hashtable_cmp", test_utils_hashtable_cmp);
g_test_add_func("/general/test_nm_g_source_sentinel", test_nm_g_source_sentinel);
g_test_add_func("/general/test_nm_ascii", test_nm_ascii);
+ g_test_add_func("/general/test_parse_env_file", test_parse_env_file);
+ g_test_add_func("/general/test_unbase64char", test_unbase64char);
+ g_test_add_func("/general/test_unbase64mem1", test_unbase64mem1);
+ g_test_add_func("/general/test_unbase64mem2", test_unbase64mem2);
+ g_test_add_func("/general/test_unbase64mem3", test_unbase64mem3);
+ g_test_add_func("/general/test_path_compare", test_path_compare);
+ g_test_add_func("/general/test_path_equal", test_path_equal);
+ g_test_add_func("/general/test_path_find_first_component", test_path_find_first_component);
+ g_test_add_func("/general/test_path_startswith", test_path_startswith);
+ g_test_add_func("/general/test_path_simplify", test_path_simplify);
+ g_test_add_func("/general/test_hostname_is_valid", test_hostname_is_valid);
return g_test_run();
}
diff --git a/src/libnm-log-core/nm-logging.c b/src/libnm-log-core/nm-logging.c
index f464ef296d..5cce508daf 100644
--- a/src/libnm-log-core/nm-logging.c
+++ b/src/libnm-log-core/nm-logging.c
@@ -468,7 +468,7 @@ _domains_to_string(gboolean include_level_override,
* nm_logging_setup(), because we want to expand "DEFAULT" and "ALL".
*/
- nm_str_buf_init(&sbuf, NM_UTILS_GET_NEXT_REALLOC_SIZE_40, FALSE);
+ sbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_40, FALSE);
for (diter = &domain_desc[0]; diter->name; diter++) {
/* If it's set for any lower level, it will also be set for LOGL_ERR */
diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h
index 5c72fade99..a4cba9ced8 100644
--- a/src/libnm-platform/nm-platform.h
+++ b/src/libnm-platform/nm-platform.h
@@ -333,6 +333,9 @@ typedef enum {
* should be configured. */ \
bool a_force_commit : 1; \
\
+ /* Don't have a bitfield as last field in __NMPlatformIPAddress_COMMON. It would then
+ * be unclear how the following fields get merged. We could also use a zero bitfield,
+ * but instead we just have there the uint8 field. */ \
guint8 plen; \
;
@@ -343,10 +346,7 @@ typedef enum {
**/
typedef struct {
__NMPlatformIPAddress_COMMON;
- union {
- guint8 address_ptr[1];
- guint32 __dummy_for_32bit_alignment;
- };
+ _nm_alignas(NMIPAddr) guint8 address_ptr[];
} NMPlatformIPAddress;
/**
@@ -358,11 +358,15 @@ struct _NMPlatformIP4Address {
/* Whether the address is ready to be configured. By default, an address is, but this
* flag may indicate that the address is just for tracking purpose only, but the ACD
- * state is not yet ready for the address to be configured. */
+ * state is not yet ready for the address to be configured.
+ *
+ * This bit fits actually in an alignment gap between __NMPlatformIPAddress_COMMON and
+ * "address" field. Usually "address" must be the first field after __NMPlatformIPAddress_COMMON,
+ * but there is a gap. We have a static assertion that checks this, so all is good. */
bool a_acd_not_ready : 1;
/* The local address IFA_LOCAL. */
- in_addr_t address;
+ _nm_alignas(NMIPAddr) in_addr_t address;
/* The IFA_ADDRESS PTP peer address. This field is rather important, because
* it constitutes the identifier for the IPv4 address (e.g. you can add two
@@ -390,7 +394,7 @@ struct _NMPlatformIP4Address {
**/
struct _NMPlatformIP6Address {
__NMPlatformIPAddress_COMMON;
- struct in6_addr address;
+ _nm_alignas(NMIPAddr) struct in6_addr address;
struct in6_addr peer_address;
};
@@ -426,6 +430,47 @@ typedef union {
#define __NMPlatformIPRoute_COMMON \
__NMPlatformObjWithIfindex_COMMON; \
\
+ /* rtnh_flags
+ *
+ * Routes with rtm_flags RTM_F_CLONED are hidden by platform and
+ * do not exist from the point-of-view of platform users.
+ * Such a route is not alive, according to nmp_object_is_alive().
+ *
+ * NOTE: currently we ignore all flags except RTM_F_CLONED
+ * and RTNH_F_ONLINK.
+ * We also may not properly consider the flags as part of the ID
+ * in route-cmp. */ \
+ unsigned r_rtm_flags; \
+ \
+ /* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \
+ guint32 mss; \
+ \
+ /* RTA_METRICS.RTAX_WINDOW (iproute2: window) */ \
+ guint32 window; \
+ \
+ /* RTA_METRICS.RTAX_CWND (iproute2: cwnd) */ \
+ guint32 cwnd; \
+ \
+ /* RTA_METRICS.RTAX_INITCWND (iproute2: initcwnd) */ \
+ guint32 initcwnd; \
+ \
+ /* RTA_METRICS.RTAX_INITRWND (iproute2: initrwnd) */ \
+ guint32 initrwnd; \
+ \
+ /* RTA_METRICS.RTAX_MTU (iproute2: mtu) */ \
+ guint32 mtu; \
+ \
+ /* RTA_PRIORITY (iproute2: metric)
+ * If "metric_any" is %TRUE, then this is interpreted as an offset that will be
+ * added to a default base metric. In such cases, the offset is usually zero. */ \
+ guint32 metric; \
+ \
+ /* rtm_table, RTA_TABLE.
+ *
+ * This is not the original table ID. Instead, 254 (RT_TABLE_MAIN) and
+ * zero (RT_TABLE_UNSPEC) are swapped, so that the default is the main
+ * table. Use nm_platform_route_table_coerce()/nm_platform_route_table_uncoerce(). */ \
+ guint32 table_coerced; \
/* The NMIPConfigSource. For routes that we receive from cache this corresponds
* to the rtm_protocol field (and is one of the NM_IP_CONFIG_SOURCE_RTPROT_* values).
* When adding a route, the source will be coerced to the protocol using
@@ -440,8 +485,6 @@ typedef union {
* to zero, in which case the first matching route (with proto ignored) is deleted. */ \
NMIPConfigSource rt_source; \
\
- guint8 plen; \
- \
/* RTA_METRICS:
*
* For IPv4 routes, these properties are part of their
@@ -480,62 +523,22 @@ typedef union {
/* Whether the route should be committed even if it was removed externally. */ \
bool r_force_commit : 1; \
\
- /* rtnh_flags
- *
- * Routes with rtm_flags RTM_F_CLONED are hidden by platform and
- * do not exist from the point-of-view of platform users.
- * Such a route is not alive, according to nmp_object_is_alive().
- *
- * NOTE: currently we ignore all flags except RTM_F_CLONED
- * and RTNH_F_ONLINK.
- * We also may not properly consider the flags as part of the ID
- * in route-cmp. */ \
- unsigned r_rtm_flags; \
- \
- /* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \
- guint32 mss; \
- \
- /* RTA_METRICS.RTAX_WINDOW (iproute2: window) */ \
- guint32 window; \
- \
- /* RTA_METRICS.RTAX_CWND (iproute2: cwnd) */ \
- guint32 cwnd; \
- \
- /* RTA_METRICS.RTAX_INITCWND (iproute2: initcwnd) */ \
- guint32 initcwnd; \
- \
- /* RTA_METRICS.RTAX_INITRWND (iproute2: initrwnd) */ \
- guint32 initrwnd; \
- \
- /* RTA_METRICS.RTAX_MTU (iproute2: mtu) */ \
- guint32 mtu; \
- \
- /* RTA_PRIORITY (iproute2: metric)
- * If "metric_any" is %TRUE, then this is interpreted as an offset that will be
- * added to a default base metric. In such cases, the offset is usually zero. */ \
- guint32 metric; \
- \
- /* rtm_table, RTA_TABLE.
- *
- * This is not the original table ID. Instead, 254 (RT_TABLE_MAIN) and
- * zero (RT_TABLE_UNSPEC) are swapped, so that the default is the main
- * table. Use nm_platform_route_table_coerce()/nm_platform_route_table_uncoerce(). */ \
- guint32 table_coerced; \
- \
/* rtm_type.
*
* This is not the original type, if type_coerced is 0 then
* it means RTN_UNSPEC otherwise the type value is preserved.
- * */ \
+ */ \
guint8 type_coerced; \
+ \
+ /* Don't have a bitfield as last field in __NMPlatformIPAddress_COMMON. It would then
+ * be unclear how the following fields get merged. We could also use a zero bitfield,
+ * but instead we just have there the uint8 field. */ \
+ guint8 plen; \
;
typedef struct {
__NMPlatformIPRoute_COMMON;
- union {
- guint8 network_ptr[1];
- guint32 __dummy_for_32bit_alignment;
- };
+ _nm_alignas(NMIPAddr) guint8 network_ptr[];
} NMPlatformIPRoute;
#define NM_PLATFORM_IP_ROUTE_CAST(route) \
@@ -827,10 +830,10 @@ typedef struct {
} NMPlatformVFVlan;
typedef struct {
+ guint num_vlans;
guint32 index;
guint32 min_tx_rate;
guint32 max_tx_rate;
- guint num_vlans;
NMPlatformVFVlan *vlans;
struct {
guint8 data[20]; /* _NM_UTILS_HWADDR_LEN_MAX */
@@ -848,41 +851,41 @@ typedef struct {
} NMPlatformBridgeVlan;
typedef struct {
- NMEtherAddr group_addr;
- bool mcast_querier : 1;
- bool mcast_query_use_ifaddr : 1;
- bool mcast_snooping : 1;
- bool stp_state : 1;
- bool vlan_stats_enabled : 1;
- guint16 group_fwd_mask;
- guint16 priority;
- guint16 vlan_protocol;
- guint32 ageing_time;
- guint32 forward_delay;
- guint32 hello_time;
- guint32 max_age;
- guint32 mcast_last_member_count;
- guint32 mcast_startup_query_count;
- guint32 mcast_hash_max;
guint64 mcast_last_member_interval;
guint64 mcast_membership_interval;
guint64 mcast_querier_interval;
guint64 mcast_query_interval;
guint64 mcast_query_response_interval;
guint64 mcast_startup_query_interval;
+ guint32 ageing_time;
+ guint32 forward_delay;
+ guint32 hello_time;
+ guint32 max_age;
+ guint32 mcast_hash_max;
+ guint32 mcast_last_member_count;
+ guint32 mcast_startup_query_count;
+ guint16 group_fwd_mask;
+ guint16 priority;
+ guint16 vlan_protocol;
+ NMEtherAddr group_addr;
guint8 mcast_router;
+ bool mcast_querier : 1;
+ bool mcast_query_use_ifaddr : 1;
+ bool mcast_snooping : 1;
+ bool stp_state : 1;
+ bool vlan_stats_enabled : 1;
} NMPlatformLnkBridge;
extern const NMPlatformLnkBridge nm_platform_lnk_bridge_default;
typedef struct {
+ int parent_ifindex;
in_addr_t local;
in_addr_t remote;
- int parent_ifindex;
- guint16 input_flags;
- guint16 output_flags;
guint32 input_key;
guint32 output_key;
+ guint16 input_flags;
+ guint16 output_flags;
guint8 ttl;
guint8 tos;
bool path_mtu_discovery : 1;
@@ -898,12 +901,12 @@ typedef struct {
struct in6_addr local;
struct in6_addr remote;
int parent_ifindex;
+ guint flow_label;
+ guint32 flags;
guint8 ttl;
guint8 tclass;
guint8 encap_limit;
guint8 proto;
- guint flow_label;
- guint32 flags;
/* IP6GRE only */
guint32 input_key;
@@ -915,9 +918,9 @@ typedef struct {
} NMPlatformLnkIp6Tnl;
typedef struct {
+ int parent_ifindex;
in_addr_t local;
in_addr_t remote;
- int parent_ifindex;
guint8 ttl;
guint8 tos;
bool path_mtu_discovery : 1;
@@ -946,9 +949,9 @@ typedef struct {
} NMPlatformLnkMacvlan;
typedef struct {
+ int parent_ifindex;
in_addr_t local;
in_addr_t remote;
- int parent_ifindex;
guint16 flags;
guint8 ttl;
guint8 tos;
@@ -984,9 +987,9 @@ typedef struct {
typedef struct {
struct in6_addr group6;
struct in6_addr local6;
+ int parent_ifindex;
in_addr_t group;
in_addr_t local;
- int parent_ifindex;
guint32 id;
guint32 ageing;
guint32 limit;
diff --git a/src/libnm-std-aux/nm-default-std.h b/src/libnm-std-aux/nm-default-std.h
index 23f5fc604b..45c0d1538c 100644
--- a/src/libnm-std-aux/nm-default-std.h
+++ b/src/libnm-std-aux/nm-default-std.h
@@ -42,52 +42,52 @@
#if NM_MORE_ASSERTS == 0
/* The cast macros like NM_TYPE() are implemented via G_TYPE_CHECK_INSTANCE_CAST()
- * and _G_TYPE_CIC(). The latter, by default performs runtime checks of the type
- * by calling g_type_check_instance_cast().
- * This check has a certain overhead without being helpful.
- *
- * Example 1:
- * static void foo (NMType *obj)
- * {
- * access_obj_without_check (obj);
- * }
- * foo ((NMType *) obj);
- * // There is no runtime check and passing an invalid pointer
- * // leads to a crash.
- *
- * Example 2:
- * static void foo (NMType *obj)
- * {
- * access_obj_without_check (obj);
- * }
- * foo (NM_TYPE (obj));
- * // There is a runtime check which prints a g_warning(), but that doesn't
- * // avoid the crash as NM_TYPE() cannot do anything then passing on the
- * // invalid pointer.
- *
- * Example 3:
- * static void foo (NMType *obj)
- * {
- * g_return_if_fail (NM_IS_TYPE (obj));
- * access_obj_without_check (obj);
- * }
- * foo ((NMType *) obj);
- * // There is a runtime check which prints a g_critical() which also avoids
- * // the crash. That is actually helpful to catch bugs and avoid crashes.
- *
- * Example 4:
- * static void foo (NMType *obj)
- * {
- * g_return_if_fail (NM_IS_TYPE (obj));
- * access_obj_without_check (obj);
- * }
- * foo (NM_TYPE (obj));
- * // The runtime check is performed twice, with printing a g_warning() and
- * // a g_critical() and avoiding the crash.
- *
- * Example 3 is how it should be done. Type checks in NM_TYPE() are pointless.
- * Disable them for our production builds.
- */
+ * and _G_TYPE_CIC(). The latter, by default performs runtime checks of the type
+ * by calling g_type_check_instance_cast().
+ * This check has a certain overhead without being helpful.
+ *
+ * Example 1:
+ * static void foo (NMType *obj)
+ * {
+ * access_obj_without_check (obj);
+ * }
+ * foo ((NMType *) obj);
+ * // There is no runtime check and passing an invalid pointer
+ * // leads to a crash.
+ *
+ * Example 2:
+ * static void foo (NMType *obj)
+ * {
+ * access_obj_without_check (obj);
+ * }
+ * foo (NM_TYPE (obj));
+ * // There is a runtime check which prints a g_warning(), but that doesn't
+ * // avoid the crash as NM_TYPE() cannot do anything then passing on the
+ * // invalid pointer.
+ *
+ * Example 3:
+ * static void foo (NMType *obj)
+ * {
+ * g_return_if_fail (NM_IS_TYPE (obj));
+ * access_obj_without_check (obj);
+ * }
+ * foo ((NMType *) obj);
+ * // There is a runtime check which prints a g_critical() which also avoids
+ * // the crash. That is actually helpful to catch bugs and avoid crashes.
+ *
+ * Example 4:
+ * static void foo (NMType *obj)
+ * {
+ * g_return_if_fail (NM_IS_TYPE (obj));
+ * access_obj_without_check (obj);
+ * }
+ * foo (NM_TYPE (obj));
+ * // The runtime check is performed twice, with printing a g_warning() and
+ * // a g_critical() and avoiding the crash.
+ *
+ * Example 3 is how it should be done. Type checks in NM_TYPE() are pointless.
+ * Disable them for our production builds.
+ */
#ifndef G_DISABLE_CAST_CHECKS
#define G_DISABLE_CAST_CHECKS
#endif
@@ -99,4 +99,9 @@
/*****************************************************************************/
+#include "libnm-std-aux/nm-std-aux.h"
+#include "libnm-std-aux/nm-std-utils.h"
+
+/*****************************************************************************/
+
#endif /* __NM_DEFAULT_STD_H__ */
diff --git a/src/libnm-std-aux/nm-std-utils.h b/src/libnm-std-aux/nm-std-utils.h
index 76d49d2f5f..6aa787eb6a 100644
--- a/src/libnm-std-aux/nm-std-utils.h
+++ b/src/libnm-std-aux/nm-std-utils.h
@@ -14,12 +14,12 @@
* certain buffer sizes.
*
* The use of these defines is to get favorable allocation sequences.
- * For example, nm_str_buf_init() asks for an initial allocation size. Note that
+ * For example, NM_STR_BUF_INIT() asks for an initial allocation size. Note that
* it reserves the exactly requested amount, under the assumption that the
* user may know how many bytes will be required. However, often the caller
* doesn't know in advance, and NMStrBuf grows exponentially by calling
* nm_utils_get_next_realloc_size().
- * Imagine you call nm_str_buf_init() with an initial buffer size 100, and you
+ * Imagine you call NM_STR_BUF_INIT() with an initial buffer size 100, and you
* add one character at a time. Then the first reallocation will increase the
* buffer size only from 100 to 104.
* If you however start with an initial buffer size of 104, then the next reallocation
@@ -30,6 +30,7 @@
#define NM_UTILS_GET_NEXT_REALLOC_SIZE_40 ((size_t) 40)
#define NM_UTILS_GET_NEXT_REALLOC_SIZE_104 ((size_t) 104)
#define NM_UTILS_GET_NEXT_REALLOC_SIZE_232 ((size_t) 232)
+#define NM_UTILS_GET_NEXT_REALLOC_SIZE_488 ((size_t) 488)
#define NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 ((size_t) 1000)
size_t nm_utils_get_next_realloc_size(bool true_realloc, size_t requested);
diff --git a/src/libnm-systemd-core/meson.build b/src/libnm-systemd-core/meson.build
index 80b95c4224..70293a6154 100644
--- a/src/libnm-systemd-core/meson.build
+++ b/src/libnm-systemd-core/meson.build
@@ -3,20 +3,13 @@
libnm_systemd_core = static_library(
'nm-systemd-core',
sources: files(
- 'src/libsystemd-network/arp-util.c',
'src/libsystemd-network/dhcp-identifier.c',
- 'src/libsystemd-network/dhcp-network.c',
- 'src/libsystemd-network/dhcp-option.c',
- 'src/libsystemd-network/dhcp-packet.c',
'src/libsystemd-network/dhcp6-network.c',
'src/libsystemd-network/dhcp6-option.c',
'src/libsystemd-network/dhcp6-protocol.c',
'src/libsystemd-network/lldp-neighbor.c',
'src/libsystemd-network/lldp-network.c',
'src/libsystemd-network/network-common.c',
- 'src/libsystemd-network/network-internal.c',
- 'src/libsystemd-network/sd-dhcp-client.c',
- 'src/libsystemd-network/sd-dhcp-lease.c',
'src/libsystemd-network/sd-dhcp6-client.c',
'src/libsystemd-network/sd-dhcp6-lease.c',
'src/libsystemd-network/sd-lldp-rx.c',
@@ -25,8 +18,6 @@ libnm_systemd_core = static_library(
'src/libsystemd/sd-id128/id128-util.c',
'src/libsystemd/sd-id128/sd-id128.c',
'nm-sd.c',
- 'nm-sd-utils-core.c',
- 'nm-sd-utils-dhcp.c',
'sd-adapt-core/nm-sd-adapt-core.c',
),
include_directories: [
diff --git a/src/libnm-systemd-core/nm-sd-utils-core.c b/src/libnm-systemd-core/nm-sd-utils-core.c
deleted file mode 100644
index 21e8a3044e..0000000000
--- a/src/libnm-systemd-core/nm-sd-utils-core.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#include "libnm-systemd-core/nm-default-systemd-core.h"
-
-#include "nm-sd-utils-core.h"
-
-#include "libnm-glib-aux/nm-uuid.h"
-
-#include "nm-sd-adapt-core.h"
-
-#include "sd-id128.h"
-
-/*****************************************************************************/
-
-NMUuid *
-nm_sd_utils_id128_get_machine(NMUuid *out_uuid)
-{
- g_assert(out_uuid);
-
- G_STATIC_ASSERT_EXPR(sizeof(*out_uuid) == sizeof(sd_id128_t));
- if (sd_id128_get_machine((sd_id128_t *) out_uuid) < 0)
- return NULL;
- return out_uuid;
-}
diff --git a/src/libnm-systemd-core/nm-sd-utils-core.h b/src/libnm-systemd-core/nm-sd-utils-core.h
deleted file mode 100644
index ccad002989..0000000000
--- a/src/libnm-systemd-core/nm-sd-utils-core.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2018 Red Hat, Inc.
- */
-
-#ifndef __NM_SD_UTILS_CORE_H__
-#define __NM_SD_UTILS_CORE_H__
-
-/*****************************************************************************/
-
-struct _NMUuid;
-
-struct _NMUuid *nm_sd_utils_id128_get_machine(struct _NMUuid *out_uuid);
-
-/*****************************************************************************/
-
-#endif /* __NM_SD_UTILS_CORE_H__ */
diff --git a/src/libnm-systemd-core/nm-sd-utils-dhcp.c b/src/libnm-systemd-core/nm-sd-utils-dhcp.c
deleted file mode 100644
index 13c75055ec..0000000000
--- a/src/libnm-systemd-core/nm-sd-utils-dhcp.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019 Red Hat, Inc.
- */
-
-#include "libnm-systemd-core/nm-default-systemd-core.h"
-
-#include "nm-sd-utils-dhcp.h"
-
-#include "sd-adapt-core/nm-sd-adapt-core.h"
-#include "src/libsystemd-network/dhcp-lease-internal.h"
-
-int
-nm_sd_dhcp_lease_get_private_options(sd_dhcp_lease *lease, nm_sd_dhcp_option **out_options)
-{
- int cnt = 0;
-
- g_return_val_if_fail(lease, -EINVAL);
- g_return_val_if_fail(out_options, -EINVAL);
- g_return_val_if_fail(*out_options == NULL, -EINVAL);
-
- if (lease->private_options == NULL)
- return -ENODATA;
-
- LIST_FOREACH(options, raw_option, lease->private_options)
- cnt++;
-
- *out_options = g_new(nm_sd_dhcp_option, cnt);
- cnt = 0;
-
- LIST_FOREACH(options, raw_option, lease->private_options)
- {
- (*out_options)[cnt].code = raw_option->tag;
- (*out_options)[cnt].data = raw_option->data;
- (*out_options)[cnt].data_len = raw_option->length;
- cnt++;
- }
-
- return cnt;
-}
diff --git a/src/libnm-systemd-core/nm-sd-utils-dhcp.h b/src/libnm-systemd-core/nm-sd-utils-dhcp.h
deleted file mode 100644
index 6487a90dfe..0000000000
--- a/src/libnm-systemd-core/nm-sd-utils-dhcp.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019 Red Hat, Inc.
- */
-
-#ifndef __NETWORKMANAGER_DHCP_SYSTEMD_UTILS_H__
-#define __NETWORKMANAGER_DHCP_SYSTEMD_UTILS_H__
-
-#include "nm-sd.h"
-
-typedef struct {
- uint8_t code;
- uint8_t data_len;
- void *data;
-} nm_sd_dhcp_option;
-
-int nm_sd_dhcp_lease_get_private_options(sd_dhcp_lease *lease, nm_sd_dhcp_option **out_options);
-
-#endif /* __NETWORKMANAGER_DHCP_SYSTEMD_UTILS_H__ */
diff --git a/src/libnm-systemd-core/nm-sd.c b/src/libnm-systemd-core/nm-sd.c
index 9978a159c4..b512e3fcba 100644
--- a/src/libnm-systemd-core/nm-sd.c
+++ b/src/libnm-systemd-core/nm-sd.c
@@ -108,6 +108,5 @@ nm_sd_event_attach_default(void)
/* ensure that defines in nm-sd.h correspond to the internal defines. */
#include "nm-sd-adapt-core.h"
-#include "dhcp-lease-internal.h"
/*****************************************************************************/
diff --git a/src/libnm-systemd-core/nm-sd.h b/src/libnm-systemd-core/nm-sd.h
index 421f53729b..79bc503106 100644
--- a/src/libnm-systemd-core/nm-sd.h
+++ b/src/libnm-systemd-core/nm-sd.h
@@ -6,7 +6,6 @@
#ifndef __NM_SD_H__
#define __NM_SD_H__
-#include "src/systemd/sd-dhcp-client.h"
#include "src/systemd/sd-dhcp6-client.h"
#include "src/systemd/sd-lldp-rx.h"
@@ -14,15 +13,4 @@
guint nm_sd_event_attach_default(void);
-/*****************************************************************************
- * expose internal systemd API
- *
- * FIXME: don't use any internal systemd API.
- *****************************************************************************/
-
-struct sd_dhcp_lease;
-
-int dhcp_lease_save(struct sd_dhcp_lease *lease, const char *lease_file);
-int dhcp_lease_load(struct sd_dhcp_lease **ret, const char *lease_file);
-
#endif /* __NM_SD_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
deleted file mode 100644
index c8a73111b5..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/arp-util.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/***
- Copyright Ā© 2014 Axis Communications AB. All rights reserved.
-***/
-
-#include "nm-sd-adapt-core.h"
-
-#include <arpa/inet.h>
-#include <linux/filter.h>
-#include <netinet/if_ether.h>
-
-#include "arp-util.h"
-#include "ether-addr-util.h"
-#include "fd-util.h"
-#include "in-addr-util.h"
-#include "unaligned.h"
-#include "util.h"
-
-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 ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hrd)), /* A <- header */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), /* header == ethernet ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pro)), /* A <- protocol */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), /* protocol == IP ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hln)), /* A <- hardware address length */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct ether_addr), 1, 0), /* length == sizeof(ether_addr)? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pln)), /* A <- protocol address length */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct in_addr), 1, 0), /* length == sizeof(in_addr) ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_op)), /* A <- operation */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0), /* protocol == request ? */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), /* protocol == reply ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- /* Sender Hardware Address must be different from our own */
- BPF_STMT(BPF_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_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_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_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_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_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 = {
- .len = ELEMENTSOF(filter),
- .filter = (struct sock_filter*) filter,
- };
-
- assert(fd >= 0);
-
- if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0)
- return -errno;
-
- return 0;
-}
-
-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),
- .ll.sll_ifindex = ifindex,
- .ll.sll_halen = ETH_ALEN,
- .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
- };
- _cleanup_close_ int s = -1;
- int r;
-
- assert(ifindex > 0);
- assert(mac);
-
- s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
- if (s < 0)
- return -errno;
-
- r = arp_update_filter(s, a, mac);
- if (r < 0)
- return r;
-
- if (bind(s, &link.sa, sizeof(link.ll)) < 0)
- return -errno;
-
- return TAKE_FD(s);
-}
-
-int arp_send_packet(
- int fd,
- int ifindex,
- const struct in_addr *pa,
- const struct ether_addr *ha,
- bool announce) {
-
- union sockaddr_union link = {
- .ll.sll_family = AF_PACKET,
- .ll.sll_protocol = htobe16(ETH_P_ARP),
- .ll.sll_ifindex = ifindex,
- .ll.sll_halen = ETH_ALEN,
- .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
- };
- struct ether_arp arp = {
- .ea_hdr.ar_hrd = htobe16(ARPHRD_ETHER), /* HTYPE */
- .ea_hdr.ar_pro = htobe16(ETHERTYPE_IP), /* PTYPE */
- .ea_hdr.ar_hln = ETH_ALEN, /* HLEN */
- .ea_hdr.ar_pln = sizeof(struct in_addr), /* PLEN */
- .ea_hdr.ar_op = htobe16(ARPOP_REQUEST), /* REQUEST */
- };
- ssize_t n;
-
- assert(fd >= 0);
- assert(ifindex > 0);
- assert(pa);
- assert(in4_addr_is_set(pa));
- assert(ha);
- assert(!ether_addr_is_null(ha));
-
- memcpy(&arp.arp_sha, ha, ETH_ALEN);
- memcpy(&arp.arp_tpa, pa, sizeof(struct in_addr));
-
- if (announce)
- memcpy(&arp.arp_spa, pa, sizeof(struct in_addr));
-
- n = sendto(fd, &arp, sizeof(struct ether_arp), 0, &link.sa, sizeof(link.ll));
- if (n < 0)
- return -errno;
- if (n != sizeof(struct ether_arp))
- return -EIO;
-
- return 0;
-}
diff --git a/src/libnm-systemd-core/src/libsystemd-network/arp-util.h b/src/libnm-systemd-core/src/libsystemd-network/arp-util.h
deleted file mode 100644
index b66a81bf9b..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/arp-util.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-/***
- Copyright Ā© 2014 Axis Communications AB. All rights reserved.
-***/
-
-#include <net/ethernet.h>
-#include <netinet/in.h>
-
-#include "socket-util.h"
-#include "sparse-endian.h"
-
-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,
- int ifindex,
- const struct in_addr *pa,
- const struct ether_addr *ha,
- bool announce);
-static inline int arp_send_probe(
- int fd,
- int ifindex,
- const struct in_addr *pa,
- const struct ether_addr *ha) {
- return arp_send_packet(fd, ifindex, pa, ha, false);
-}
-static inline int arp_send_announcement(
- int fd,
- int ifindex,
- const struct in_addr *pa,
- const struct ether_addr *ha) {
- return arp_send_packet(fd, ifindex, pa, ha, true);
-}
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h
deleted file mode 100644
index 466d8e4b3f..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-/***
- Copyright Ā© 2013 Intel Corporation. All rights reserved.
-***/
-
-#include <linux/if_packet.h>
-#include <net/ethernet.h>
-#include <stdint.h>
-
-#include "sd-dhcp-client.h"
-
-#include "dhcp-protocol.h"
-#include "network-common.h"
-#include "socket-util.h"
-
-typedef struct sd_dhcp_option {
- unsigned n_ref;
-
- uint8_t option;
- void *data;
- size_t length;
-} sd_dhcp_option;
-
-typedef struct DHCPServerData {
- struct in_addr *addr;
- size_t size;
-} DHCPServerData;
-
-extern const struct hash_ops dhcp_option_hash_ops;
-
-typedef struct sd_dhcp_client sd_dhcp_client;
-
-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_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type);
-int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
- const void *packet, size_t len);
-int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
- const void *packet, size_t len);
-
-int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_t overload,
- uint8_t code, size_t optlen, const void *optval);
-int dhcp_option_find_option(uint8_t *options, size_t length, uint8_t wanted_code, size_t *ret_offset);
-int dhcp_option_remove_option(uint8_t *options, size_t buflen, uint8_t option_code);
-
-typedef int (*dhcp_option_callback_t)(uint8_t code, uint8_t len,
- const void *option, void *userdata);
-
-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, uint8_t hlen, const uint8_t *chaddr,
- size_t optlen, size_t *optoffset);
-
-uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len);
-
-void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
- uint16_t source, be32_t destination_addr,
- uint16_t destination, uint16_t len, int ip_service_type);
-
-int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port);
-
-void dhcp_client_set_test_mode(sd_dhcp_client *client, bool test_mode);
-
-/* If we are invoking callbacks of a dhcp-client, ensure unreffing the
- * client from the callback doesn't destroy the object we are working
- * on */
-#define DHCP_CLIENT_DONT_DESTROY(client) \
- _cleanup_(sd_dhcp_client_unrefp) _unused_ sd_dhcp_client *_dont_destroy_##client = sd_dhcp_client_ref(client)
-
-#define log_dhcp_client_errno(client, error, fmt, ...) \
- log_interface_prefix_full_errno( \
- "DHCPv4 client: ", \
- sd_dhcp_client, client, \
- error, fmt, ##__VA_ARGS__)
-#define log_dhcp_client(client, fmt, ...) \
- log_interface_prefix_full_errno_zerook( \
- "DHCPv4 client: ", \
- sd_dhcp_client, client, \
- 0, fmt, ##__VA_ARGS__)
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
deleted file mode 100644
index c67e9511a1..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-/***
- Copyright Ā© 2013 Intel Corporation. All rights reserved.
-***/
-
-#include "sd-dhcp-client.h"
-
-#include "dhcp-internal.h"
-#include "dhcp-protocol.h"
-#include "list.h"
-#include "util.h"
-
-struct sd_dhcp_route {
- struct in_addr dst_addr;
- struct in_addr gw_addr;
- unsigned char dst_prefixlen;
-};
-
-struct sd_dhcp_raw_option {
- LIST_FIELDS(struct sd_dhcp_raw_option, options);
-
- uint8_t tag;
- uint8_t length;
- void *data;
-};
-
-struct sd_dhcp_lease {
- unsigned n_ref;
-
- /* each 0 if unset */
- uint32_t t1;
- uint32_t t2;
- uint32_t lifetime;
-
- /* each 0 if unset */
- be32_t address;
- be32_t server_address;
- be32_t next_server;
-
- bool have_subnet_mask;
- be32_t subnet_mask;
-
- bool have_broadcast;
- be32_t broadcast;
-
- struct in_addr *router;
- size_t router_size;
-
- DHCPServerData servers[_SD_DHCP_LEASE_SERVER_TYPE_MAX];
-
- struct sd_dhcp_route *static_routes;
- size_t n_static_routes;
- struct sd_dhcp_route *classless_routes;
- size_t n_classless_routes;
-
- uint16_t mtu; /* 0 if unset */
-
- char *domainname;
- char **search_domains;
- char *hostname;
- char *root_path;
-
- void *client_id;
- size_t client_id_len;
-
- void *vendor_specific;
- size_t vendor_specific_len;
-
- 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);
-};
-
-int dhcp_lease_new(sd_dhcp_lease **ret);
-
-int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata);
-int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***domains);
-int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len);
-
-int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease);
-
-int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c
deleted file mode 100644
index 1c5f342754..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/***
- Copyright Ā© 2013 Intel Corporation. All rights reserved.
-***/
-
-#include "nm-sd-adapt-core.h"
-
-#include <errno.h>
-#include <net/ethernet.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <stdio.h>
-#include <string.h>
-#include <linux/filter.h>
-#include <linux/if_infiniband.h>
-#include <linux/if_packet.h>
-
-#include "dhcp-internal.h"
-#include "fd-util.h"
-#include "socket-util.h"
-#include "unaligned.h"
-
-static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
- uint32_t xid,
- const uint8_t *bcast_addr,
- size_t bcast_addr_len,
- const struct ether_addr *eth_mac,
- uint16_t arp_type, uint8_t dhcp_hlen,
- uint16_t port) {
- 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(DHCPPacket), 1, 0), /* packet >= DHCPPacket ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, ip.protocol)), /* A <- IP protocol */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0), /* IP protocol == UDP ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, ip.frag_off)), /* A <- Flags */
- BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x20), /* A <- A & 0x20 (More Fragments bit) */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, ip.frag_off)), /* A <- Flags + Fragment offset */
- BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x1fff), /* A <- A & 0x1fff (Fragment offset) */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, udp.dest)), /* A <- UDP destination port */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, port, 1, 0), /* UDP destination port == DHCP client port ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.op)), /* A <- DHCP op */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0), /* op == BOOTREPLY ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)), /* A <- DHCP header type */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arp_type, 1, 0), /* header type == arp_type ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)), /* A <- client identifier */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0), /* client identifier == xid ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- MAC address length */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
-
- /* 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, 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_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- 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_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, UINT32_MAX), /* accept */
- };
- struct sock_fprog fprog = {
- .len = ELEMENTSOF(filter),
- .filter = filter
- };
- _cleanup_close_ int s = -1;
- int r;
-
- assert(ifindex > 0);
- assert(link);
-
- s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
- if (s < 0)
- return -errno;
-
- r = setsockopt_int(s, SOL_PACKET, PACKET_AUXDATA, true);
- if (r < 0)
- return r;
-
- r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
- if (r < 0)
- return -errno;
-
- link->ll = (struct sockaddr_ll) {
- .sll_family = AF_PACKET,
- .sll_protocol = htobe16(ETH_P_IP),
- .sll_ifindex = ifindex,
- .sll_hatype = htobe16(arp_type),
- .sll_halen = bcast_addr_len,
- };
- memcpy(link->ll.sll_addr, bcast_addr, bcast_addr_len); /* We may overflow link->ll. link->ll_buffer ensures we have enough space. */
-
- r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll));
- if (r < 0)
- return -errno;
-
- 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) {
-
- static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
- /* Default broadcast address for IPoIB */
- static const uint8_t ib_bcast[] = {
- 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0xff, 0xff, 0xff
- };
- struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } };
- const uint8_t *default_bcast_addr;
- size_t expected_bcast_addr_len;
- uint8_t dhcp_hlen = 0;
-
- if (arp_type == ARPHRD_ETHER) {
- assert_return(mac_addr_len == ETH_ALEN, -EINVAL);
- memcpy(&eth_mac, mac_addr, ETH_ALEN);
- dhcp_hlen = ETH_ALEN;
-
- default_bcast_addr = eth_bcast;
- expected_bcast_addr_len = ETH_ALEN;
- } else if (arp_type == ARPHRD_INFINIBAND) {
- default_bcast_addr = ib_bcast;
- expected_bcast_addr_len = INFINIBAND_ALEN;
- } else
- return -EINVAL;
-
- if (bcast_addr && bcast_addr_len > 0)
- assert_return(bcast_addr_len == expected_bcast_addr_len, -EINVAL);
- else {
- bcast_addr = default_bcast_addr;
- bcast_addr_len = expected_bcast_addr_len;
- }
-
- return _bind_raw_socket(ifindex, link, xid, bcast_addr, bcast_addr_len,
- &eth_mac, arp_type, dhcp_hlen, port);
-}
-
-int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) {
- union sockaddr_union src = {
- .in.sin_family = AF_INET,
- .in.sin_port = htobe16(port),
- .in.sin_addr.s_addr = address,
- };
- _cleanup_close_ int s = -1;
- int r;
-
- s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
- if (s < 0)
- return -errno;
-
- if (ip_service_type >= 0)
- r = setsockopt_int(s, IPPROTO_IP, IP_TOS, ip_service_type);
- else
- r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6);
- if (r < 0)
- return r;
-
- r = setsockopt_int(s, SOL_SOCKET, SO_REUSEADDR, true);
- if (r < 0)
- return r;
-
- if (ifindex > 0) {
- r = socket_bind_to_ifindex(s, ifindex);
- if (r < 0)
- return r;
- }
-
- if (port == DHCP_PORT_SERVER) {
- r = setsockopt_int(s, SOL_SOCKET, SO_BROADCAST, true);
- if (r < 0)
- return r;
- if (address == INADDR_ANY) {
- /* IP_PKTINFO filter should not be applied when packets are
- allowed to enter/leave through the interface other than
- DHCP server sits on(BindToInterface option). */
- r = setsockopt_int(s, IPPROTO_IP, IP_PKTINFO, true);
- if (r < 0)
- return r;
- }
- } else {
- r = setsockopt_int(s, IPPROTO_IP, IP_FREEBIND, true);
- if (r < 0)
- return r;
- }
-
- 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) {
-
- /* 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 > 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) {
-
- union sockaddr_union dest = {
- .in.sin_family = AF_INET,
- .in.sin_port = htobe16(port),
- .in.sin_addr.s_addr = address,
- };
-
- assert(s >= 0);
- assert(packet);
- assert(len > 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-option.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c
deleted file mode 100644
index 712f609784..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c
+++ /dev/null
@@ -1,443 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/***
- Copyright Ā© 2013 Intel Corporation. All rights reserved.
-***/
-
-#include "nm-sd-adapt-core.h"
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include "alloc-util.h"
-#include "dhcp-internal.h"
-#include "dhcp-server-internal.h"
-#include "memory-util.h"
-#include "strv.h"
-#include "utf8.h"
-
-/* Append type-length value structure to the options buffer */
-static int dhcp_option_append_tlv(uint8_t options[], size_t size, size_t *offset, uint8_t code, size_t optlen, const void *optval) {
- assert(options);
- assert(size > 0);
- assert(offset);
- assert(optlen <= UINT8_MAX);
- assert(*offset < size);
-
- if (*offset + 2 + optlen > size)
- return -ENOBUFS;
-
- options[*offset] = code;
- options[*offset + 1] = optlen;
-
- memcpy_safe(&options[*offset + 2], optval, optlen);
- *offset += 2 + optlen;
- return 0;
-}
-
-static int option_append(uint8_t options[], size_t size, size_t *offset,
- uint8_t code, size_t optlen, const void *optval) {
- assert(options);
- assert(size > 0);
- assert(offset);
-
- int r;
-
- if (code != SD_DHCP_OPTION_END)
- /* always make sure there is space for an END option */
- size--;
-
- switch (code) {
-
- case SD_DHCP_OPTION_PAD:
- case SD_DHCP_OPTION_END:
- if (*offset + 1 > size)
- return -ENOBUFS;
-
- options[*offset] = code;
- *offset += 1;
- break;
-
- case SD_DHCP_OPTION_USER_CLASS: {
- size_t total = 0;
-
- if (strv_isempty((char **) optval))
- return -EINVAL;
-
- STRV_FOREACH(s, (char **) optval) {
- size_t len = strlen(*s);
-
- if (len > 255 || len == 0)
- return -EINVAL;
-
- total += 1 + len;
- }
-
- if (*offset + 2 + total > size)
- return -ENOBUFS;
-
- options[*offset] = code;
- options[*offset + 1] = total;
- *offset += 2;
-
- STRV_FOREACH(s, (char **) optval) {
- size_t len = strlen(*s);
-
- options[*offset] = len;
- memcpy(&options[*offset + 1], *s, len);
- *offset += 1 + len;
- }
-
- break;
- }
- case SD_DHCP_OPTION_SIP_SERVER:
- if (*offset + 3 + optlen > size)
- return -ENOBUFS;
-
- options[*offset] = code;
- options[*offset + 1] = optlen + 1;
- options[*offset + 2] = 1;
-
- memcpy_safe(&options[*offset + 3], optval, optlen);
- *offset += 3 + optlen;
-
- break;
- case SD_DHCP_OPTION_VENDOR_SPECIFIC: {
- OrderedSet *s = (OrderedSet *) optval;
- struct sd_dhcp_option *p;
- size_t l = 0;
-
- ORDERED_SET_FOREACH(p, s)
- l += p->length + 2;
-
- if (*offset + l + 2 > size)
- return -ENOBUFS;
-
- options[*offset] = code;
- options[*offset + 1] = l;
- *offset += 2;
-
- ORDERED_SET_FOREACH(p, s) {
- r = dhcp_option_append_tlv(options, size, offset, p->option, p->length, p->data);
- if (r < 0)
- return r;
- }
- break;
- }
- case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION: {
-#if 0 /* NM_IGNORED */
- sd_dhcp_server *server = (sd_dhcp_server *) optval;
- size_t current_offset = *offset + 2;
-
- if (server->agent_circuit_id) {
- r = dhcp_option_append_tlv(options, size, &current_offset, SD_DHCP_RELAY_AGENT_CIRCUIT_ID,
- strlen(server->agent_circuit_id), server->agent_circuit_id);
- if (r < 0)
- return r;
- }
- if (server->agent_remote_id) {
- r = dhcp_option_append_tlv(options, size, &current_offset, SD_DHCP_RELAY_AGENT_REMOTE_ID,
- strlen(server->agent_remote_id), server->agent_remote_id);
- if (r < 0)
- return r;
- }
-
- options[*offset] = code;
- options[*offset + 1] = current_offset - *offset - 2;
- assert(current_offset - *offset - 2 <= UINT8_MAX);
- *offset = current_offset;
- break;
-#endif /* NM_IGNORED */
- g_return_val_if_reached(-EINVAL);
- }
- default:
- return dhcp_option_append_tlv(options, size, offset, code, optlen, optval);
- }
- return 0;
-}
-
-static int option_length(uint8_t *options, size_t length, size_t offset) {
- assert(options);
- assert(offset < length);
-
- if (IN_SET(options[offset], SD_DHCP_OPTION_PAD, SD_DHCP_OPTION_END))
- return 1;
- if (length < offset + 2)
- return -ENOBUFS;
-
- /* validating that buffer is long enough */
- if (length < offset + 2 + options[offset + 1])
- return -ENOBUFS;
-
- return options[offset + 1] + 2;
-}
-
-int dhcp_option_find_option(uint8_t *options, size_t length, uint8_t code, size_t *ret_offset) {
- int r;
-
- assert(options);
- assert(ret_offset);
-
- for (size_t offset = 0; offset < length; offset += r) {
- r = option_length(options, length, offset);
- if (r < 0)
- return r;
-
- if (code == options[offset]) {
- *ret_offset = offset;
- return r;
- }
- }
- return -ENOENT;
-}
-
-int dhcp_option_remove_option(uint8_t *options, size_t length, uint8_t option_code) {
- int r;
- size_t offset;
-
- assert(options);
-
- r = dhcp_option_find_option(options, length, option_code, &offset);
- if (r < 0)
- return r;
-
- memmove(options + offset, options + offset + r, length - offset - r);
- return length - r;
-}
-
-int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
- uint8_t overload,
- uint8_t code, size_t optlen, const void *optval) {
- const bool use_file = overload & DHCP_OVERLOAD_FILE;
- const bool use_sname = overload & DHCP_OVERLOAD_SNAME;
- int r;
-
- assert(message);
- assert(offset);
-
- /* If *offset is in range [0, size), we are writing to ->options,
- * if *offset is in range [size, size + sizeof(message->file)) and use_file, we are writing to ->file,
- * if *offset is in range [size + use_file*sizeof(message->file), size + use_file*sizeof(message->file) + sizeof(message->sname))
- * and use_sname, we are writing to ->sname.
- */
-
- if (*offset < size) {
- /* still space in the options array */
- r = option_append(message->options, size, offset, code, optlen, optval);
- if (r >= 0)
- return 0;
- else if (r == -ENOBUFS && (use_file || use_sname)) {
- /* did not fit, but we have more buffers to try
- close the options array and move the offset to its end */
- r = option_append(message->options, size, offset, SD_DHCP_OPTION_END, 0, NULL);
- if (r < 0)
- return r;
-
- *offset = size;
- } else
- return r;
- }
-
- if (use_file) {
- size_t file_offset = *offset - size;
-
- if (file_offset < sizeof(message->file)) {
- /* still space in the 'file' array */
- r = option_append(message->file, sizeof(message->file), &file_offset, code, optlen, optval);
- if (r >= 0) {
- *offset = size + file_offset;
- return 0;
- } else if (r == -ENOBUFS && use_sname) {
- /* did not fit, but we have more buffers to try
- close the file array and move the offset to its end */
- r = option_append(message->file, sizeof(message->file), &file_offset, SD_DHCP_OPTION_END, 0, NULL);
- if (r < 0)
- return r;
-
- *offset = size + sizeof(message->file);
- } else
- return r;
- }
- }
-
- if (use_sname) {
- size_t sname_offset = *offset - size - use_file*sizeof(message->file);
-
- if (sname_offset < sizeof(message->sname)) {
- /* still space in the 'sname' array */
- r = option_append(message->sname, sizeof(message->sname), &sname_offset, code, optlen, optval);
- if (r >= 0) {
- *offset = size + use_file*sizeof(message->file) + sname_offset;
- return 0;
- } else
- /* no space, or other error, give up */
- return r;
- }
- }
-
- return -ENOBUFS;
-}
-
-static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload,
- uint8_t *message_type, char **error_message, dhcp_option_callback_t cb,
- void *userdata) {
- uint8_t code, len;
- const uint8_t *option;
- size_t offset = 0;
-
- while (offset < buflen) {
- code = options[offset ++];
-
- switch (code) {
- case SD_DHCP_OPTION_PAD:
- continue;
-
- case SD_DHCP_OPTION_END:
- return 0;
- }
-
- if (buflen < offset + 1)
- return -ENOBUFS;
-
- len = options[offset ++];
-
- if (buflen < offset + len)
- return -EINVAL;
-
- option = &options[offset];
-
- switch (code) {
- case SD_DHCP_OPTION_MESSAGE_TYPE:
- if (len != 1)
- return -EINVAL;
-
- if (message_type)
- *message_type = *option;
-
- break;
-
- case SD_DHCP_OPTION_ERROR_MESSAGE:
- if (len == 0)
- return -EINVAL;
-
- if (error_message) {
- _cleanup_free_ char *string = NULL;
-
- /* Accept a trailing NUL byte */
- if (memchr(option, 0, len - 1))
- return -EINVAL;
-
- string = memdup_suffix0((const char *) option, len);
- if (!string)
- return -ENOMEM;
-
- if (!ascii_is_valid(string))
- return -EINVAL;
-
- free_and_replace(*error_message, string);
- }
-
- break;
- case SD_DHCP_OPTION_OVERLOAD:
- if (len != 1)
- return -EINVAL;
-
- if (overload)
- *overload = *option;
-
- break;
-
- default:
- if (cb)
- cb(code, len, option, userdata);
-
- break;
- }
-
- offset += len;
- }
-
- if (offset < buflen)
- return -EINVAL;
-
- return 0;
-}
-
-int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **_error_message) {
- _cleanup_free_ char *error_message = NULL;
- uint8_t overload = 0;
- uint8_t message_type = 0;
- int r;
-
- if (!message)
- return -EINVAL;
-
- if (len < sizeof(DHCPMessage))
- return -EINVAL;
-
- len -= sizeof(DHCPMessage);
-
- r = parse_options(message->options, len, &overload, &message_type, &error_message, cb, userdata);
- if (r < 0)
- return r;
-
- if (overload & DHCP_OVERLOAD_FILE) {
- r = parse_options(message->file, sizeof(message->file), NULL, &message_type, &error_message, cb, userdata);
- if (r < 0)
- return r;
- }
-
- if (overload & DHCP_OVERLOAD_SNAME) {
- r = parse_options(message->sname, sizeof(message->sname), NULL, &message_type, &error_message, cb, userdata);
- if (r < 0)
- return r;
- }
-
- if (message_type == 0)
- return -ENOMSG;
-
- if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE))
- *_error_message = TAKE_PTR(error_message);
-
- return message_type;
-}
-
-static sd_dhcp_option* dhcp_option_free(sd_dhcp_option *i) {
- if (!i)
- return NULL;
-
- free(i->data);
- return mfree(i);
-}
-
-int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret) {
- assert_return(ret, -EINVAL);
- assert_return(length == 0 || data, -EINVAL);
-
- _cleanup_free_ void *q = memdup(data, length);
- if (!q)
- return -ENOMEM;
-
- sd_dhcp_option *p = new(sd_dhcp_option, 1);
- if (!p)
- return -ENOMEM;
-
- *p = (sd_dhcp_option) {
- .n_ref = 1,
- .option = option,
- .length = length,
- .data = TAKE_PTR(q),
- };
-
- *ret = TAKE_PTR(p);
- return 0;
-}
-
-DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_option, sd_dhcp_option, dhcp_option_free);
-DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
- dhcp_option_hash_ops,
- void,
- trivial_hash_func,
- trivial_compare_func,
- sd_dhcp_option,
- sd_dhcp_option_unref);
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c
deleted file mode 100644
index 25a69a616e..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/***
- Copyright Ā© 2013 Intel Corporation. All rights reserved.
-***/
-
-#include "nm-sd-adapt-core.h"
-
-#include <errno.h>
-#include <net/ethernet.h>
-#include <net/if_arp.h>
-#include <string.h>
-
-#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,
- 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(chaddr || hlen == 0);
-
- message->op = op;
- message->htype = arp_type;
-
- /* 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);
-
- r = dhcp_option_append(message, optlen, &offset, 0,
- SD_DHCP_OPTION_MESSAGE_TYPE, 1, &type);
- if (r < 0)
- return r;
-
- *optoffset = offset;
-
- return 0;
-}
-
-uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) {
- uint64_t *buf_64 = (uint64_t*)buf;
- uint64_t *end_64 = buf_64 + (len / sizeof(uint64_t));
- uint64_t sum = 0;
-
- /* See RFC1071 */
-
- while (buf_64 < end_64) {
- sum += *buf_64;
- if (sum < *buf_64)
- /* wrap around in one's complement */
- sum++;
-
- buf_64++;
- }
-
- if (len % sizeof(uint64_t)) {
- /* If the buffer is not aligned to 64-bit, we need
- to zero-pad the last few bytes and add them in */
- uint64_t buf_tail = 0;
-
- memcpy(&buf_tail, buf_64, len % sizeof(uint64_t));
-
- sum += buf_tail;
- if (sum < buf_tail)
- /* wrap around */
- sum++;
- }
-
- while (sum >> 16)
- sum = (sum & 0xffff) + (sum >> 16);
-
- return ~sum;
-}
-
-void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
- uint16_t source_port, be32_t destination_addr,
- uint16_t destination_port, uint16_t len, int ip_service_type) {
- packet->ip.version = IPVERSION;
- packet->ip.ihl = DHCP_IP_SIZE / 4;
- packet->ip.tot_len = htobe16(len);
-
- if (ip_service_type >= 0)
- packet->ip.tos = ip_service_type;
- else
- packet->ip.tos = IPTOS_CLASS_CS6;
-
- packet->ip.protocol = IPPROTO_UDP;
- packet->ip.saddr = source_addr;
- packet->ip.daddr = destination_addr;
-
- packet->udp.source = htobe16(source_port);
- packet->udp.dest = htobe16(destination_port);
-
- packet->udp.len = htobe16(len - DHCP_IP_SIZE);
-
- packet->ip.check = packet->udp.len;
- packet->udp.check = dhcp_packet_checksum((uint8_t*)&packet->ip.ttl, len - 8);
-
- packet->ip.ttl = IPDEFTTL;
- packet->ip.check = 0;
- packet->ip.check = dhcp_packet_checksum((uint8_t*)&packet->ip, DHCP_IP_SIZE);
-}
-
-int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port) {
- size_t hdrlen;
-
- assert(packet);
-
- /* IP */
-
- if (packet->ip.version != IPVERSION)
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
- "ignoring packet: not IPv4");
-
- if (packet->ip.ihl < 5)
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
- "ignoring packet: IPv4 IHL (%u words) invalid",
- packet->ip.ihl);
-
- hdrlen = packet->ip.ihl * 4;
- if (hdrlen < 20)
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
- "ignoring packet: IPv4 IHL (%zu bytes) "
- "smaller than minimum (20 bytes)",
- hdrlen);
-
- if (len < hdrlen)
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
- "ignoring packet: packet (%zu bytes) "
- "smaller than expected (%zu) by IP header",
- len, hdrlen);
-
- /* UDP */
-
- if (packet->ip.protocol != IPPROTO_UDP)
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
- "ignoring packet: not UDP");
-
- if (len < hdrlen + be16toh(packet->udp.len))
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
- "ignoring packet: packet (%zu bytes) "
- "smaller than expected (%zu) by UDP header",
- len, hdrlen + be16toh(packet->udp.len));
-
- if (be16toh(packet->udp.dest) != port)
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
- "ignoring packet: to port %u, which "
- "is not the DHCP client port (%u)",
- be16toh(packet->udp.dest), port);
-
- /* checksums - computing these is relatively expensive, so only do it
- if all the other checks have passed
- */
-
- if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen))
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
- "ignoring packet: invalid IP checksum");
-
- if (checksum && packet->udp.check) {
- packet->ip.check = packet->udp.len;
- packet->ip.ttl = 0;
-
- if (dhcp_packet_checksum((uint8_t*)&packet->ip.ttl,
- be16toh(packet->udp.len) + 12))
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
- "ignoring packet: invalid UDP checksum");
- }
-
- return 0;
-}
diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-protocol.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp-protocol.h
deleted file mode 100644
index dd54bcf6ee..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-protocol.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-/***
- Copyright Ā© 2013 Intel Corporation. All rights reserved.
-***/
-
-#include <netinet/ip.h>
-#include <netinet/udp.h>
-#include <stdint.h>
-
-#include "macro.h"
-#include "sparse-endian.h"
-
-struct DHCPMessage {
- uint8_t op;
- uint8_t htype;
- uint8_t hlen;
- uint8_t hops;
- be32_t xid;
- be16_t secs;
- be16_t flags;
- be32_t ciaddr;
- be32_t yiaddr;
- be32_t siaddr;
- be32_t giaddr;
- uint8_t chaddr[16];
- uint8_t sname[64];
- uint8_t file[128];
- be32_t magic;
- uint8_t options[0];
-} _packed_;
-
-typedef struct DHCPMessage DHCPMessage;
-
-struct DHCPPacket {
- struct iphdr ip;
- struct udphdr udp;
- DHCPMessage dhcp;
-} _packed_;
-
-typedef struct DHCPPacket DHCPPacket;
-
-#define DHCP_IP_SIZE (int32_t)(sizeof(struct iphdr))
-#define DHCP_IP_UDP_SIZE (int32_t)(sizeof(struct udphdr) + DHCP_IP_SIZE)
-#define DHCP_MESSAGE_SIZE (int32_t)(sizeof(DHCPMessage))
-#define DHCP_DEFAULT_MIN_SIZE 576 /* the minimum internet hosts must be able to receive */
-#define DHCP_MIN_OPTIONS_SIZE (DHCP_DEFAULT_MIN_SIZE - DHCP_IP_UDP_SIZE - DHCP_MESSAGE_SIZE)
-#define DHCP_MAGIC_COOKIE (uint32_t)(0x63825363)
-
-enum {
- DHCP_PORT_SERVER = 67,
- DHCP_PORT_CLIENT = 68,
-};
-
-enum DHCPState {
- DHCP_STATE_INIT = 0,
- DHCP_STATE_SELECTING = 1,
- DHCP_STATE_INIT_REBOOT = 2,
- DHCP_STATE_REBOOTING = 3,
- DHCP_STATE_REQUESTING = 4,
- DHCP_STATE_BOUND = 5,
- DHCP_STATE_RENEWING = 6,
- DHCP_STATE_REBINDING = 7,
- DHCP_STATE_STOPPED = 8,
-};
-
-typedef enum DHCPState DHCPState;
-
-enum {
- BOOTREQUEST = 1,
- BOOTREPLY = 2,
-};
-
-enum {
- DHCP_DISCOVER = 1, /* [RFC2132] */
- DHCP_OFFER = 2, /* [RFC2132] */
- DHCP_REQUEST = 3, /* [RFC2132] */
- DHCP_DECLINE = 4, /* [RFC2132] */
- DHCP_ACK = 5, /* [RFC2132] */
- DHCP_NAK = 6, /* [RFC2132] */
- DHCP_RELEASE = 7, /* [RFC2132] */
- DHCP_INFORM = 8, /* [RFC2132] */
- DHCP_FORCERENEW = 9, /* [RFC3203] */
- DHCPLEASEQUERY = 10, /* [RFC4388] */
- DHCPLEASEUNASSIGNED = 11, /* [RFC4388] */
- DHCPLEASEUNKNOWN = 12, /* [RFC4388] */
- DHCPLEASEACTIVE = 13, /* [RFC4388] */
- DHCPBULKLEASEQUERY = 14, /* [RFC6926] */
- DHCPLEASEQUERYDONE = 15, /* [RFC6926] */
- DHCPACTIVELEASEQUERY = 16, /* [RFC7724] */
- DHCPLEASEQUERYSTATUS = 17, /* [RFC7724] */
- DHCPTLS = 18, /* [RFC7724] */
-};
-
-enum {
- DHCP_OVERLOAD_FILE = 1,
- DHCP_OVERLOAD_SNAME = 2,
-};
-
-#define DHCP_MAX_FQDN_LENGTH 255
-
-enum {
- DHCP_FQDN_FLAG_S = (1 << 0),
- DHCP_FQDN_FLAG_O = (1 << 1),
- DHCP_FQDN_FLAG_E = (1 << 2),
- DHCP_FQDN_FLAG_N = (1 << 3),
-};
diff --git a/src/libnm-systemd-core/src/libsystemd-network/network-internal.c b/src/libnm-systemd-core/src/libsystemd-network/network-internal.c
deleted file mode 100644
index 60ce47eab1..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/network-internal.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nm-sd-adapt-core.h"
-
-#include <arpa/inet.h>
-#include <linux/if.h>
-#include <netinet/ether.h>
-
-#include "sd-ndisc.h"
-
-#include "alloc-util.h"
-#include "dhcp-lease-internal.h"
-#include "extract-word.h"
-#include "hexdecoct.h"
-#include "log.h"
-#include "network-internal.h"
-#include "parse-util.h"
-
-size_t serialize_in_addrs(FILE *f,
- const struct in_addr *addresses,
- size_t size,
- bool *with_leading_space,
- bool (*predicate)(const struct in_addr *addr)) {
- assert(f);
- assert(addresses);
-
- size_t count = 0;
- bool _space = false;
- if (!with_leading_space)
- with_leading_space = &_space;
-
- for (size_t i = 0; i < size; i++) {
- char sbuf[INET_ADDRSTRLEN];
-
- if (predicate && !predicate(&addresses[i]))
- continue;
-
- if (*with_leading_space)
- fputc(' ', f);
- fputs(inet_ntop(AF_INET, &addresses[i], sbuf, sizeof(sbuf)), f);
- count++;
- *with_leading_space = true;
- }
-
- return count;
-}
-
-int deserialize_in_addrs(struct in_addr **ret, const char *string) {
- _cleanup_free_ struct in_addr *addresses = NULL;
- int size = 0;
-
- assert(ret);
- assert(string);
-
- for (;;) {
- _cleanup_free_ char *word = NULL;
- struct in_addr *new_addresses;
- int r;
-
- r = extract_first_word(&string, &word, NULL, 0);
- if (r < 0)
- return r;
- if (r == 0)
- break;
-
- new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr));
- if (!new_addresses)
- return -ENOMEM;
- else
- addresses = new_addresses;
-
- r = inet_pton(AF_INET, word, &(addresses[size]));
- if (r <= 0)
- continue;
-
- size++;
- }
-
- *ret = size > 0 ? TAKE_PTR(addresses) : NULL;
-
- return size;
-}
-
-void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size, bool *with_leading_space) {
- assert(f);
- assert(addresses);
- assert(size);
-
- bool _space = false;
- if (!with_leading_space)
- with_leading_space = &_space;
-
- for (size_t i = 0; i < size; i++) {
- char buffer[INET6_ADDRSTRLEN];
-
- if (*with_leading_space)
- fputc(' ', f);
- fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f);
- *with_leading_space = true;
- }
-}
-
-int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
- _cleanup_free_ struct in6_addr *addresses = NULL;
- int size = 0;
-
- assert(ret);
- assert(string);
-
- for (;;) {
- _cleanup_free_ char *word = NULL;
- struct in6_addr *new_addresses;
- int r;
-
- r = extract_first_word(&string, &word, NULL, 0);
- if (r < 0)
- return r;
- if (r == 0)
- break;
-
- new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr));
- if (!new_addresses)
- return -ENOMEM;
- else
- addresses = new_addresses;
-
- r = inet_pton(AF_INET6, word, &(addresses[size]));
- if (r <= 0)
- continue;
-
- size++;
- }
-
- *ret = TAKE_PTR(addresses);
-
- return size;
-}
-
-void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) {
- assert(f);
- assert(key);
- assert(routes);
- assert(size);
-
- fprintf(f, "%s=", key);
-
- for (size_t i = 0; i < size; i++) {
- char sbuf[INET_ADDRSTRLEN];
- struct in_addr dest, gw;
- uint8_t length;
-
- assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0);
- assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0);
- assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0);
-
- fprintf(f, "%s/%" PRIu8, inet_ntop(AF_INET, &dest, sbuf, sizeof sbuf), length);
- fprintf(f, ",%s%s", inet_ntop(AF_INET, &gw, sbuf, sizeof sbuf), i < size - 1 ? " ": "");
- }
-
- fputs("\n", f);
-}
-
-int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, const char *string) {
- _cleanup_free_ struct sd_dhcp_route *routes = NULL;
- size_t size = 0;
-
- assert(ret);
- assert(ret_size);
- assert(string);
-
- /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
- for (;;) {
- _cleanup_free_ char *word = NULL;
- char *tok, *tok_end;
- unsigned n;
- int r;
-
- r = extract_first_word(&string, &word, NULL, 0);
- if (r < 0)
- return r;
- if (r == 0)
- break;
-
- if (!GREEDY_REALLOC(routes, size + 1))
- return -ENOMEM;
-
- tok = word;
-
- /* get the subnet */
- tok_end = strchr(tok, '/');
- if (!tok_end)
- continue;
- *tok_end = '\0';
-
- r = inet_aton(tok, &routes[size].dst_addr);
- if (r == 0)
- continue;
-
- tok = tok_end + 1;
-
- /* get the prefixlen */
- tok_end = strchr(tok, ',');
- if (!tok_end)
- continue;
-
- *tok_end = '\0';
-
- r = safe_atou(tok, &n);
- if (r < 0 || n > 32)
- continue;
-
- routes[size].dst_prefixlen = (uint8_t) n;
- tok = tok_end + 1;
-
- /* get the gateway */
- r = inet_aton(tok, &routes[size].gw_addr);
- if (r == 0)
- continue;
-
- size++;
- }
-
- *ret_size = size;
- *ret = TAKE_PTR(routes);
-
- return 0;
-}
-
-int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) {
- _cleanup_free_ char *hex_buf = NULL;
-
- assert(f);
- assert(key);
- assert(data);
-
- hex_buf = hexmem(data, size);
- if (!hex_buf)
- return -ENOMEM;
-
- fprintf(f, "%s=%s\n", key, hex_buf);
-
- return 0;
-}
diff --git a/src/libnm-systemd-core/src/libsystemd-network/network-internal.h b/src/libnm-systemd-core/src/libsystemd-network/network-internal.h
deleted file mode 100644
index 5aa225e977..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/network-internal.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-#include <stdbool.h>
-#include <stdio.h>
-
-#include "sd-dhcp-lease.h"
-
-size_t serialize_in_addrs(FILE *f,
- const struct in_addr *addresses,
- size_t size,
- bool *with_leading_space,
- bool (*predicate)(const struct in_addr *addr));
-int deserialize_in_addrs(struct in_addr **addresses, const char *string);
-void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
- size_t size,
- bool *with_leading_space);
-int deserialize_in6_addrs(struct in6_addr **addresses, const char *string);
-
-/* don't include "dhcp-lease-internal.h" as it causes conflicts between netinet/ip.h and linux/ip.h */
-struct sd_dhcp_route;
-struct sd_dhcp_lease;
-
-void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route **routes, size_t size);
-int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, const char *string);
-
-/* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */
-int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size);
-
-int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
-int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file);
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
deleted file mode 100644
index d56978adcd..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c
+++ /dev/null
@@ -1,2285 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/***
- Copyright Ā© 2013 Intel Corporation. All rights reserved.
-***/
-
-#include "nm-sd-adapt-core.h"
-
-#include <errno.h>
-#include <net/ethernet.h>
-#include <net/if_arp.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <linux/if_infiniband.h>
-
-#include "sd-dhcp-client.h"
-
-#include "alloc-util.h"
-#include "dhcp-identifier.h"
-#include "dhcp-internal.h"
-#include "dhcp-lease-internal.h"
-#include "dhcp-protocol.h"
-#include "dns-domain.h"
-#include "event-util.h"
-#include "fd-util.h"
-#include "hostname-util.h"
-#include "io-util.h"
-#include "memory-util.h"
-#include "network-common.h"
-#include "random-util.h"
-#include "set.h"
-#include "sort-util.h"
-#include "string-util.h"
-#include "strv.h"
-#include "time-util.h"
-#include "utf8.h"
-#include "web-util.h"
-
-#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
-#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
-
-#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC)
-#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE)
-
-#define TRANSIENT_FAILURE_ATTEMPTS 3 /* Arbitrary limit: how many attempts are considered enough to report
- * transient failure. */
-
-typedef struct sd_dhcp_client_id {
- uint8_t type;
- union {
- struct {
- /* 0: Generic (non-LL) (RFC 2132) */
- uint8_t data[MAX_CLIENT_ID_LEN];
- } _packed_ gen;
- struct {
- /* 1: Ethernet Link-Layer (RFC 2132) */
- uint8_t haddr[ETH_ALEN];
- } _packed_ eth;
- struct {
- /* 2 - 254: ARP/Link-Layer (RFC 2132) */
- uint8_t haddr[0];
- } _packed_ ll;
- struct {
- /* 255: Node-specific (RFC 4361) */
- be32_t iaid;
- struct duid duid;
- } _packed_ ns;
- struct {
- uint8_t data[MAX_CLIENT_ID_LEN];
- } _packed_ raw;
- };
-} _packed_ sd_dhcp_client_id;
-
-struct sd_dhcp_client {
- unsigned n_ref;
-
- DHCPState state;
- sd_event *event;
- int event_priority;
- sd_event_source *timeout_resend;
- int ifindex;
- char *ifname;
- int fd;
- uint16_t port;
- union sockaddr_union link;
- sd_event_source *receive_message;
- bool request_broadcast;
- Set *req_opts;
- bool anonymize;
- be32_t last_addr;
- uint8_t mac_addr[MAX_MAC_ADDR_LEN];
- size_t mac_addr_len;
- uint8_t bcast_addr[MAX_MAC_ADDR_LEN];
- size_t bcast_addr_len;
- uint16_t arp_type;
- sd_dhcp_client_id client_id;
- size_t client_id_len;
- char *hostname;
- char *vendor_class_identifier;
- char *mudurl;
- char **user_class;
- uint32_t mtu;
- uint32_t fallback_lease_lifetime;
- uint32_t xid;
- usec_t start_time;
- usec_t t1_time;
- usec_t t2_time;
- usec_t expire_time;
- uint64_t attempt;
- uint64_t max_attempts;
- OrderedHashmap *extra_options;
- OrderedHashmap *vendor_options;
- usec_t request_sent;
- sd_event_source *timeout_t1;
- sd_event_source *timeout_t2;
- sd_event_source *timeout_expire;
- sd_dhcp_client_callback_t callback;
- void *userdata;
- sd_dhcp_lease *lease;
- usec_t start_delay;
- int ip_service_type;
-
- /* Ignore ifindex when generating iaid. See dhcp_identifier_set_iaid(). */
- bool test_mode;
-};
-
-static const uint8_t default_req_opts[] = {
- SD_DHCP_OPTION_SUBNET_MASK,
- SD_DHCP_OPTION_ROUTER,
- SD_DHCP_OPTION_HOST_NAME,
- SD_DHCP_OPTION_DOMAIN_NAME,
- SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
-};
-
-/* RFC7844 section 3:
- MAY contain the Parameter Request List option.
- RFC7844 section 3.6:
- The client intending to protect its privacy SHOULD only request a
- minimal number of options in the PRL and SHOULD also randomly shuffle
- the ordering of option codes in the PRL. If this random ordering
- cannot be implemented, the client MAY order the option codes in the
- PRL by option code number (lowest to highest).
-*/
-/* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */
-static const uint8_t default_req_opts_anonymize[] = {
- SD_DHCP_OPTION_SUBNET_MASK, /* 1 */
- SD_DHCP_OPTION_ROUTER, /* 3 */
- SD_DHCP_OPTION_DOMAIN_NAME_SERVER, /* 6 */
- SD_DHCP_OPTION_DOMAIN_NAME, /* 15 */
- SD_DHCP_OPTION_ROUTER_DISCOVERY, /* 31 */
- SD_DHCP_OPTION_STATIC_ROUTE, /* 33 */
- SD_DHCP_OPTION_VENDOR_SPECIFIC, /* 43 */
- SD_DHCP_OPTION_NETBIOS_NAME_SERVER, /* 44 */
- SD_DHCP_OPTION_NETBIOS_NODE_TYPE, /* 46 */
- SD_DHCP_OPTION_NETBIOS_SCOPE, /* 47 */
- SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, /* 121 */
- SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE, /* 249 */
- SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, /* 252 */
-};
-
-static int client_receive_message_raw(
- sd_event_source *s,
- int fd,
- uint32_t revents,
- void *userdata);
-static int client_receive_message_udp(
- sd_event_source *s,
- int fd,
- uint32_t revents,
- void *userdata);
-static void client_stop(sd_dhcp_client *client, int error);
-
-int sd_dhcp_client_id_to_string(const void *data, size_t len, char **ret) {
- const sd_dhcp_client_id *client_id = data;
- _cleanup_free_ char *t = NULL;
- int r = 0;
-
- assert_return(data, -EINVAL);
- assert_return(len >= 1, -EINVAL);
- assert_return(ret, -EINVAL);
-
- len -= 1;
- if (len > MAX_CLIENT_ID_LEN)
- return -EINVAL;
-
- switch (client_id->type) {
- case 0:
- if (utf8_is_printable((char *) client_id->gen.data, len))
- r = asprintf(&t, "%.*s", (int) len, client_id->gen.data);
- else
- r = asprintf(&t, "DATA");
- break;
- case 1:
- if (len != sizeof_field(sd_dhcp_client_id, eth))
- return -EINVAL;
-
- r = asprintf(&t, "%02x:%02x:%02x:%02x:%02x:%02x",
- client_id->eth.haddr[0],
- client_id->eth.haddr[1],
- client_id->eth.haddr[2],
- client_id->eth.haddr[3],
- client_id->eth.haddr[4],
- client_id->eth.haddr[5]);
- break;
- case 2 ... 254:
- r = asprintf(&t, "ARP/LL");
- break;
- case 255:
- if (len < 6)
- return -EINVAL;
-
- uint32_t iaid = be32toh(client_id->ns.iaid);
- uint16_t duid_type = be16toh(client_id->ns.duid.type);
- if (dhcp_validate_duid_len(duid_type, len - 6, true) < 0)
- return -EINVAL;
-
- r = asprintf(&t, "IAID:0x%x/DUID", iaid);
- break;
- }
-
- if (r < 0)
- return -ENOMEM;
- *ret = TAKE_PTR(t);
- return 0;
-}
-
-int sd_dhcp_client_set_callback(
- sd_dhcp_client *client,
- sd_dhcp_client_callback_t cb,
- void *userdata) {
-
- assert_return(client, -EINVAL);
-
- client->callback = cb;
- client->userdata = userdata;
-
- return 0;
-}
-
-int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) {
- assert_return(client, -EINVAL);
-
- client->request_broadcast = broadcast;
-
- return 0;
-}
-
-int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
- assert_return(client, -EINVAL);
- assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
-
- switch (option) {
-
- case SD_DHCP_OPTION_PAD:
- case SD_DHCP_OPTION_OVERLOAD:
- case SD_DHCP_OPTION_MESSAGE_TYPE:
- case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST:
- case SD_DHCP_OPTION_END:
- return -EINVAL;
-
- default:
- break;
- }
-
- return set_ensure_put(&client->req_opts, NULL, UINT8_TO_PTR(option));
-}
-
-int sd_dhcp_client_set_request_address(
- sd_dhcp_client *client,
- const struct in_addr *last_addr) {
-
- assert_return(client, -EINVAL);
- assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
-
- if (last_addr)
- client->last_addr = last_addr->s_addr;
- else
- client->last_addr = INADDR_ANY;
-
- return 0;
-}
-
-int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) {
- assert_return(client, -EINVAL);
- assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY);
- assert_return(ifindex > 0, -EINVAL);
-
- client->ifindex = ifindex;
- return 0;
-}
-
-int sd_dhcp_client_set_ifname(sd_dhcp_client *client, const char *ifname) {
- assert_return(client, -EINVAL);
- assert_return(ifname, -EINVAL);
-
- if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
- return -EINVAL;
-
- return free_and_strdup(&client->ifname, ifname);
-}
-
-int sd_dhcp_client_get_ifname(sd_dhcp_client *client, const char **ret) {
- int r;
-
- assert_return(client, -EINVAL);
-
- r = get_ifname(client->ifindex, &client->ifname);
- if (r < 0)
- return r;
-
- if (ret)
- *ret = client->ifname;
-
- return 0;
-}
-
-int sd_dhcp_client_set_mac(
- sd_dhcp_client *client,
- const uint8_t *addr,
- const uint8_t *bcast_addr,
- size_t addr_len,
- uint16_t arp_type) {
-
- DHCP_CLIENT_DONT_DESTROY(client);
- bool need_restart = false;
- int r;
-
- assert_return(client, -EINVAL);
- assert_return(addr, -EINVAL);
- assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
- assert_return(arp_type > 0, -EINVAL);
-
- if (arp_type == ARPHRD_ETHER)
- assert_return(addr_len == ETH_ALEN, -EINVAL);
- else if (arp_type == ARPHRD_INFINIBAND)
- assert_return(addr_len == INFINIBAND_ALEN, -EINVAL);
- else
- return -EINVAL;
-
- if (client->mac_addr_len == addr_len &&
- memcmp(&client->mac_addr, addr, addr_len) == 0 &&
- (client->bcast_addr_len > 0) == !!bcast_addr &&
- (!bcast_addr || memcmp(&client->bcast_addr, bcast_addr, addr_len) == 0))
- return 0;
-
- if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
- log_dhcp_client(client, "Changing MAC address on running DHCP client, restarting");
- need_restart = true;
- client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
- }
-
- memcpy(&client->mac_addr, addr, addr_len);
- client->mac_addr_len = addr_len;
- client->arp_type = arp_type;
- client->bcast_addr_len = 0;
-
- if (bcast_addr) {
- memcpy(&client->bcast_addr, bcast_addr, addr_len);
- client->bcast_addr_len = addr_len;
- }
-
- if (need_restart && client->state != DHCP_STATE_STOPPED) {
- r = sd_dhcp_client_start(client);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m");
- }
-
- return 0;
-}
-
-int sd_dhcp_client_get_client_id(
- sd_dhcp_client *client,
- uint8_t *type,
- const uint8_t **data,
- size_t *data_len) {
-
- assert_return(client, -EINVAL);
- assert_return(type, -EINVAL);
- assert_return(data, -EINVAL);
- assert_return(data_len, -EINVAL);
-
- if (client->client_id_len) {
- *type = client->client_id.type;
- *data = client->client_id.raw.data;
- *data_len = client->client_id_len - sizeof(client->client_id.type);
- } else {
- *type = 0;
- *data = NULL;
- *data_len = 0;
- }
-
- return 0;
-}
-
-int sd_dhcp_client_set_client_id(
- sd_dhcp_client *client,
- uint8_t type,
- const uint8_t *data,
- size_t data_len) {
-
- DHCP_CLIENT_DONT_DESTROY(client);
- bool need_restart = false;
- int r;
-
- assert_return(client, -EINVAL);
- assert_return(data, -EINVAL);
- assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
- G_STATIC_ASSERT_EXPR (_NM_MAX_CLIENT_ID_LEN == MAX_CLIENT_ID_LEN);
-
- if (client->client_id_len == data_len + sizeof(client->client_id.type) &&
- client->client_id.type == type &&
- memcmp(&client->client_id.raw.data, data, data_len) == 0)
- return 0;
-
- /* For hardware types, log debug message about unexpected data length.
- *
- * Note that infiniband's INFINIBAND_ALEN is 20 bytes long, but only
- * the last 8 bytes of the address are stable and suitable to put into
- * the client-id. The caller is advised to account for that. */
- if ((type == ARPHRD_ETHER && data_len != ETH_ALEN) ||
- (type == ARPHRD_INFINIBAND && data_len != 8))
- log_dhcp_client(client, "Changing client ID to hardware type %u with "
- "unexpected address length %zu",
- type, data_len);
-
- if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
- log_dhcp_client(client, "Changing client ID on running DHCP "
- "client, restarting");
- need_restart = true;
- client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
- }
-
- client->client_id.type = type;
- memcpy(&client->client_id.raw.data, data, data_len);
- client->client_id_len = data_len + sizeof (client->client_id.type);
-
- if (need_restart && client->state != DHCP_STATE_STOPPED) {
- r = sd_dhcp_client_start(client);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m");
- }
-
- return 0;
-}
-
-#if 0 /* NM_IGNORED */
-/**
- * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid
- * without further modification. Otherwise, if duid_type is supported, DUID
- * is set based on that type. Otherwise, an error is returned.
- */
-static int dhcp_client_set_iaid_duid_internal(
- sd_dhcp_client *client,
- bool iaid_append,
- bool iaid_set,
- uint32_t iaid,
- DUIDType duid_type,
- const void *duid,
- size_t duid_len,
- usec_t llt_time) {
-
- DHCP_CLIENT_DONT_DESTROY(client);
- int r;
- size_t len;
-
- assert_return(client, -EINVAL);
- assert_return(duid_len == 0 || duid, -EINVAL);
-
- if (duid) {
- r = dhcp_validate_duid_len(duid_type, duid_len, true);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to validate length of DUID: %m");
- }
-
- zero(client->client_id);
- client->client_id.type = 255;
-
- if (iaid_append) {
- if (iaid_set)
- client->client_id.ns.iaid = htobe32(iaid);
- else {
- r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
- client->mac_addr_len,
- /* legacy_unstable_byteorder = */ true,
- /* use_mac = */ client->test_mode,
- &client->client_id.ns.iaid);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to set IAID: %m");
- }
- }
-
- if (duid) {
- client->client_id.ns.duid.type = htobe16(duid_type);
- memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len);
- len = sizeof(client->client_id.ns.duid.type) + duid_len;
-
- } else {
- r = dhcp_identifier_set_duid(duid_type, client->mac_addr, client->mac_addr_len,
- client->arp_type, llt_time, client->test_mode,
- &client->client_id.ns.duid, &len);
- if (r == -EOPNOTSUPP)
- return log_dhcp_client_errno(client, r,
- "Failed to set %s. MAC address is not set or "
- "interface type is not supported.",
- duid_type_to_string(duid_type));
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to set %s: %m",
- duid_type_to_string(duid_type));
- }
-
- client->client_id_len = sizeof(client->client_id.type) + len +
- (iaid_append ? sizeof(client->client_id.ns.iaid) : 0);
-
- if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
- log_dhcp_client(client, "Configured %sDUID, restarting.", iaid_append ? "IAID+" : "");
- client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
- r = sd_dhcp_client_start(client);
- if (r < 0)
- return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m");
- }
-
- return 0;
-}
-
-int sd_dhcp_client_set_iaid_duid(
- sd_dhcp_client *client,
- bool iaid_set,
- uint32_t iaid,
- uint16_t duid_type,
- const void *duid,
- size_t duid_len) {
- return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, duid_type, duid, duid_len, 0);
-}
-
-int sd_dhcp_client_set_iaid_duid_llt(
- sd_dhcp_client *client,
- bool iaid_set,
- uint32_t iaid,
- usec_t llt_time) {
- return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, DUID_TYPE_LLT, NULL, 0, llt_time);
-}
-
-int sd_dhcp_client_set_duid(
- sd_dhcp_client *client,
- uint16_t duid_type,
- const void *duid,
- size_t duid_len) {
- return dhcp_client_set_iaid_duid_internal(client, false, false, 0, duid_type, duid, duid_len, 0);
-}
-
-int sd_dhcp_client_set_duid_llt(
- sd_dhcp_client *client,
- usec_t llt_time) {
- return dhcp_client_set_iaid_duid_internal(client, false, false, 0, DUID_TYPE_LLT, NULL, 0, llt_time);
-}
-#endif /* NM_IGNORED */
-
-void dhcp_client_set_test_mode(sd_dhcp_client *client, bool test_mode) {
- assert(client);
-
- client->test_mode = test_mode;
-}
-
-int sd_dhcp_client_set_hostname(
- sd_dhcp_client *client,
- const char *hostname) {
-
- assert_return(client, -EINVAL);
-
- /* Make sure hostnames qualify as DNS and as Linux hostnames */
- if (hostname &&
- !(hostname_is_valid(hostname, 0) && dns_name_is_valid(hostname) > 0))
- return -EINVAL;
-
- return free_and_strdup(&client->hostname, hostname);
-}
-
-int sd_dhcp_client_set_vendor_class_identifier(
- sd_dhcp_client *client,
- const char *vci) {
-
- assert_return(client, -EINVAL);
-
- return free_and_strdup(&client->vendor_class_identifier, vci);
-}
-
-int sd_dhcp_client_set_mud_url(
- sd_dhcp_client *client,
- const char *mudurl) {
-
- assert_return(client, -EINVAL);
- assert_return(mudurl, -EINVAL);
- assert_return(strlen(mudurl) <= 255, -EINVAL);
- assert_return(http_url_is_valid(mudurl), -EINVAL);
-
- return free_and_strdup(&client->mudurl, mudurl);
-}
-
-int sd_dhcp_client_set_user_class(
- sd_dhcp_client *client,
- char * const *user_class) {
-
- char **s = NULL;
-
- assert_return(client, -EINVAL);
- assert_return(!strv_isempty(user_class), -EINVAL);
-
- STRV_FOREACH(p, user_class) {
- size_t n = strlen(*p);
-
- if (n > 255 || n == 0)
- return -EINVAL;
- }
-
- s = strv_copy(user_class);
- if (!s)
- return -ENOMEM;
-
- return strv_free_and_replace(client->user_class, s);
-}
-
-int sd_dhcp_client_set_client_port(
- sd_dhcp_client *client,
- uint16_t port) {
-
- assert_return(client, -EINVAL);
-
- client->port = port;
-
- return 0;
-}
-
-int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) {
- assert_return(client, -EINVAL);
- assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE);
-
- client->mtu = mtu;
-
- return 0;
-}
-
-int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempts) {
- assert_return(client, -EINVAL);
-
- client->max_attempts = max_attempts;
-
- return 0;
-}
-
-int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v) {
- int r;
-
- assert_return(client, -EINVAL);
- assert_return(v, -EINVAL);
-
- r = ordered_hashmap_ensure_put(&client->extra_options, &dhcp_option_hash_ops, UINT_TO_PTR(v->option), v);
- if (r < 0)
- return r;
-
- sd_dhcp_option_ref(v);
- return 0;
-}
-
-int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v) {
- int r;
-
- assert_return(client, -EINVAL);
- assert_return(v, -EINVAL);
-
- r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp_option_hash_ops);
- if (r < 0)
- return -ENOMEM;
-
- r = ordered_hashmap_put(client->vendor_options, v, v);
- if (r < 0)
- return r;
-
- sd_dhcp_option_ref(v);
-
- return 1;
-}
-
-int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) {
- assert_return(client, -EINVAL);
-
- if (!IN_SET(client->state, DHCP_STATE_SELECTING, DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING))
- return -EADDRNOTAVAIL;
-
- if (ret)
- *ret = client->lease;
-
- return 0;
-}
-
-int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) {
- assert_return(client, -EINVAL);
-
- client->ip_service_type = type;
-
- return 0;
-}
-
-int sd_dhcp_client_set_fallback_lease_lifetime(sd_dhcp_client *client, uint32_t fallback_lease_lifetime) {
- assert_return(client, -EINVAL);
- assert_return(fallback_lease_lifetime > 0, -EINVAL);
-
- client->fallback_lease_lifetime = fallback_lease_lifetime;
-
- return 0;
-}
-
-static int client_notify(sd_dhcp_client *client, int event) {
- assert(client);
-
- if (client->callback)
- return client->callback(client, event, client->userdata);
-
- return 0;
-}
-
-static int client_initialize(sd_dhcp_client *client) {
- assert_return(client, -EINVAL);
-
- client->receive_message = sd_event_source_disable_unref(client->receive_message);
-
- client->fd = safe_close(client->fd);
-
- (void) event_source_disable(client->timeout_resend);
- (void) event_source_disable(client->timeout_t1);
- (void) event_source_disable(client->timeout_t2);
- (void) event_source_disable(client->timeout_expire);
-
- client->attempt = 0;
-
- client->state = DHCP_STATE_INIT;
- client->xid = 0;
-
- client->lease = sd_dhcp_lease_unref(client->lease);
-
- return 0;
-}
-
-static void client_stop(sd_dhcp_client *client, int error) {
- assert(client);
-
- if (error < 0)
- log_dhcp_client_errno(client, error, "STOPPED: %m");
- else if (error == SD_DHCP_CLIENT_EVENT_STOP)
- log_dhcp_client(client, "STOPPED");
- else
- log_dhcp_client(client, "STOPPED: Unknown event");
-
- client_notify(client, error);
-
- client_initialize(client);
-}
-
-/* RFC2131 section 4.1:
- * retransmission delays should include -1 to +1 sec of random 'fuzz'. */
-#define RFC2131_RANDOM_FUZZ \
- ((int64_t)(random_u64() % (2 * USEC_PER_SEC)) - (int64_t)USEC_PER_SEC)
-
-/* RFC2131 section 4.1:
- * for retransmission delays, timeout should start at 4s then double
- * each attempt with max of 64s, with -1 to +1 sec of random 'fuzz' added.
- * This assumes the first call will be using attempt 1. */
-static usec_t client_compute_request_timeout(usec_t now, uint64_t attempt) {
- usec_t timeout = (UINT64_C(1) << MIN(attempt + 1, UINT64_C(6))) * USEC_PER_SEC;
-
- return usec_sub_signed(usec_add(now, timeout), RFC2131_RANDOM_FUZZ);
-}
-
-/* RFC2131 section 4.4.5:
- * T1 defaults to (0.5 * duration_of_lease).
- * T2 defaults to (0.875 * duration_of_lease). */
-#define T1_DEFAULT(lifetime) ((lifetime) / 2)
-#define T2_DEFAULT(lifetime) (((lifetime) * 7) / 8)
-
-/* RFC2131 section 4.4.5:
- * the client SHOULD wait one-half of the remaining time until T2 (in RENEWING state)
- * and one-half of the remaining lease time (in REBINDING state), down to a minimum
- * of 60 seconds.
- * Note that while the default T1/T2 initial times do have random 'fuzz' applied,
- * the RFC sec 4.4.5 does not mention adding any fuzz to retries. */
-static usec_t client_compute_reacquisition_timeout(usec_t now, usec_t expire) {
- return now + MAX(usec_sub_unsigned(expire, now) / 2, 60 * USEC_PER_SEC);
-}
-
-static int cmp_uint8(const uint8_t *a, const uint8_t *b) {
- return CMP(*a, *b);
-}
-
-static int client_message_init(
- sd_dhcp_client *client,
- DHCPPacket **ret,
- uint8_t type,
- size_t *_optlen,
- size_t *_optoffset) {
-
- _cleanup_free_ DHCPPacket *packet = NULL;
- size_t optlen, optoffset, size;
- be16_t max_size;
- usec_t time_now;
- uint16_t secs;
- int r;
-
- assert(client);
- assert(client->start_time);
- assert(ret);
- assert(_optlen);
- assert(_optoffset);
- assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE, DHCP_DECLINE));
-
- optlen = DHCP_MIN_OPTIONS_SIZE;
- size = sizeof(DHCPPacket) + optlen;
-
- packet = malloc0(size);
- if (!packet)
- return -ENOMEM;
-
- r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type,
- client->arp_type, client->mac_addr_len, client->mac_addr,
- optlen, &optoffset);
- if (r < 0)
- return r;
-
- /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
- refuse to issue an DHCP lease if 'secs' is set to zero */
- r = sd_event_now(client->event, CLOCK_BOOTTIME, &time_now);
- if (r < 0)
- return r;
- assert(time_now >= client->start_time);
-
- /* seconds between sending first and last DISCOVER
- * must always be strictly positive to deal with broken servers */
- secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
- packet->dhcp.secs = htobe16(secs);
-
- /* 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
- DHCPREQUEST messages that client sends. The BROADCAST bit will
- provide a hint to the DHCP server and BOOTP relay agent to broadcast
- any messages to the client on the client's subnet.
-
- Note: some interfaces needs this to be enabled, but some networks
- needs this to be disabled as broadcasts are filteretd, so this
- needs to be configurable */
- if (client->request_broadcast || client->arp_type != ARPHRD_ETHER)
- packet->dhcp.flags = htobe16(0x8000);
-
- /* If no client identifier exists, construct an RFC 4361-compliant one */
- if (client->client_id_len == 0) {
- size_t duid_len;
-
- client->client_id.type = 255;
-
- r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len,
- /* legacy_unstable_byteorder = */ true,
- /* use_mac = */ client->test_mode,
- &client->client_id.ns.iaid);
- if (r < 0)
- return r;
-
- r = dhcp_identifier_set_duid_en(client->test_mode, &client->client_id.ns.duid, &duid_len);
- if (r < 0)
- return r;
-
- client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len;
- }
-
- /* Some DHCP servers will refuse to issue an DHCP lease if the Client
- Identifier option is not set */
- if (client->client_id_len) {
- r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_CLIENT_IDENTIFIER,
- client->client_id_len,
- &client->client_id);
- if (r < 0)
- return r;
- }
-
- /* RFC2131 section 3.5:
- in its initial DHCPDISCOVER or DHCPREQUEST message, a
- client may provide the server with a list of specific
- parameters the client is interested in. If the client
- includes a list of parameters in a DHCPDISCOVER message,
- it MUST include that list in any subsequent DHCPREQUEST
- messages.
- */
-
- /* RFC7844 section 3:
- MAY contain the Parameter Request List option. */
- /* NOTE: in case that there would be an option to do not send
- * any PRL at all, the size should be checked before sending */
- if (!set_isempty(client->req_opts) && type != DHCP_RELEASE) {
- _cleanup_free_ uint8_t *opts = NULL;
- size_t n_opts, i = 0;
- void *val;
-
- n_opts = set_size(client->req_opts);
- opts = new(uint8_t, n_opts);
- if (!opts)
- return -ENOMEM;
-
- SET_FOREACH(val, client->req_opts)
- opts[i++] = PTR_TO_UINT8(val);
- assert(i == n_opts);
-
- /* For anonymizing the request, let's sort the options. */
- typesafe_qsort(opts, n_opts, cmp_uint8);
-
- r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_PARAMETER_REQUEST_LIST,
- n_opts, opts);
- if (r < 0)
- return r;
- }
-
- /* RFC2131 section 3.5:
- The client SHOULD include the ā€™maximum DHCP message sizeā€™ option to
- let the server know how large the server may make its DHCP messages.
-
- Note (from ConnMan): Some DHCP servers will send bigger DHCP packets
- than the defined default size unless the Maximum Message Size option
- is explicitly set
-
- RFC3442 "Requirements to Avoid Sizing Constraints":
- Because a full routing table can be quite large, the standard 576
- octet maximum size for a DHCP message may be too short to contain
- some legitimate Classless Static Route options. Because of this,
- clients implementing the Classless Static Route option SHOULD send a
- Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP
- stack is capable of receiving larger IP datagrams. In this case, the
- client SHOULD set the value of this option to at least the MTU of the
- interface that the client is configuring. The client MAY set the
- value of this option higher, up to the size of the largest UDP packet
- it is prepared to accept. (Note that the value specified in the
- Maximum DHCP Message Size option is the total maximum packet size,
- including IP and UDP headers.)
- */
- /* RFC7844 section 3:
- SHOULD NOT contain any other option. */
- if (!client->anonymize && type != DHCP_RELEASE) {
- max_size = htobe16(size);
- r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0,
- SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE,
- 2, &max_size);
- if (r < 0)
- return r;
- }
-
- *_optlen = optlen;
- *_optoffset = optoffset;
- *ret = TAKE_PTR(packet);
-
- return 0;
-}
-
-static int client_append_fqdn_option(
- DHCPMessage *message,
- size_t optlen,
- size_t *optoffset,
- const char *fqdn) {
-
- uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH];
- int r;
-
- buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */
- DHCP_FQDN_FLAG_E; /* Canonical wire format */
- buffer[1] = 0; /* RCODE1 (deprecated) */
- buffer[2] = 0; /* RCODE2 (deprecated) */
-
- r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3, false);
- if (r > 0)
- r = dhcp_option_append(message, optlen, optoffset, 0,
- SD_DHCP_OPTION_FQDN, 3 + r, buffer);
-
- return r;
-}
-
-static int dhcp_client_send_raw(
- sd_dhcp_client *client,
- DHCPPacket *packet,
- size_t len) {
-
- dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port,
- INADDR_BROADCAST, DHCP_PORT_SERVER, len, client->ip_service_type);
-
- return dhcp_network_send_raw_socket(client->fd, &client->link,
- packet, len);
-}
-
-static int client_append_common_discover_request_options(sd_dhcp_client *client, DHCPPacket *packet, size_t *optoffset, size_t optlen) {
- sd_dhcp_option *j;
- int r;
-
- assert(client);
-
- if (client->hostname) {
- /* According to RFC 4702 "clients that send the Client FQDN option in
- their messages MUST NOT also send the Host Name option". Just send
- one of the two depending on the hostname type.
- */
- if (dns_name_is_single_label(client->hostname)) {
- /* it is unclear from RFC 2131 if client should send hostname in
- DHCPDISCOVER but dhclient does and so we do as well
- */
- r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
- SD_DHCP_OPTION_HOST_NAME,
- strlen(client->hostname), client->hostname);
- } else
- r = client_append_fqdn_option(&packet->dhcp, optlen, optoffset,
- client->hostname);
- if (r < 0)
- return r;
- }
-
- if (client->vendor_class_identifier) {
- r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
- SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER,
- strlen(client->vendor_class_identifier),
- client->vendor_class_identifier);
- if (r < 0)
- return r;
- }
-
- if (client->mudurl) {
- r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
- SD_DHCP_OPTION_MUD_URL,
- strlen(client->mudurl),
- client->mudurl);
- if (r < 0)
- return r;
- }
-
- if (client->user_class) {
- r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
- SD_DHCP_OPTION_USER_CLASS,
- strv_length(client->user_class),
- client->user_class);
- if (r < 0)
- return r;
- }
-
- ORDERED_HASHMAP_FOREACH(j, client->extra_options) {
- r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0,
- j->option, j->length, j->data);
- if (r < 0)
- return r;
- }
-
- if (!ordered_hashmap_isempty(client->vendor_options)) {
- r = dhcp_option_append(
- &packet->dhcp, optlen, optoffset, 0,
- SD_DHCP_OPTION_VENDOR_SPECIFIC,
- ordered_hashmap_size(client->vendor_options), client->vendor_options);
- if (r < 0)
- return r;
- }
-
-
- return 0;
-}
-
-static int client_send_discover(sd_dhcp_client *client) {
- _cleanup_free_ DHCPPacket *discover = NULL;
- size_t optoffset, optlen;
- int r;
-
- assert(client);
- assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING));
-
- r = client_message_init(client, &discover, DHCP_DISCOVER,
- &optlen, &optoffset);
- if (r < 0)
- return r;
-
- /* the client may suggest values for the network address
- and lease time in the DHCPDISCOVER message. The client may include
- the ā€™requested IP addressā€™ option to suggest that a particular IP
- address be assigned, and may include the ā€™IP address lease timeā€™
- option to suggest the lease time it would like.
- */
- /* RFC7844 section 3:
- SHOULD NOT contain any other option. */
- if (!client->anonymize && client->last_addr != INADDR_ANY) {
- r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
- 4, &client->last_addr);
- if (r < 0)
- return r;
- }
-
- r = client_append_common_discover_request_options(client, discover, &optoffset, optlen);
- if (r < 0)
- return r;
-
- r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_END, 0, NULL);
- if (r < 0)
- return r;
-
- /* We currently ignore:
- The client SHOULD wait a random time between one and ten seconds to
- desynchronize the use of DHCP at startup.
- */
- r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset);
- if (r < 0)
- return r;
-
- log_dhcp_client(client, "DISCOVER");
-
- return 0;
-}
-
-static int client_send_request(sd_dhcp_client *client) {
- _cleanup_free_ DHCPPacket *request = NULL;
- size_t optoffset, optlen;
- int r;
-
- assert(client);
-
- r = client_message_init(client, &request, DHCP_REQUEST, &optlen, &optoffset);
- if (r < 0)
- return r;
-
- switch (client->state) {
- /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC,
- SELECTING should be REQUESTING)
- */
-
- case DHCP_STATE_REQUESTING:
- /* Client inserts the address of the selected server in ā€™server
- identifierā€™, ā€™ciaddrā€™ MUST be zero, ā€™requested IP addressā€™ MUST be
- filled in with the yiaddr value from the chosen DHCPOFFER.
- */
-
- r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_SERVER_IDENTIFIER,
- 4, &client->lease->server_address);
- if (r < 0)
- return r;
-
- r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
- 4, &client->lease->address);
- if (r < 0)
- return r;
-
- break;
-
- case DHCP_STATE_INIT_REBOOT:
- /* ā€™server identifierā€™ MUST NOT be filled in, ā€™requested IP addressā€™
- option MUST be filled in with clientā€™s notion of its previously
- assigned address. ā€™ciaddrā€™ MUST be zero.
- */
- r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_REQUESTED_IP_ADDRESS,
- 4, &client->last_addr);
- if (r < 0)
- return r;
- break;
-
- case DHCP_STATE_RENEWING:
- /* ā€™server identifierā€™ MUST NOT be filled in, ā€™requested IP addressā€™
- option MUST NOT be filled in, ā€™ciaddrā€™ MUST be filled in with
- clientā€™s IP address.
- */
-
- case DHCP_STATE_REBINDING:
- /* ā€™server identifierā€™ MUST NOT be filled in, ā€™requested IP addressā€™
- option MUST NOT be filled in, ā€™ciaddrā€™ MUST be filled in with
- clientā€™s IP address.
-
- This message MUST be broadcast to the 0xffffffff IP broadcast address.
- */
- request->dhcp.ciaddr = client->lease->address;
-
- break;
-
- case DHCP_STATE_INIT:
- case DHCP_STATE_SELECTING:
- case DHCP_STATE_REBOOTING:
- case DHCP_STATE_BOUND:
- case DHCP_STATE_STOPPED:
- return -EINVAL;
- }
-
- r = client_append_common_discover_request_options(client, request, &optoffset, optlen);
- if (r < 0)
- return r;
-
- r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_END, 0, NULL);
- if (r < 0)
- return r;
-
- if (client->state == DHCP_STATE_RENEWING)
- r = dhcp_network_send_udp_socket(client->fd,
- client->lease->server_address,
- DHCP_PORT_SERVER,
- &request->dhcp,
- sizeof(DHCPMessage) + optoffset);
- else
- r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset);
- if (r < 0)
- return r;
-
- switch (client->state) {
-
- case DHCP_STATE_REQUESTING:
- log_dhcp_client(client, "REQUEST (requesting)");
- break;
-
- case DHCP_STATE_INIT_REBOOT:
- log_dhcp_client(client, "REQUEST (init-reboot)");
- break;
-
- case DHCP_STATE_RENEWING:
- log_dhcp_client(client, "REQUEST (renewing)");
- break;
-
- case DHCP_STATE_REBINDING:
- log_dhcp_client(client, "REQUEST (rebinding)");
- break;
-
- default:
- log_dhcp_client(client, "REQUEST (invalid)");
- break;
- }
-
- return 0;
-}
-
-static int client_start(sd_dhcp_client *client);
-
-static int client_timeout_resend(
- sd_event_source *s,
- uint64_t usec,
- void *userdata) {
-
- sd_dhcp_client *client = userdata;
- DHCP_CLIENT_DONT_DESTROY(client);
- usec_t next_timeout;
- uint64_t time_now;
- int r;
-
- assert(s);
- assert(client);
- assert(client->event);
-
- r = sd_event_now(client->event, CLOCK_BOOTTIME, &time_now);
- if (r < 0)
- goto error;
-
- switch (client->state) {
-
- case DHCP_STATE_RENEWING:
- next_timeout = client_compute_reacquisition_timeout(time_now, client->t2_time);
- break;
-
- case DHCP_STATE_REBINDING:
- next_timeout = client_compute_reacquisition_timeout(time_now, client->expire_time);
- break;
-
- case DHCP_STATE_REBOOTING:
- /* start over as we did not receive a timely ack or nak */
- r = client_initialize(client);
- if (r < 0)
- goto error;
-
- r = client_start(client);
- if (r < 0)
- goto error;
-
- log_dhcp_client(client, "REBOOTED");
- return 0;
-
- case DHCP_STATE_INIT:
- case DHCP_STATE_INIT_REBOOT:
- case DHCP_STATE_SELECTING:
- case DHCP_STATE_REQUESTING:
- case DHCP_STATE_BOUND:
- if (client->attempt >= client->max_attempts)
- goto error;
-
- client->attempt++;
- next_timeout = client_compute_request_timeout(time_now, client->attempt);
- break;
-
- case DHCP_STATE_STOPPED:
- r = -EINVAL;
- goto error;
-
- default:
- assert_not_reached();
- }
-
- r = event_reset_time(client->event, &client->timeout_resend,
- CLOCK_BOOTTIME,
- next_timeout, 10 * USEC_PER_MSEC,
- client_timeout_resend, client,
- client->event_priority, "dhcp4-resend-timer", true);
- if (r < 0)
- goto error;
-
- switch (client->state) {
- case DHCP_STATE_INIT:
- r = client_send_discover(client);
- if (r >= 0) {
- client->state = DHCP_STATE_SELECTING;
- client->attempt = 0;
- } else if (client->attempt >= client->max_attempts)
- goto error;
-
- break;
-
- case DHCP_STATE_SELECTING:
- r = client_send_discover(client);
- if (r < 0 && client->attempt >= client->max_attempts)
- goto error;
-
- break;
-
- case DHCP_STATE_INIT_REBOOT:
- case DHCP_STATE_REQUESTING:
- case DHCP_STATE_RENEWING:
- case DHCP_STATE_REBINDING:
- r = client_send_request(client);
- if (r < 0 && client->attempt >= client->max_attempts)
- goto error;
-
- if (client->state == DHCP_STATE_INIT_REBOOT)
- client->state = DHCP_STATE_REBOOTING;
-
- client->request_sent = time_now;
- break;
-
- case DHCP_STATE_REBOOTING:
- case DHCP_STATE_BOUND:
- break;
-
- case DHCP_STATE_STOPPED:
- r = -EINVAL;
- goto error;
- }
-
- if (client->attempt >= TRANSIENT_FAILURE_ATTEMPTS)
- client_notify(client, SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE);
-
- return 0;
-
-error:
- client_stop(client, r);
-
- /* Errors were dealt with when stopping the client, don't spill
- errors into the event loop handler */
- return 0;
-}
-
-static int client_initialize_io_events(
- sd_dhcp_client *client,
- sd_event_io_handler_t io_callback) {
-
- int r;
-
- assert(client);
- assert(client->event);
-
- r = sd_event_add_io(client->event, &client->receive_message,
- client->fd, EPOLLIN, io_callback,
- client);
- if (r < 0)
- goto error;
-
- r = sd_event_source_set_priority(client->receive_message,
- client->event_priority);
- if (r < 0)
- goto error;
-
- r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message");
- if (r < 0)
- goto error;
-
-error:
- if (r < 0)
- client_stop(client, r);
-
- return 0;
-}
-
-static int client_initialize_time_events(sd_dhcp_client *client) {
- uint64_t usec = 0;
- int r;
-
- assert(client);
- assert(client->event);
-
- if (client->start_delay > 0) {
- assert_se(sd_event_now(client->event, CLOCK_BOOTTIME, &usec) >= 0);
- usec += client->start_delay;
- }
-
- r = event_reset_time(client->event, &client->timeout_resend,
- CLOCK_BOOTTIME,
- usec, 0,
- client_timeout_resend, client,
- client->event_priority, "dhcp4-resend-timer", true);
- if (r < 0)
- client_stop(client, r);
-
- return 0;
-
-}
-
-static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) {
- client_initialize_io_events(client, io_callback);
- client_initialize_time_events(client);
-
- return 0;
-}
-
-static int client_start_delayed(sd_dhcp_client *client) {
- int r;
-
- assert_return(client, -EINVAL);
- assert_return(client->event, -EINVAL);
- assert_return(client->ifindex > 0, -EINVAL);
- assert_return(client->fd < 0, -EBUSY);
- assert_return(client->xid == 0, -EINVAL);
- assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT), -EBUSY);
-
- client->xid = random_u32();
-
- r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
- client->mac_addr, client->mac_addr_len,
- client->bcast_addr, client->bcast_addr_len,
- client->arp_type, client->port);
- if (r < 0) {
- client_stop(client, r);
- return r;
- }
- client->fd = r;
-
- if (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT))
- client->start_time = now(CLOCK_BOOTTIME);
-
- return client_initialize_events(client, client_receive_message_raw);
-}
-
-static int client_start(sd_dhcp_client *client) {
- client->start_delay = 0;
- return client_start_delayed(client);
-}
-
-static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) {
- sd_dhcp_client *client = userdata;
- DHCP_CLIENT_DONT_DESTROY(client);
-
- log_dhcp_client(client, "EXPIRED");
-
- client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
-
- /* lease was lost, start over if not freed or stopped in callback */
- if (client->state != DHCP_STATE_STOPPED) {
- client_initialize(client);
- client_start(client);
- }
-
- return 0;
-}
-
-static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
- sd_dhcp_client *client = userdata;
- DHCP_CLIENT_DONT_DESTROY(client);
- int r;
-
- assert(client);
-
- client->receive_message = sd_event_source_disable_unref(client->receive_message);
- client->fd = safe_close(client->fd);
-
- client->state = DHCP_STATE_REBINDING;
- client->attempt = 0;
-
- r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid,
- client->mac_addr, client->mac_addr_len,
- client->bcast_addr, client->bcast_addr_len,
- client->arp_type, client->port);
- if (r < 0) {
- client_stop(client, r);
- return 0;
- }
- client->fd = r;
-
- return client_initialize_events(client, client_receive_message_raw);
-}
-
-static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
- sd_dhcp_client *client = userdata;
- DHCP_CLIENT_DONT_DESTROY(client);
-
- if (client->lease)
- client->state = DHCP_STATE_RENEWING;
- else if (client->state != DHCP_STATE_INIT)
- client->state = DHCP_STATE_INIT_REBOOT;
- client->attempt = 0;
-
- return client_initialize_time_events(client);
-}
-
-static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) {
- _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
- int r;
-
- r = dhcp_lease_new(&lease);
- if (r < 0)
- return r;
-
- if (client->client_id_len) {
- r = dhcp_lease_set_client_id(lease,
- (uint8_t *) &client->client_id,
- client->client_id_len);
- if (r < 0)
- return r;
- }
-
- r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL);
- if (r != DHCP_OFFER) {
- log_dhcp_client(client, "received message was not an OFFER, ignoring");
- return -ENOMSG;
- }
-
- lease->next_server = offer->siaddr;
- lease->address = offer->yiaddr;
-
- if (lease->lifetime == 0 && client->fallback_lease_lifetime > 0)
- lease->lifetime = client->fallback_lease_lifetime;
-
- if (lease->address == 0 ||
- lease->server_address == 0 ||
- lease->lifetime == 0) {
- log_dhcp_client(client, "received lease lacks address, server address or lease lifetime, ignoring");
- return -ENOMSG;
- }
-
- if (!lease->have_subnet_mask) {
- r = dhcp_lease_set_default_subnet_mask(lease);
- if (r < 0) {
- log_dhcp_client(client,
- "received lease lacks subnet mask, "
- "and a fallback one cannot be generated, ignoring");
- return -ENOMSG;
- }
- }
-
- sd_dhcp_lease_unref(client->lease);
- client->lease = TAKE_PTR(lease);
-
- if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0)
- return -ENOMSG;
-
- log_dhcp_client(client, "OFFER");
-
- return 0;
-}
-
-static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) {
- int r;
-
- r = dhcp_option_parse(force, len, NULL, NULL, NULL);
- if (r != DHCP_FORCERENEW)
- return -ENOMSG;
-
-#if 0
- log_dhcp_client(client, "FORCERENEW");
-
- return 0;
-#else
- /* FIXME: Ignore FORCERENEW requests until we implement RFC3118 (Authentication for DHCP
- * Messages) and/or RFC6704 (Forcerenew Nonce Authentication), as unauthenticated FORCERENEW
- * requests causes a security issue (TALOS-2020-1142, CVE-2020-13529). */
- log_dhcp_client(client, "Received FORCERENEW, ignoring.");
- return -ENOMSG;
-#endif
-}
-
-static bool lease_equal(const sd_dhcp_lease *a, const sd_dhcp_lease *b) {
- if (a->address != b->address)
- return false;
-
- if (a->subnet_mask != b->subnet_mask)
- return false;
-
- if (a->router_size != b->router_size)
- return false;
-
- for (size_t i = 0; i < a->router_size; i++)
- if (a->router[i].s_addr != b->router[i].s_addr)
- return false;
-
- return true;
-}
-
-static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) {
- _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
- _cleanup_free_ char *error_message = NULL;
- int r;
-
- r = dhcp_lease_new(&lease);
- if (r < 0)
- return r;
-
- if (client->client_id_len) {
- r = dhcp_lease_set_client_id(lease,
- (uint8_t *) &client->client_id,
- client->client_id_len);
- if (r < 0)
- return r;
- }
-
- r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message);
- if (r == DHCP_NAK) {
- log_dhcp_client(client, "NAK: %s", strna(error_message));
- return -EADDRNOTAVAIL;
- }
-
- if (r != DHCP_ACK) {
- log_dhcp_client(client, "received message was not an ACK, ignoring");
- return -ENOMSG;
- }
-
- lease->next_server = ack->siaddr;
-
- lease->address = ack->yiaddr;
-
- if (lease->address == INADDR_ANY ||
- lease->server_address == INADDR_ANY ||
- lease->lifetime == 0) {
- log_dhcp_client(client, "received lease lacks address, server "
- "address or lease lifetime, ignoring");
- return -ENOMSG;
- }
-
- if (lease->subnet_mask == INADDR_ANY) {
- r = dhcp_lease_set_default_subnet_mask(lease);
- if (r < 0) {
- log_dhcp_client(client,
- "received lease lacks subnet mask, "
- "and a fallback one cannot be generated, ignoring");
- return -ENOMSG;
- }
- }
-
- r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
- if (client->lease) {
- if (lease_equal(client->lease, lease))
- r = SD_DHCP_CLIENT_EVENT_RENEW;
- else
- r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
-
- client->lease = sd_dhcp_lease_unref(client->lease);
- }
-
- client->lease = TAKE_PTR(lease);
-
- log_dhcp_client(client, "ACK");
-
- return r;
-}
-
-static int client_set_lease_timeouts(sd_dhcp_client *client) {
- usec_t time_now;
- int r;
-
- assert(client);
- assert(client->event);
- assert(client->lease);
- assert(client->lease->lifetime);
-
- /* don't set timers for infinite leases */
- if (client->lease->lifetime == 0xffffffff) {
- (void) event_source_disable(client->timeout_t1);
- (void) event_source_disable(client->timeout_t2);
- (void) event_source_disable(client->timeout_expire);
-
- return 0;
- }
-
- r = sd_event_now(client->event, CLOCK_BOOTTIME, &time_now);
- if (r < 0)
- return r;
- assert(client->request_sent <= time_now);
-
- /* verify that 0 < t2 < lifetime */
- if (client->lease->t2 == 0 || client->lease->t2 >= client->lease->lifetime)
- client->lease->t2 = T2_DEFAULT(client->lease->lifetime);
- /* verify that 0 < t1 < lifetime */
- if (client->lease->t1 == 0 || client->lease->t1 >= client->lease->t2)
- client->lease->t1 = T1_DEFAULT(client->lease->lifetime);
- /* now, if t1 >= t2, t1 *must* be T1_DEFAULT, since the previous check
- * could not evalate to false if t1 >= t2; so setting t2 to T2_DEFAULT
- * guarantees t1 < t2. */
- if (client->lease->t1 >= client->lease->t2)
- client->lease->t2 = T2_DEFAULT(client->lease->lifetime);
-
- client->expire_time = client->request_sent + client->lease->lifetime * USEC_PER_SEC;
- client->t1_time = client->request_sent + client->lease->t1 * USEC_PER_SEC;
- client->t2_time = client->request_sent + client->lease->t2 * USEC_PER_SEC;
-
- /* RFC2131 section 4.4.5:
- * Times T1 and T2 SHOULD be chosen with some random "fuzz".
- * Since the RFC doesn't specify here the exact 'fuzz' to use,
- * we use the range from section 4.1: -1 to +1 sec. */
- client->t1_time = usec_sub_signed(client->t1_time, RFC2131_RANDOM_FUZZ);
- client->t2_time = usec_sub_signed(client->t2_time, RFC2131_RANDOM_FUZZ);
-
- /* after fuzzing, ensure t2 is still >= t1 */
- client->t2_time = MAX(client->t1_time, client->t2_time);
-
- /* arm lifetime timeout */
- r = event_reset_time(client->event, &client->timeout_expire,
- CLOCK_BOOTTIME,
- client->expire_time, 10 * USEC_PER_MSEC,
- client_timeout_expire, client,
- client->event_priority, "dhcp4-lifetime", true);
- if (r < 0)
- return r;
-
- /* don't arm earlier timeouts if this has already expired */
- if (client->expire_time <= time_now)
- return 0;
-
- log_dhcp_client(client, "lease expires in %s",
- FORMAT_TIMESPAN(client->expire_time - time_now, USEC_PER_SEC));
-
- /* arm T2 timeout */
- r = event_reset_time(client->event, &client->timeout_t2,
- CLOCK_BOOTTIME,
- client->t2_time, 10 * USEC_PER_MSEC,
- client_timeout_t2, client,
- client->event_priority, "dhcp4-t2-timeout", true);
- if (r < 0)
- return r;
-
- /* don't arm earlier timeout if this has already expired */
- if (client->t2_time <= time_now)
- return 0;
-
- log_dhcp_client(client, "T2 expires in %s",
- FORMAT_TIMESPAN(client->t2_time - time_now, USEC_PER_SEC));
-
- /* arm T1 timeout */
- r = event_reset_time(client->event, &client->timeout_t1,
- CLOCK_BOOTTIME,
- client->t1_time, 10 * USEC_PER_MSEC,
- client_timeout_t1, client,
- client->event_priority, "dhcp4-t1-timer", true);
- if (r < 0)
- return r;
-
- if (client->t1_time > time_now)
- log_dhcp_client(client, "T1 expires in %s",
- FORMAT_TIMESPAN(client->t1_time - time_now, USEC_PER_SEC));
-
- return 0;
-}
-
-static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) {
- DHCP_CLIENT_DONT_DESTROY(client);
- int r, notify_event;
-
- assert(client);
- assert(client->event);
- assert(message);
-
- switch (client->state) {
- case DHCP_STATE_SELECTING:
-
- r = client_handle_offer(client, message, len);
- if (r == -ENOMSG)
- return 0; /* invalid message, let's ignore it */
- if (r < 0)
- goto error;
-
- client->state = DHCP_STATE_REQUESTING;
- client->attempt = 0;
-
- r = event_reset_time(client->event, &client->timeout_resend,
- CLOCK_BOOTTIME,
- 0, 0,
- client_timeout_resend, client,
- client->event_priority, "dhcp4-resend-timer", true);
- break;
-
- case DHCP_STATE_REBOOTING:
- case DHCP_STATE_REQUESTING:
- case DHCP_STATE_RENEWING:
- case DHCP_STATE_REBINDING:
-
- r = client_handle_ack(client, message, len);
- if (r == -ENOMSG)
- return 0; /* invalid message, let's ignore it */
- if (r == -EADDRNOTAVAIL) {
- /* got a NAK, let's restart the client */
- client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
-
- r = client_initialize(client);
- if (r < 0)
- goto error;
-
- r = client_start_delayed(client);
- if (r < 0)
- goto error;
-
- log_dhcp_client(client, "REBOOT in %s", FORMAT_TIMESPAN(client->start_delay, USEC_PER_SEC));
-
- client->start_delay = CLAMP(client->start_delay * 2,
- RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC);
- return 0;
- }
- if (r < 0)
- goto error;
-
- if (IN_SET(client->state, DHCP_STATE_REQUESTING, DHCP_STATE_REBOOTING))
- notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
- else
- notify_event = r;
-
- client->start_delay = 0;
- (void) event_source_disable(client->timeout_resend);
- client->receive_message = sd_event_source_disable_unref(client->receive_message);
- client->fd = safe_close(client->fd);
-
- client->state = DHCP_STATE_BOUND;
- client->attempt = 0;
-
- client->last_addr = client->lease->address;
-
- r = client_set_lease_timeouts(client);
- if (r < 0) {
- log_dhcp_client(client, "could not set lease timeouts");
- goto error;
- }
-
- r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port, client->ip_service_type);
- if (r < 0) {
- log_dhcp_client(client, "could not bind UDP socket");
- goto error;
- }
-
- client->fd = r;
-
- client_initialize_io_events(client, client_receive_message_udp);
-
- if (IN_SET(client->state, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING) &&
- notify_event == SD_DHCP_CLIENT_EVENT_IP_ACQUIRE)
- /* FIXME: hmm, maybe this is a bug... */
- log_dhcp_client(client, "client_handle_ack() returned SD_DHCP_CLIENT_EVENT_IP_ACQUIRE while DHCP client is %s the address, skipping callback.",
- client->state == DHCP_STATE_RENEWING ? "renewing" : "rebinding");
- else
- client_notify(client, notify_event);
- break;
-
- case DHCP_STATE_BOUND:
- r = client_handle_forcerenew(client, message, len);
- if (r == -ENOMSG)
- return 0; /* invalid message, let's ignore it */
- if (r < 0)
- goto error;
-
- r = client_timeout_t1(NULL, 0, client);
- break;
-
- case DHCP_STATE_INIT:
- case DHCP_STATE_INIT_REBOOT:
- r = 0;
- break;
-
- case DHCP_STATE_STOPPED:
- r = -EINVAL;
- goto error;
- default:
- assert_not_reached();
- }
-
-error:
- if (r < 0)
- client_stop(client, r);
-
- return r;
-}
-
-static int client_receive_message_udp(
- sd_event_source *s,
- int fd,
- uint32_t revents,
- void *userdata) {
-
- sd_dhcp_client *client = userdata;
- _cleanup_free_ DHCPMessage *message = NULL;
- const uint8_t *expected_chaddr = NULL;
- uint8_t expected_hlen = 0;
- ssize_t len, buflen;
-
- assert(s);
- assert(client);
-
- buflen = next_datagram_size_fd(fd);
- 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;
- }
-
- message = malloc0(buflen);
- if (!message)
- return -ENOMEM;
-
- len = recv(fd, message, buflen, 0);
- if (len < 0) {
- if (ERRNO_IS_TRANSIENT(errno) || ERRNO_IS_DISCONNECT(errno))
- return 0;
-
- 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");
- return 0;
- }
-
- if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) {
- log_dhcp_client(client, "Not a DHCP message: ignoring");
- return 0;
- }
-
- if (message->op != BOOTREPLY) {
- log_dhcp_client(client, "Not a BOOTREPLY message: ignoring");
- return 0;
- }
-
- if (message->htype != client->arp_type) {
- log_dhcp_client(client, "Packet type does not match client type");
- return 0;
- }
-
- if (client->arp_type == ARPHRD_ETHER) {
- expected_hlen = ETH_ALEN;
- expected_chaddr = &client->mac_addr[0];
- }
-
- if (message->hlen != expected_hlen) {
- log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen);
- return 0;
- }
-
- if (expected_hlen > 0 && memcmp(&message->chaddr[0], expected_chaddr, expected_hlen)) {
- log_dhcp_client(client, "Received chaddr does not match expected: ignoring");
- return 0;
- }
-
- if (client->state != DHCP_STATE_BOUND &&
- be32toh(message->xid) != client->xid) {
- /* in BOUND state, we may receive FORCERENEW with xid set by server,
- so ignore the xid in this case */
- log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring",
- be32toh(message->xid), client->xid);
- return 0;
- }
-
- 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(
- sd_event_source *s,
- int fd,
- uint32_t revents,
- void *userdata) {
-
- sd_dhcp_client *client = userdata;
- _cleanup_free_ DHCPPacket *packet = NULL;
- CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct tpacket_auxdata))) control;
- struct iovec iov = {};
- struct msghdr msg = {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
- bool checksum = true;
- ssize_t buflen, len;
- int r;
-
- assert(s);
- assert(client);
-
- buflen = next_datagram_size_fd(fd);
- 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;
- }
-
- packet = malloc0(buflen);
- if (!packet)
- return -ENOMEM;
-
- iov = IOVEC_MAKE(packet, buflen);
-
- len = recvmsg_safe(fd, &msg, 0);
- 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;
-
- cmsg = cmsg_find(&msg, SOL_PACKET, PACKET_AUXDATA, CMSG_LEN(sizeof(struct tpacket_auxdata)));
- if (cmsg) {
- struct tpacket_auxdata *aux = (struct tpacket_auxdata*) CMSG_DATA(cmsg);
- checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
- }
-
- r = dhcp_packet_verify_headers(packet, len, checksum, client->port);
- if (r < 0)
- return 0;
-
- len -= DHCP_IP_UDP_SIZE;
-
- 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) {
- assert_return(client, -EINVAL);
- assert_return(client->fd >= 0, -EINVAL);
-
- if (!client->lease)
- return 0;
-
- client->start_delay = 0;
- client->attempt = 1;
- client->state = DHCP_STATE_RENEWING;
-
- return client_initialize_time_events(client);
-}
-
-int sd_dhcp_client_is_running(sd_dhcp_client *client) {
- if (!client)
- return 0;
-
- return !IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED);
-}
-
-int sd_dhcp_client_start(sd_dhcp_client *client) {
- int r;
-
- assert_return(client, -EINVAL);
-
- r = client_initialize(client);
- if (r < 0)
- return r;
-
- /* RFC7844 section 3.3:
- SHOULD perform a complete four-way handshake, starting with a
- DHCPDISCOVER, to obtain a new address lease. If the client can
- ascertain that this is exactly the same network to which it was
- previously connected, and if the link-layer address did not change,
- the client MAY issue a DHCPREQUEST to try to reclaim the current
- address. */
- if (client->last_addr && !client->anonymize)
- client->state = DHCP_STATE_INIT_REBOOT;
-
- r = client_start(client);
- if (r >= 0)
- log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex);
-
- return r;
-}
-
-int sd_dhcp_client_send_release(sd_dhcp_client *client) {
- assert_return(client, -EINVAL);
- assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE);
- assert_return(client->lease, -EUNATCH);
-
- _cleanup_free_ DHCPPacket *release = NULL;
- size_t optoffset, optlen;
- int r;
-
- r = client_message_init(client, &release, DHCP_RELEASE, &optlen, &optoffset);
- if (r < 0)
- return r;
-
- /* Fill up release IP and MAC */
- release->dhcp.ciaddr = client->lease->address;
- memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
-
- r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_END, 0, NULL);
- if (r < 0)
- return r;
-
- r = dhcp_network_send_udp_socket(client->fd,
- client->lease->server_address,
- DHCP_PORT_SERVER,
- &release->dhcp,
- sizeof(DHCPMessage) + optoffset);
- if (r < 0)
- return r;
-
- log_dhcp_client(client, "RELEASE");
-
- return 0;
-}
-
-int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
- assert_return(client, -EINVAL);
- assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE);
- assert_return(client->lease, -EUNATCH);
-
- _cleanup_free_ DHCPPacket *release = NULL;
- size_t optoffset, optlen;
- int r;
-
- r = client_message_init(client, &release, DHCP_DECLINE, &optlen, &optoffset);
- if (r < 0)
- return r;
-
- release->dhcp.ciaddr = client->lease->address;
- memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len);
-
- r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0,
- SD_DHCP_OPTION_END, 0, NULL);
- if (r < 0)
- return r;
-
- r = dhcp_network_send_udp_socket(client->fd,
- client->lease->server_address,
- DHCP_PORT_SERVER,
- &release->dhcp,
- sizeof(DHCPMessage) + optoffset);
- if (r < 0)
- return r;
-
- log_dhcp_client(client, "DECLINE");
-
- client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
-
- if (client->state != DHCP_STATE_STOPPED) {
- r = sd_dhcp_client_start(client);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-int sd_dhcp_client_stop(sd_dhcp_client *client) {
- if (!client)
- return 0;
-
- DHCP_CLIENT_DONT_DESTROY(client);
-
- client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
- client->state = DHCP_STATE_STOPPED;
-
- return 0;
-}
-
-int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) {
- int r;
-
- assert_return(client, -EINVAL);
- assert_return(!client->event, -EBUSY);
-
- if (event)
- client->event = sd_event_ref(event);
- else {
- r = sd_event_default(&client->event);
- if (r < 0)
- return 0;
- }
-
- client->event_priority = priority;
-
- return 0;
-}
-
-int sd_dhcp_client_detach_event(sd_dhcp_client *client) {
- assert_return(client, -EINVAL);
-
- client->event = sd_event_unref(client->event);
-
- return 0;
-}
-
-sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) {
- assert_return(client, NULL);
-
- return client->event;
-}
-
-static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) {
- if (!client)
- return NULL;
-
- log_dhcp_client(client, "FREE");
-
- client_initialize(client);
-
- client->timeout_resend = sd_event_source_unref(client->timeout_resend);
- client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
- client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
- client->timeout_expire = sd_event_source_unref(client->timeout_expire);
-
- sd_dhcp_client_detach_event(client);
-
- set_free(client->req_opts);
- free(client->hostname);
- free(client->vendor_class_identifier);
- free(client->mudurl);
- client->user_class = strv_free(client->user_class);
- ordered_hashmap_free(client->extra_options);
- ordered_hashmap_free(client->vendor_options);
- free(client->ifname);
- return mfree(client);
-}
-
-DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free);
-
-int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) {
- const uint8_t *opts;
- size_t n_opts;
- int r;
-
- assert_return(ret, -EINVAL);
-
- _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = new(sd_dhcp_client, 1);
- if (!client)
- return -ENOMEM;
-
- *client = (sd_dhcp_client) {
- .n_ref = 1,
- .state = DHCP_STATE_INIT,
- .ifindex = -1,
- .fd = -1,
- .mtu = DHCP_DEFAULT_MIN_SIZE,
- .port = DHCP_PORT_CLIENT,
- .anonymize = !!anonymize,
- .max_attempts = UINT64_MAX,
- .ip_service_type = -1,
- };
- /* NOTE: this could be moved to a function. */
- if (anonymize) {
- n_opts = ELEMENTSOF(default_req_opts_anonymize);
- opts = default_req_opts_anonymize;
- } else {
- n_opts = ELEMENTSOF(default_req_opts);
- opts = default_req_opts;
- }
-
- for (size_t i = 0; i < n_opts; i++) {
- r = sd_dhcp_client_set_request_option(client, opts[i]);
- if (r < 0)
- return r;
- }
-
- *ret = TAKE_PTR(client);
-
- return 0;
-}
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
deleted file mode 100644
index 5f83fa66ae..0000000000
--- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c
+++ /dev/null
@@ -1,1508 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/***
- Copyright Ā© 2013 Intel Corporation. All rights reserved.
-***/
-
-#include "nm-sd-adapt-core.h"
-
-#include <arpa/inet.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "sd-dhcp-lease.h"
-
-#include "alloc-util.h"
-#include "dhcp-lease-internal.h"
-#include "dhcp-protocol.h"
-#include "dns-domain.h"
-#include "env-file.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "hexdecoct.h"
-#include "hostname-util.h"
-#include "in-addr-util.h"
-#include "network-internal.h"
-#include "parse-util.h"
-#include "stdio-util.h"
-#include "string-util.h"
-#include "strv.h"
-#include "tmpfile-util.h"
-#include "unaligned.h"
-
-int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
- assert_return(lease, -EINVAL);
- assert_return(addr, -EINVAL);
-
- if (lease->address == 0)
- return -ENODATA;
-
- addr->s_addr = lease->address;
- return 0;
-}
-
-int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) {
- assert_return(lease, -EINVAL);
- assert_return(addr, -EINVAL);
-
- if (!lease->have_broadcast)
- return -ENODATA;
-
- addr->s_addr = lease->broadcast;
- return 0;
-}
-
-int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
- assert_return(lease, -EINVAL);
- assert_return(lifetime, -EINVAL);
-
- if (lease->lifetime <= 0)
- return -ENODATA;
-
- *lifetime = lease->lifetime;
- return 0;
-}
-
-int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1) {
- assert_return(lease, -EINVAL);
- assert_return(t1, -EINVAL);
-
- if (lease->t1 <= 0)
- return -ENODATA;
-
- *t1 = lease->t1;
- return 0;
-}
-
-int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2) {
- assert_return(lease, -EINVAL);
- assert_return(t2, -EINVAL);
-
- if (lease->t2 <= 0)
- return -ENODATA;
-
- *t2 = lease->t2;
- return 0;
-}
-
-int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) {
- assert_return(lease, -EINVAL);
- assert_return(mtu, -EINVAL);
-
- if (lease->mtu <= 0)
- return -ENODATA;
-
- *mtu = lease->mtu;
- return 0;
-}
-
-int sd_dhcp_lease_get_servers(
- sd_dhcp_lease *lease,
- sd_dhcp_lease_server_type_t what,
- const struct in_addr **addr) {
-
- assert_return(lease, -EINVAL);
- assert_return(what >= 0, -EINVAL);
- assert_return(what < _SD_DHCP_LEASE_SERVER_TYPE_MAX, -EINVAL);
-
- if (lease->servers[what].size <= 0)
- return -ENODATA;
-
- if (addr)
- *addr = lease->servers[what].addr;
-
- return (int) lease->servers[what].size;
-}
-
-int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) {
- return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_DNS, addr);
-}
-int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) {
- return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_NTP, addr);
-}
-int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr) {
- return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SIP, addr);
-}
-int sd_dhcp_lease_get_pop3(sd_dhcp_lease *lease, const struct in_addr **addr) {
- return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_POP3, addr);
-}
-int sd_dhcp_lease_get_smtp(sd_dhcp_lease *lease, const struct in_addr **addr) {
- return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SMTP, addr);
-}
-int sd_dhcp_lease_get_lpr(sd_dhcp_lease *lease, const struct in_addr **addr) {
- return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_LPR, addr);
-}
-
-int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) {
- assert_return(lease, -EINVAL);
- assert_return(domainname, -EINVAL);
-
- if (!lease->domainname)
- return -ENODATA;
-
- *domainname = lease->domainname;
- return 0;
-}
-
-int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) {
- assert_return(lease, -EINVAL);
- assert_return(hostname, -EINVAL);
-
- if (!lease->hostname)
- return -ENODATA;
-
- *hostname = lease->hostname;
- return 0;
-}
-
-int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
- assert_return(lease, -EINVAL);
- assert_return(root_path, -EINVAL);
-
- if (!lease->root_path)
- return -ENODATA;
-
- *root_path = lease->root_path;
- return 0;
-}
-
-int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr) {
- assert_return(lease, -EINVAL);
- assert_return(addr, -EINVAL);
-
- if (lease->router_size <= 0)
- return -ENODATA;
-
- *addr = lease->router;
- return (int) lease->router_size;
-}
-
-int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
- assert_return(lease, -EINVAL);
- assert_return(addr, -EINVAL);
-
- if (!lease->have_subnet_mask)
- return -ENODATA;
-
- addr->s_addr = lease->subnet_mask;
- return 0;
-}
-
-int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) {
- assert_return(lease, -EINVAL);
- assert_return(addr, -EINVAL);
-
- if (lease->server_address == 0)
- return -ENODATA;
-
- addr->s_addr = lease->server_address;
- return 0;
-}
-
-int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) {
- assert_return(lease, -EINVAL);
- assert_return(addr, -EINVAL);
-
- if (lease->next_server == 0)
- return -ENODATA;
-
- addr->s_addr = lease->next_server;
- return 0;
-}
-
-/*
- * The returned routes array must be freed by the caller.
- * Route objects have the same lifetime of the lease and must not be freed.
- */
-static int dhcp_lease_get_routes(sd_dhcp_route *routes, size_t n_routes, sd_dhcp_route ***ret) {
- assert(routes || n_routes == 0);
-
- if (n_routes <= 0)
- return -ENODATA;
-
- if (ret) {
- sd_dhcp_route **buf;
-
- buf = new(sd_dhcp_route*, n_routes);
- if (!buf)
- return -ENOMEM;
-
- for (size_t i = 0; i < n_routes; i++)
- buf[i] = &routes[i];
-
- *ret = buf;
- }
-
- return (int) n_routes;
-}
-
-int sd_dhcp_lease_get_static_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret) {
- assert_return(lease, -EINVAL);
-
- return dhcp_lease_get_routes(lease->static_routes, lease->n_static_routes, ret);
-}
-
-int sd_dhcp_lease_get_classless_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret) {
- assert_return(lease, -EINVAL);
-
- return dhcp_lease_get_routes(lease->classless_routes, lease->n_classless_routes, ret);
-}
-
-int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) {
- size_t r;
-
- assert_return(lease, -EINVAL);
- assert_return(domains, -EINVAL);
-
- r = strv_length(lease->search_domains);
- if (r > 0) {
- *domains = lease->search_domains;
- return (int) r;
- }
-
- 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);
- assert_return(data_len, -EINVAL);
-
- if (lease->vendor_specific_len <= 0)
- return -ENODATA;
-
- *data = lease->vendor_specific;
- *data_len = lease->vendor_specific_len;
- return 0;
-}
-
-static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
- assert(lease);
-
- while (lease->private_options) {
- struct sd_dhcp_raw_option *option = lease->private_options;
-
- LIST_REMOVE(options, lease->private_options, option);
-
- free(option->data);
- free(option);
- }
-
- free(lease->root_path);
- free(lease->router);
- free(lease->timezone);
- free(lease->hostname);
- free(lease->domainname);
-
- for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++)
- free(lease->servers[i].addr);
-
- free(lease->static_routes);
- free(lease->classless_routes);
- free(lease->client_id);
- free(lease->vendor_specific);
- strv_free(lease->search_domains);
- free(lease->sixrd_br_addresses);
- return mfree(lease);
-}
-
-DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_lease, sd_dhcp_lease, dhcp_lease_free);
-
-static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
- assert(option);
- assert(ret);
-
- if (len != 4)
- return -EINVAL;
-
- *ret = unaligned_read_be32((be32_t*) option);
- if (*ret < min)
- *ret = min;
-
- return 0;
-}
-
-static int lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
- assert(option);
- assert(ret);
-
- if (len != 2)
- return -EINVAL;
-
- *ret = unaligned_read_be16((be16_t*) option);
- if (*ret < min)
- *ret = min;
-
- return 0;
-}
-
-static int lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) {
- assert(option);
- assert(ret);
-
- if (len != 4)
- return -EINVAL;
-
- memcpy(ret, option, 4);
- return 0;
-}
-
-static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
- assert(option);
- assert(ret);
-
- if (len <= 0)
- *ret = mfree(*ret);
- else {
- char *string;
-
- /*
- * One trailing NUL byte is OK, we don't mind. See:
- * https://github.com/systemd/systemd/issues/1337
- */
- if (memchr(option, 0, len - 1))
- return -EINVAL;
-
- string = memdup_suffix0((const char *) option, len);
- if (!string)
- return -ENOMEM;
-
- free_and_replace(*ret, string);
- }
-
- return 0;
-}
-
-static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
- _cleanup_free_ char *name = NULL, *normalized = NULL;
- int r;
-
- assert(option);
- assert(ret);
-
- r = lease_parse_string(option, len, &name);
- if (r < 0)
- return r;
- if (!name) {
- *ret = mfree(*ret);
- return 0;
- }
-
- r = dns_name_normalize(name, 0, &normalized);
- if (r < 0)
- return r;
-
- if (is_localhost(normalized))
- return -EINVAL;
-
- if (dns_name_is_root(normalized))
- return -EINVAL;
-
- free_and_replace(*ret, normalized);
-
- return 0;
-}
-
-static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
- assert(option || len == 0);
- assert(ret);
- assert(n_ret);
-
- if (len <= 0) {
- *ret = mfree(*ret);
- *n_ret = 0;
- } else {
- size_t n_addresses;
- struct in_addr *addresses;
-
- if (len % 4 != 0)
- return -EINVAL;
-
- n_addresses = len / 4;
-
- addresses = newdup(struct in_addr, option, n_addresses);
- if (!addresses)
- return -ENOMEM;
-
- free(*ret);
- *ret = addresses;
- *n_ret = n_addresses;
- }
-
- return 0;
-}
-
-static int lease_parse_sip_server(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
- assert(option || len == 0);
- assert(ret);
- assert(n_ret);
-
- if (len <= 0)
- return -EINVAL;
-
- /* The SIP record is like the other, regular server records, but prefixed with a single "encoding"
- * byte that is either 0 or 1. We only support it to be 1 for now. Let's drop it and parse it like
- * the other fields */
-
- if (option[0] != 1) { /* We only support IP address encoding for now */
- *ret = mfree(*ret);
- *n_ret = 0;
- return 0;
- }
-
- return lease_parse_in_addrs(option + 1, len - 1, ret, n_ret);
-}
-
-static int lease_parse_static_routes(sd_dhcp_lease *lease, const uint8_t *option, size_t len) {
- int r;
-
- assert(lease);
- assert(option || len <= 0);
-
- if (len % 8 != 0)
- return -EINVAL;
-
- while (len >= 8) {
- struct in_addr dst, gw;
- uint8_t prefixlen;
-
- assert_se(lease_parse_be32(option, 4, &dst.s_addr) >= 0);
- option += 4;
-
- assert_se(lease_parse_be32(option, 4, &gw.s_addr) >= 0);
- option += 4;
-
- len -= 8;
-
- r = in4_addr_default_prefixlen(&dst, &prefixlen);
- if (r < 0) {
- log_debug("sd-dhcp-lease: cannot determine class of received static route, ignoring.");
- continue;
- }
-
- (void) in4_addr_mask(&dst, prefixlen);
-
- if (!GREEDY_REALLOC(lease->static_routes, lease->n_static_routes + 1))
- return -ENOMEM;
-
- lease->static_routes[lease->n_static_routes++] = (struct sd_dhcp_route) {
- .dst_addr = dst,
- .gw_addr = gw,
- .dst_prefixlen = prefixlen,
- };
- }
-
- return 0;
-}
-
-/* parses RFC3442 Classless Static Route Option */
-static int lease_parse_classless_routes(sd_dhcp_lease *lease, const uint8_t *option, size_t len) {
- assert(lease);
- assert(option || len <= 0);
-
- /* option format: (subnet-mask-width significant-subnet-octets gateway-ip) */
-
- while (len > 0) {
- uint8_t prefixlen, dst_octets;
- struct in_addr dst = {}, gw;
-
- prefixlen = *option;
- option++;
- len--;
-
- dst_octets = DIV_ROUND_UP(prefixlen, 8);
-
- /* can't have more than 4 octets in IPv4 */
- if (dst_octets > 4 || len < dst_octets)
- return -EINVAL;
-
- memcpy(&dst, option, dst_octets);
- option += dst_octets;
- len -= dst_octets;
-
- if (len < 4)
- return -EINVAL;
-
- assert_se(lease_parse_be32(option, 4, &gw.s_addr) >= 0);
- option += 4;
- len -= 4;
-
- if (!GREEDY_REALLOC(lease->classless_routes, lease->n_classless_routes + 1))
- return -ENOMEM;
-
- lease->classless_routes[lease->n_classless_routes++] = (struct sd_dhcp_route) {
- .dst_addr = dst,
- .gw_addr = gw,
- .dst_prefixlen = prefixlen,
- };
- }
-
- 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;
-
- assert(lease);
-
- switch (code) {
-
- case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME:
- r = lease_parse_u32(option, len, &lease->lifetime, 1);
- if (r < 0)
- log_debug_errno(r, "Failed to parse lease time, ignoring: %m");
-
- break;
-
- case SD_DHCP_OPTION_SERVER_IDENTIFIER:
- r = lease_parse_be32(option, len, &lease->server_address);
- if (r < 0)
- log_debug_errno(r, "Failed to parse server identifier, ignoring: %m");
-
- break;
-
- case SD_DHCP_OPTION_SUBNET_MASK:
- r = lease_parse_be32(option, len, &lease->subnet_mask);
- if (r < 0)
- log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m");
- else
- lease->have_subnet_mask = true;
- break;
-
- case SD_DHCP_OPTION_BROADCAST:
- r = lease_parse_be32(option, len, &lease->broadcast);
- if (r < 0)
- log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m");
- else
- lease->have_broadcast = true;
- break;
-
- case SD_DHCP_OPTION_ROUTER:
- r = lease_parse_in_addrs(option, len, &lease->router, &lease->router_size);
- if (r < 0)
- log_debug_errno(r, "Failed to parse router addresses, ignoring: %m");
- break;
-
- case SD_DHCP_OPTION_DOMAIN_NAME_SERVER:
- r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_DNS].addr, &lease->servers[SD_DHCP_LEASE_DNS].size);
- if (r < 0)
- log_debug_errno(r, "Failed to parse DNS server, ignoring: %m");
- break;
-
- case SD_DHCP_OPTION_NTP_SERVER:
- r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_NTP].addr, &lease->servers[SD_DHCP_LEASE_NTP].size);
- if (r < 0)
- log_debug_errno(r, "Failed to parse NTP server, ignoring: %m");
- break;
-
- case SD_DHCP_OPTION_SIP_SERVER:
- r = lease_parse_sip_server(option, len, &lease->servers[SD_DHCP_LEASE_SIP].addr, &lease->servers[SD_DHCP_LEASE_SIP].size);
- if (r < 0)
- log_debug_errno(r, "Failed to parse SIP server, ignoring: %m");
- break;
-
- case SD_DHCP_OPTION_POP3_SERVER:
- r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_POP3].addr, &lease->servers[SD_DHCP_LEASE_POP3].size);
- if (r < 0)
- log_debug_errno(r, "Failed to parse POP3 server, ignoring: %m");
- break;
-
- case SD_DHCP_OPTION_SMTP_SERVER:
- r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_SMTP].addr, &lease->servers[SD_DHCP_LEASE_SMTP].size);
- if (r < 0)
- log_debug_errno(r, "Failed to parse SMTP server, ignoring: %m");
- break;
-
- case SD_DHCP_OPTION_LPR_SERVER:
- r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_LPR].addr, &lease->servers[SD_DHCP_LEASE_LPR].size);
- if (r < 0)
- log_debug_errno(r, "Failed to parse LPR server, ignoring: %m");
- break;
-
- case SD_DHCP_OPTION_STATIC_ROUTE:
- r = lease_parse_static_routes(lease, option, len);
- if (r < 0)
- log_debug_errno(r, "Failed to parse static routes, ignoring: %m");
- break;
-
- case SD_DHCP_OPTION_MTU_INTERFACE:
- r = lease_parse_u16(option, len, &lease->mtu, 68);
- if (r < 0)
- log_debug_errno(r, "Failed to parse MTU, ignoring: %m");
- if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) {
- log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE);
- lease->mtu = DHCP_DEFAULT_MIN_SIZE;
- }
-
- break;
-
- case SD_DHCP_OPTION_DOMAIN_NAME:
- r = lease_parse_domain(option, len, &lease->domainname);
- if (r < 0) {
- log_debug_errno(r, "Failed to parse domain name, ignoring: %m");
- return 0;
- }
-
- break;
-
- case SD_DHCP_OPTION_DOMAIN_SEARCH:
- r = dhcp_lease_parse_search_domains(option, len, &lease->search_domains);
- if (r < 0)
- log_debug_errno(r, "Failed to parse Domain Search List, ignoring: %m");
- break;
-
- case SD_DHCP_OPTION_HOST_NAME:
- r = lease_parse_domain(option, len, &lease->hostname);
- if (r < 0) {
- log_debug_errno(r, "Failed to parse hostname, ignoring: %m");
- return 0;
- }
-
- break;
-
- case SD_DHCP_OPTION_ROOT_PATH:
- r = lease_parse_string(option, len, &lease->root_path);
- if (r < 0)
- log_debug_errno(r, "Failed to parse root path, ignoring: %m");
- break;
-
- case SD_DHCP_OPTION_RENEWAL_TIME:
- r = lease_parse_u32(option, len, &lease->t1, 1);
- if (r < 0)
- log_debug_errno(r, "Failed to parse T1 time, ignoring: %m");
- break;
-
- case SD_DHCP_OPTION_REBINDING_TIME:
- r = lease_parse_u32(option, len, &lease->t2, 1);
- if (r < 0)
- log_debug_errno(r, "Failed to parse T2 time, ignoring: %m");
- break;
-
- case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
- r = lease_parse_classless_routes(lease, option, len);
- if (r < 0)
- log_debug_errno(r, "Failed to parse classless routes, ignoring: %m");
- break;
-
- case SD_DHCP_OPTION_TZDB_TIMEZONE: {
- _cleanup_free_ char *tz = NULL;
-
- r = lease_parse_string(option, len, &tz);
- if (r < 0) {
- log_debug_errno(r, "Failed to parse timezone option, ignoring: %m");
- return 0;
- }
-
- if (!timezone_is_valid(tz, LOG_DEBUG)) {
- log_debug("Timezone is not valid, ignoring.");
- return 0;
- }
-
- free_and_replace(lease->timezone, tz);
-
- break;
- }
-
- case SD_DHCP_OPTION_VENDOR_SPECIFIC:
-
- if (len <= 0)
- lease->vendor_specific = mfree(lease->vendor_specific);
- else {
- void *p;
-
- p = memdup(option, len);
- if (!p)
- return -ENOMEM;
-
- free(lease->vendor_specific);
- lease->vendor_specific = p;
- }
-
- 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)
- return r;
-
- break;
-
- default:
- log_debug("Ignoring option DHCP option %"PRIu8" while parsing.", code);
- break;
- }
-
- return 0;
-}
-
-/* Parses compressed domain names. */
-int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***domains) {
- _cleanup_strv_free_ char **names = NULL;
- size_t pos = 0, cnt = 0;
- int r;
-
- assert(domains);
- assert_return(option && len > 0, -ENODATA);
-
- while (pos < len) {
- _cleanup_free_ char *name = NULL;
- size_t n = 0;
- size_t jump_barrier = pos, next_chunk = 0;
- bool first = true;
-
- for (;;) {
- uint8_t c;
- c = option[pos++];
-
- if (c == 0) {
- /* End of name */
- break;
- } else if (c <= 63) {
- const char *label;
-
- /* Literal label */
- label = (const char*) (option + pos);
- pos += c;
- if (pos >= len)
- return -EBADMSG;
-
- if (!GREEDY_REALLOC(name, n + !first + DNS_LABEL_ESCAPED_MAX))
- return -ENOMEM;
-
- if (first)
- first = false;
- else
- name[n++] = '.';
-
- r = dns_label_escape(label, c, name + n, DNS_LABEL_ESCAPED_MAX);
- if (r < 0)
- return r;
-
- n += r;
- } else if (FLAGS_SET(c, 0xc0)) {
- /* Pointer */
-
- uint8_t d;
- uint16_t ptr;
-
- if (pos >= len)
- return -EBADMSG;
-
- d = option[pos++];
- ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
-
- /* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */
- if (ptr >= jump_barrier)
- return -EBADMSG;
- jump_barrier = ptr;
-
- /* Save current location so we don't end up re-parsing what's parsed so far. */
- if (next_chunk == 0)
- next_chunk = pos;
-
- pos = ptr;
- } else
- return -EBADMSG;
- }
-
- if (!GREEDY_REALLOC(name, n + 1))
- return -ENOMEM;
- name[n] = 0;
-
- r = strv_extend(&names, name);
- if (r < 0)
- return r;
-
- cnt++;
-
- if (next_chunk != 0)
- pos = next_chunk;
- }
-
- strv_free_and_replace(*domains, names);
-
- return cnt;
-}
-
-int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len) {
- struct sd_dhcp_raw_option *option, *before = NULL;
-
- assert(lease);
-
- LIST_FOREACH(options, cur, lease->private_options) {
- if (tag < cur->tag) {
- before = cur;
- break;
- }
- if (tag == cur->tag) {
- log_debug("Ignoring duplicate option, tagged %i.", tag);
- return 0;
- }
- }
-
- option = new(struct sd_dhcp_raw_option, 1);
- if (!option)
- return -ENOMEM;
-
- option->tag = tag;
- option->length = len;
- option->data = memdup(data, len);
- if (!option->data) {
- free(option);
- return -ENOMEM;
- }
-
- LIST_INSERT_BEFORE(options, lease->private_options, before, option);
- return 0;
-}
-
-int dhcp_lease_new(sd_dhcp_lease **ret) {
- sd_dhcp_lease *lease;
-
- lease = new0(sd_dhcp_lease, 1);
- if (!lease)
- return -ENOMEM;
-
- lease->n_ref = 1;
-
- *ret = lease;
- return 0;
-}
-
-int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
- _cleanup_(unlink_and_freep) char *temp_path = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- struct in_addr address;
- const struct in_addr *addresses;
- const void *client_id, *data;
- size_t client_id_len, data_len;
- char sbuf[INET_ADDRSTRLEN];
- const char *string;
- uint16_t mtu;
- _cleanup_free_ sd_dhcp_route **routes = NULL;
- char **search_domains;
- uint32_t t1, t2, lifetime;
- int r;
-
- assert(lease);
- assert(lease_file);
-
- r = fopen_temporary(lease_file, &f, &temp_path);
- if (r < 0)
- return r;
-
- (void) fchmod(fileno(f), 0644);
-
- fprintf(f,
- "# This is private data. Do not parse.\n");
-
- r = sd_dhcp_lease_get_address(lease, &address);
- if (r >= 0)
- fprintf(f, "ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
-
- r = sd_dhcp_lease_get_netmask(lease, &address);
- if (r >= 0)
- fprintf(f, "NETMASK=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
-
- r = sd_dhcp_lease_get_router(lease, &addresses);
- if (r > 0) {
- fputs("ROUTER=", f);
- serialize_in_addrs(f, addresses, r, false, NULL);
- fputc('\n', f);
- }
-
- r = sd_dhcp_lease_get_server_identifier(lease, &address);
- if (r >= 0)
- fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
-
- r = sd_dhcp_lease_get_next_server(lease, &address);
- if (r >= 0)
- fprintf(f, "NEXT_SERVER=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
-
- r = sd_dhcp_lease_get_broadcast(lease, &address);
- if (r >= 0)
- fprintf(f, "BROADCAST=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
-
- r = sd_dhcp_lease_get_mtu(lease, &mtu);
- if (r >= 0)
- fprintf(f, "MTU=%" PRIu16 "\n", mtu);
-
- r = sd_dhcp_lease_get_t1(lease, &t1);
- if (r >= 0)
- fprintf(f, "T1=%" PRIu32 "\n", t1);
-
- r = sd_dhcp_lease_get_t2(lease, &t2);
- if (r >= 0)
- fprintf(f, "T2=%" PRIu32 "\n", t2);
-
- r = sd_dhcp_lease_get_lifetime(lease, &lifetime);
- if (r >= 0)
- fprintf(f, "LIFETIME=%" PRIu32 "\n", lifetime);
-
- r = sd_dhcp_lease_get_dns(lease, &addresses);
- if (r > 0) {
- fputs("DNS=", f);
- serialize_in_addrs(f, addresses, r, false, NULL);
- fputc('\n', f);
- }
-
- r = sd_dhcp_lease_get_ntp(lease, &addresses);
- if (r > 0) {
- fputs("NTP=", f);
- serialize_in_addrs(f, addresses, r, false, NULL);
- fputc('\n', f);
- }
-
- r = sd_dhcp_lease_get_sip(lease, &addresses);
- if (r > 0) {
- fputs("SIP=", f);
- serialize_in_addrs(f, addresses, r, false, NULL);
- fputc('\n', f);
- }
-
- r = sd_dhcp_lease_get_domainname(lease, &string);
- if (r >= 0)
- fprintf(f, "DOMAINNAME=%s\n", string);
-
- r = sd_dhcp_lease_get_search_domains(lease, &search_domains);
- if (r > 0) {
- fputs("DOMAIN_SEARCH_LIST=", f);
- fputstrv(f, search_domains, NULL, NULL);
- fputc('\n', f);
- }
-
- r = sd_dhcp_lease_get_hostname(lease, &string);
- if (r >= 0)
- fprintf(f, "HOSTNAME=%s\n", string);
-
- r = sd_dhcp_lease_get_root_path(lease, &string);
- if (r >= 0)
- fprintf(f, "ROOT_PATH=%s\n", string);
-
- r = sd_dhcp_lease_get_static_routes(lease, &routes);
- if (r > 0)
- serialize_dhcp_routes(f, "STATIC_ROUTES", routes, r);
-
- routes = mfree(routes);
- r = sd_dhcp_lease_get_classless_routes(lease, &routes);
- if (r > 0)
- serialize_dhcp_routes(f, "CLASSLESS_ROUTES", routes, r);
-
- r = sd_dhcp_lease_get_timezone(lease, &string);
- if (r >= 0)
- fprintf(f, "TIMEZONE=%s\n", string);
-
- r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
- if (r >= 0) {
- _cleanup_free_ char *client_id_hex = NULL;
-
- client_id_hex = hexmem(client_id, client_id_len);
- if (!client_id_hex)
- return -ENOMEM;
- fprintf(f, "CLIENTID=%s\n", client_id_hex);
- }
-
- r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len);
- if (r >= 0) {
- _cleanup_free_ char *option_hex = NULL;
-
- option_hex = hexmem(data, data_len);
- if (!option_hex)
- return -ENOMEM;
- fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
- }
-
- LIST_FOREACH(options, option, lease->private_options) {
- char key[STRLEN("OPTION_000")+1];
-
- xsprintf(key, "OPTION_%" PRIu8, option->tag);
- r = serialize_dhcp_option(f, key, option->data, option->length);
- if (r < 0)
- return r;
- }
-
- r = fflush_and_check(f);
- if (r < 0)
- return r;
-
- r = conservative_rename(temp_path, lease_file);
- if (r < 0)
- return r;
-
- temp_path = mfree(temp_path);
-
- return 0;
-}
-
-static char **private_options_free(char **options) {
- if (!options)
- return NULL;
-
- for (unsigned i = 0; i < SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE + 1; i++)
- free(options[i]);
-
- return mfree(options);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(char**, private_options_free);
-
-int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
- _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
- _cleanup_free_ char
- *address = NULL,
- *router = NULL,
- *netmask = NULL,
- *server_address = NULL,
- *next_server = NULL,
- *broadcast = NULL,
- *dns = NULL,
- *ntp = NULL,
- *sip = NULL,
- *pop3 = NULL,
- *smtp = NULL,
- *lpr = NULL,
- *mtu = NULL,
- *static_routes = NULL,
- *classless_routes = NULL,
- *domains = NULL,
- *client_id_hex = NULL,
- *vendor_specific_hex = NULL,
- *lifetime = NULL,
- *t1 = NULL,
- *t2 = NULL;
- _cleanup_(private_options_freep) char **options = NULL;
-
- int r, i;
-
- assert(lease_file);
- assert(ret);
-
- r = dhcp_lease_new(&lease);
- if (r < 0)
- return r;
-
- options = new0(char*, SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE + 1);
- if (!options)
- return -ENOMEM;
-
- r = parse_env_file(NULL, lease_file,
- "ADDRESS", &address,
- "ROUTER", &router,
- "NETMASK", &netmask,
- "SERVER_ADDRESS", &server_address,
- "NEXT_SERVER", &next_server,
- "BROADCAST", &broadcast,
- "DNS", &dns,
- "NTP", &ntp,
- "SIP", &sip,
- "POP3", &pop3,
- "SMTP", &smtp,
- "LPR", &lpr,
- "MTU", &mtu,
- "DOMAINNAME", &lease->domainname,
- "HOSTNAME", &lease->hostname,
- "DOMAIN_SEARCH_LIST", &domains,
- "ROOT_PATH", &lease->root_path,
- "STATIC_ROUTES", &static_routes,
- "CLASSLESS_ROUTES", &classless_routes,
- "CLIENTID", &client_id_hex,
- "TIMEZONE", &lease->timezone,
- "VENDOR_SPECIFIC", &vendor_specific_hex,
- "LIFETIME", &lifetime,
- "T1", &t1,
- "T2", &t2,
- "OPTION_224", &options[0],
- "OPTION_225", &options[1],
- "OPTION_226", &options[2],
- "OPTION_227", &options[3],
- "OPTION_228", &options[4],
- "OPTION_229", &options[5],
- "OPTION_230", &options[6],
- "OPTION_231", &options[7],
- "OPTION_232", &options[8],
- "OPTION_233", &options[9],
- "OPTION_234", &options[10],
- "OPTION_235", &options[11],
- "OPTION_236", &options[12],
- "OPTION_237", &options[13],
- "OPTION_238", &options[14],
- "OPTION_239", &options[15],
- "OPTION_240", &options[16],
- "OPTION_241", &options[17],
- "OPTION_242", &options[18],
- "OPTION_243", &options[19],
- "OPTION_244", &options[20],
- "OPTION_245", &options[21],
- "OPTION_246", &options[22],
- "OPTION_247", &options[23],
- "OPTION_248", &options[24],
- "OPTION_249", &options[25],
- "OPTION_250", &options[26],
- "OPTION_251", &options[27],
- "OPTION_252", &options[28],
- "OPTION_253", &options[29],
- "OPTION_254", &options[30]);
- if (r < 0)
- return r;
-
- if (address) {
- r = inet_pton(AF_INET, address, &lease->address);
- if (r <= 0)
- log_debug("Failed to parse address %s, ignoring.", address);
- }
-
- if (router) {
- r = deserialize_in_addrs(&lease->router, router);
- if (r < 0)
- log_debug_errno(r, "Failed to deserialize router addresses %s, ignoring: %m", router);
- else
- lease->router_size = r;
- }
-
- if (netmask) {
- r = inet_pton(AF_INET, netmask, &lease->subnet_mask);
- if (r <= 0)
- log_debug("Failed to parse netmask %s, ignoring.", netmask);
- else
- lease->have_subnet_mask = true;
- }
-
- if (server_address) {
- r = inet_pton(AF_INET, server_address, &lease->server_address);
- if (r <= 0)
- log_debug("Failed to parse server address %s, ignoring.", server_address);
- }
-
- if (next_server) {
- r = inet_pton(AF_INET, next_server, &lease->next_server);
- if (r <= 0)
- log_debug("Failed to parse next server %s, ignoring.", next_server);
- }
-
- if (broadcast) {
- r = inet_pton(AF_INET, broadcast, &lease->broadcast);
- if (r <= 0)
- log_debug("Failed to parse broadcast address %s, ignoring.", broadcast);
- else
- lease->have_broadcast = true;
- }
-
- if (dns) {
- r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_DNS].addr, dns);
- if (r < 0)
- log_debug_errno(r, "Failed to deserialize DNS servers %s, ignoring: %m", dns);
- else
- lease->servers[SD_DHCP_LEASE_DNS].size = r;
- }
-
- if (ntp) {
- r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_NTP].addr, ntp);
- if (r < 0)
- log_debug_errno(r, "Failed to deserialize NTP servers %s, ignoring: %m", ntp);
- else
- lease->servers[SD_DHCP_LEASE_NTP].size = r;
- }
-
- if (sip) {
- r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_SIP].addr, sip);
- if (r < 0)
- log_debug_errno(r, "Failed to deserialize SIP servers %s, ignoring: %m", sip);
- else
- lease->servers[SD_DHCP_LEASE_SIP].size = r;
- }
-
- if (pop3) {
- r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_POP3].addr, pop3);
- if (r < 0)
- log_debug_errno(r, "Failed to deserialize POP3 server %s, ignoring: %m", pop3);
- else
- lease->servers[SD_DHCP_LEASE_POP3].size = r;
- }
-
- if (smtp) {
- r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_SMTP].addr, smtp);
- if (r < 0)
- log_debug_errno(r, "Failed to deserialize SMTP server %s, ignoring: %m", smtp);
- else
- lease->servers[SD_DHCP_LEASE_SMTP].size = r;
- }
-
- if (lpr) {
- r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_LPR].addr, lpr);
- if (r < 0)
- log_debug_errno(r, "Failed to deserialize LPR server %s, ignoring: %m", lpr);
- else
- lease->servers[SD_DHCP_LEASE_LPR].size = r;
- }
-
- if (mtu) {
- r = safe_atou16(mtu, &lease->mtu);
- if (r < 0)
- log_debug_errno(r, "Failed to parse MTU %s, ignoring: %m", mtu);
- }
-
- if (domains) {
- _cleanup_strv_free_ char **a = NULL;
- a = strv_split(domains, " ");
- if (!a)
- return -ENOMEM;
-
- if (!strv_isempty(a))
- lease->search_domains = TAKE_PTR(a);
- }
-
- if (static_routes) {
- r = deserialize_dhcp_routes(
- &lease->static_routes,
- &lease->n_static_routes,
- static_routes);
- if (r < 0)
- log_debug_errno(r, "Failed to parse DHCP static routes %s, ignoring: %m", static_routes);
- }
-
- if (classless_routes) {
- r = deserialize_dhcp_routes(
- &lease->classless_routes,
- &lease->n_classless_routes,
- classless_routes);
- if (r < 0)
- log_debug_errno(r, "Failed to parse DHCP classless routes %s, ignoring: %m", classless_routes);
- }
-
- if (lifetime) {
- r = safe_atou32(lifetime, &lease->lifetime);
- if (r < 0)
- log_debug_errno(r, "Failed to parse lifetime %s, ignoring: %m", lifetime);
- }
-
- if (t1) {
- r = safe_atou32(t1, &lease->t1);
- if (r < 0)
- log_debug_errno(r, "Failed to parse T1 %s, ignoring: %m", t1);
- }
-
- if (t2) {
- r = safe_atou32(t2, &lease->t2);
- if (r < 0)
- log_debug_errno(r, "Failed to parse T2 %s, ignoring: %m", t2);
- }
-
- if (client_id_hex) {
- r = unhexmem(client_id_hex, SIZE_MAX, &lease->client_id, &lease->client_id_len);
- if (r < 0)
- log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex);
- }
-
- if (vendor_specific_hex) {
- r = unhexmem(vendor_specific_hex, SIZE_MAX, &lease->vendor_specific, &lease->vendor_specific_len);
- if (r < 0)
- log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex);
- }
-
- for (i = 0; i <= SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE; i++) {
- _cleanup_free_ void *data = NULL;
- size_t len;
-
- if (!options[i])
- continue;
-
- r = unhexmem(options[i], SIZE_MAX, &data, &len);
- if (r < 0) {
- log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]);
- continue;
- }
-
- r = dhcp_lease_insert_private_option(lease, SD_DHCP_OPTION_PRIVATE_BASE + i, data, len);
- if (r < 0)
- return r;
- }
-
- *ret = TAKE_PTR(lease);
-
- return 0;
-}
-
-int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
- struct in_addr address, mask;
- int r;
-
- assert(lease);
-
- if (lease->address == 0)
- return -ENODATA;
-
- address.s_addr = lease->address;
-
- /* fall back to the default subnet masks based on address class */
- r = in4_addr_default_subnet_mask(&address, &mask);
- if (r < 0)
- return r;
-
- lease->subnet_mask = mask.s_addr;
- lease->have_subnet_mask = true;
-
- return 0;
-}
-
-int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) {
- assert_return(lease, -EINVAL);
- assert_return(client_id, -EINVAL);
- assert_return(client_id_len, -EINVAL);
-
- if (!lease->client_id)
- return -ENODATA;
-
- *client_id = lease->client_id;
- *client_id_len = lease->client_id_len;
-
- return 0;
-}
-
-int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len) {
- assert_return(lease, -EINVAL);
- assert_return(client_id || client_id_len <= 0, -EINVAL);
-
- if (client_id_len <= 0)
- lease->client_id = mfree(lease->client_id);
- else {
- void *p;
-
- p = memdup(client_id, client_id_len);
- if (!p)
- return -ENOMEM;
-
- free(lease->client_id);
- lease->client_id = p;
- lease->client_id_len = client_id_len;
- }
-
- return 0;
-}
-
-int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) {
- assert_return(lease, -EINVAL);
- assert_return(tz, -EINVAL);
-
- if (!lease->timezone)
- return -ENODATA;
-
- *tz = lease->timezone;
- return 0;
-}
-
-int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination) {
- assert_return(route, -EINVAL);
- assert_return(destination, -EINVAL);
-
- *destination = route->dst_addr;
- return 0;
-}
-
-int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length) {
- assert_return(route, -EINVAL);
- assert_return(length, -EINVAL);
-
- *length = route->dst_prefixlen;
- return 0;
-}
-
-int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) {
- assert_return(route, -EINVAL);
- assert_return(gateway, -EINVAL);
-
- *gateway = route->gw_addr;
- 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
deleted file mode 100644
index 834f80b421..0000000000
--- a/src/libnm-systemd-core/src/systemd/sd-dhcp-client.h
+++ /dev/null
@@ -1,345 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#ifndef foosddhcpclienthfoo
-#define foosddhcpclienthfoo
-
-/***
- Copyright Ā© 2013 Intel Corporation. All rights reserved.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <inttypes.h>
-#include <net/ethernet.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <stdbool.h>
-
-#include "sd-dhcp-lease.h"
-#include "sd-dhcp-option.h"
-#include "sd-event.h"
-
-#include "_sd-common.h"
-
-_SD_BEGIN_DECLARATIONS;
-
-enum {
- SD_DHCP_CLIENT_EVENT_STOP = 0,
- SD_DHCP_CLIENT_EVENT_IP_ACQUIRE = 1,
- SD_DHCP_CLIENT_EVENT_IP_CHANGE = 2,
- SD_DHCP_CLIENT_EVENT_EXPIRED = 3,
- SD_DHCP_CLIENT_EVENT_RENEW = 4,
- SD_DHCP_CLIENT_EVENT_SELECTING = 5,
- SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE = 6, /* Sent when we have not received a reply after the first few attempts.
- * The client may want to start acquiring link-local addresses. */
-};
-
-/* https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#options */
-enum {
- SD_DHCP_OPTION_PAD = 0, /* [RFC2132] */
- SD_DHCP_OPTION_SUBNET_MASK = 1, /* [RFC2132] */
- SD_DHCP_OPTION_TIME_OFFSET = 2, /* [RFC2132], deprecated by 100 and 101 */
- SD_DHCP_OPTION_ROUTER = 3, /* [RFC2132] */
- SD_DHCP_OPTION_TIME_SERVER = 4, /* [RFC2132] */
- SD_DHCP_OPTION_NAME_SERVER = 5, /* [RFC2132] */
- SD_DHCP_OPTION_DOMAIN_NAME_SERVER = 6, /* [RFC2132] */
- SD_DHCP_OPTION_LOG_SERVER = 7, /* [RFC2132] */
- SD_DHCP_OPTION_QUOTES_SERVER = 8, /* [RFC2132] */
- SD_DHCP_OPTION_LPR_SERVER = 9, /* [RFC2132] */
- SD_DHCP_OPTION_IMPRESS_SERVER = 10, /* [RFC2132] */
- SD_DHCP_OPTION_RLP_SERVER = 11, /* [RFC2132] */
- SD_DHCP_OPTION_HOST_NAME = 12, /* [RFC2132] */
- SD_DHCP_OPTION_BOOT_FILE_SIZE = 13, /* [RFC2132] */
- SD_DHCP_OPTION_MERIT_DUMP_FILE = 14, /* [RFC2132] */
- SD_DHCP_OPTION_DOMAIN_NAME = 15, /* [RFC2132] */
- SD_DHCP_OPTION_SWAP_SERVER = 16, /* [RFC2132] */
- SD_DHCP_OPTION_ROOT_PATH = 17, /* [RFC2132] */
- SD_DHCP_OPTION_EXTENSION_FILE = 18, /* [RFC2132] */
- SD_DHCP_OPTION_FORWARD = 19, /* [RFC2132] */
- SD_DHCP_OPTION_SOURCE_ROUTE = 20, /* [RFC2132] */
- SD_DHCP_OPTION_POLICY_FILTER = 21, /* [RFC2132] */
- SD_DHCP_OPTION_MAX_DATAGRAM_ASSEMBLY = 22, /* [RFC2132] */
- SD_DHCP_OPTION_DEFAULT_IP_TTL = 23, /* [RFC2132] */
- SD_DHCP_OPTION_MTU_TIMEOUT = 24, /* [RFC2132] */
- SD_DHCP_OPTION_MTU_PLATEAU = 25, /* [RFC2132] */
- SD_DHCP_OPTION_MTU_INTERFACE = 26, /* [RFC2132] */
- SD_DHCP_OPTION_MTU_SUBNET = 27, /* [RFC2132] */
- SD_DHCP_OPTION_BROADCAST = 28, /* [RFC2132] */
- SD_DHCP_OPTION_MASK_DISCOVERY = 29, /* [RFC2132] */
- SD_DHCP_OPTION_MASK_SUPPLIER = 30, /* [RFC2132] */
- SD_DHCP_OPTION_ROUTER_DISCOVERY = 31, /* [RFC2132] */
- SD_DHCP_OPTION_ROUTER_REQUEST = 32, /* [RFC2132] */
- SD_DHCP_OPTION_STATIC_ROUTE = 33, /* [RFC2132] */
- SD_DHCP_OPTION_TRAILERS = 34, /* [RFC2132] */
- SD_DHCP_OPTION_ARP_TIMEOUT = 35, /* [RFC2132] */
- SD_DHCP_OPTION_ETHERNET = 36, /* [RFC2132] */
- SD_DHCP_OPTION_DEFAULT_TCP_TTL = 37, /* [RFC2132] */
- SD_DHCP_OPTION_KEEPALIVE_TIME = 38, /* [RFC2132] */
- SD_DHCP_OPTION_KEEPALIVE_DATA = 39, /* [RFC2132] */
- SD_DHCP_OPTION_NIS_DOMAIN = 40, /* [RFC2132] */
- SD_DHCP_OPTION_NIS_SERVER = 41, /* [RFC2132] */
- SD_DHCP_OPTION_NTP_SERVER = 42, /* [RFC2132] */
- SD_DHCP_OPTION_VENDOR_SPECIFIC = 43, /* [RFC2132] */
- SD_DHCP_OPTION_NETBIOS_NAME_SERVER = 44, /* [RFC2132] */
- SD_DHCP_OPTION_NETBIOS_DIST_SERVER = 45, /* [RFC2132] */
- SD_DHCP_OPTION_NETBIOS_NODE_TYPE = 46, /* [RFC2132] */
- SD_DHCP_OPTION_NETBIOS_SCOPE = 47, /* [RFC2132] */
- SD_DHCP_OPTION_X_WINDOW_FONT = 48, /* [RFC2132] */
- SD_DHCP_OPTION_X_WINDOW_MANAGER = 49, /* [RFC2132] */
- SD_DHCP_OPTION_REQUESTED_IP_ADDRESS = 50, /* [RFC2132] */
- SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51, /* [RFC2132] */
- SD_DHCP_OPTION_OVERLOAD = 52, /* [RFC2132] */
- SD_DHCP_OPTION_MESSAGE_TYPE = 53, /* [RFC2132] */
- SD_DHCP_OPTION_SERVER_IDENTIFIER = 54, /* [RFC2132] */
- SD_DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, /* [RFC2132] */
- SD_DHCP_OPTION_ERROR_MESSAGE = 56, /* [RFC2132] */
- SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57, /* [RFC2132] */
- SD_DHCP_OPTION_RENEWAL_TIME = 58, /* [RFC2132] */
- SD_DHCP_OPTION_REBINDING_TIME = 59, /* [RFC2132] */
- SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, /* [RFC2132] */
- SD_DHCP_OPTION_CLIENT_IDENTIFIER = 61, /* [RFC2132] */
- SD_DHCP_OPTION_NETWARE_IP_DOMAIN = 62, /* [RFC2242] */
- SD_DHCP_OPTION_NETWARE_IP_OPTION = 63, /* [RFC2242] */
- SD_DHCP_OPTION_NIS_DOMAIN_NAME = 64, /* [RFC2132] */
- SD_DHCP_OPTION_NIS_SERVER_ADDR = 65, /* [RFC2132] */
- SD_DHCP_OPTION_BOOT_SERVER_NAME = 66, /* [RFC2132] */
- SD_DHCP_OPTION_BOOT_FILENAME = 67, /* [RFC2132] */
- SD_DHCP_OPTION_HOME_AGENT_ADDRESSES = 68, /* [RFC2132] */
- SD_DHCP_OPTION_SMTP_SERVER = 69, /* [RFC2132] */
- SD_DHCP_OPTION_POP3_SERVER = 70, /* [RFC2132] */
- SD_DHCP_OPTION_NNTP_SERVER = 71, /* [RFC2132] */
- SD_DHCP_OPTION_WWW_SERVER = 72, /* [RFC2132] */
- SD_DHCP_OPTION_FINGER_SERVER = 73, /* [RFC2132] */
- SD_DHCP_OPTION_IRC_SERVER = 74, /* [RFC2132] */
- SD_DHCP_OPTION_STREETTALK_SERVER = 75, /* [RFC2132] */
- SD_DHCP_OPTION_STDA_SERVER = 76, /* [RFC2132] */
- SD_DHCP_OPTION_USER_CLASS = 77, /* [RFC3004] */
- SD_DHCP_OPTION_DIRECTORY_AGENT = 78, /* [RFC2610] */
- SD_DHCP_OPTION_SERVICE_SCOPE = 79, /* [RFC2610] */
- SD_DHCP_OPTION_RAPID_COMMIT = 80, /* [RFC4039] */
- SD_DHCP_OPTION_FQDN = 81, /* [RFC4702] */
- SD_DHCP_OPTION_RELAY_AGENT_INFORMATION = 82, /* [RFC3046] */
- SD_DHCP_OPTION_ISNS = 83, /* [RFC4174] */
- /* option code 84 is unassigned [RFC3679] */
- SD_DHCP_OPTION_NDS_SERVER = 85, /* [RFC2241] */
- SD_DHCP_OPTION_NDS_TREE_NAME = 86, /* [RFC2241] */
- SD_DHCP_OPTION_NDS_CONTEXT = 87, /* [RFC2241] */
- SD_DHCP_OPTION_BCMCS_CONTROLLER_DOMAIN_NAM = 88, /* [RFC4280] */
- SD_DHCP_OPTION_BCMCS_CONTROLLER_ADDRESS = 89, /* [RFC4280] */
- SD_DHCP_OPTION_AUTHENTICATION = 90, /* [RFC3118] */
- SD_DHCP_OPTION_CLIENT_LAST_TRANSACTION_TIME = 91, /* [RFC4388] */
- SD_DHCP_OPTION_ASSOCIATED_IP = 92, /* [RFC4388] */
- SD_DHCP_OPTION_CLIENT_SYSTEM = 93, /* [RFC4578] */
- SD_DHCP_OPTION_CLIENT_NDI = 94, /* [RFC4578] */
- SD_DHCP_OPTION_LDAP = 95, /* [RFC3679] */
- /* option code 96 is unassigned [RFC3679] */
- SD_DHCP_OPTION_UUID = 97, /* [RFC4578] */
- SD_DHCP_OPTION_USER_AUTHENTICATION = 98, /* [RFC2485] */
- SD_DHCP_OPTION_GEOCONF_CIVIC = 99, /* [RFC4776] */
- SD_DHCP_OPTION_POSIX_TIMEZONE = 100, /* [RFC4833] */
- SD_DHCP_OPTION_TZDB_TIMEZONE = 101, /* [RFC4833] */
- /* option codes 102-107 are unassigned [RFC3679] */
- SD_DHCP_OPTION_IPV6_ONLY_PREFERRED = 108, /* [RFC8925] */
- SD_DHCP_OPTION_DHCP4O6_SOURCE_ADDRESS = 109, /* [RFC8539] */
- /* option codes 110-111 are unassigned [RFC3679] */
- SD_DHCP_OPTION_NETINFO_ADDRESS = 112, /* [RFC3679] */
- SD_DHCP_OPTION_NETINFO_TAG = 113, /* [RFC3679] */
- SD_DHCP_OPTION_DHCP_CAPTIVE_PORTAL = 114, /* [RFC8910] */
- /* option code 115 is unassigned [RFC3679] */
- SD_DHCP_OPTION_AUTO_CONFIG = 116, /* [RFC2563] */
- SD_DHCP_OPTION_NAME_SERVICE_SEARCH = 117, /* [RFC2937] */
- SD_DHCP_OPTION_SUBNET_SELECTION = 118, /* [RFC3011] */
- SD_DHCP_OPTION_DOMAIN_SEARCH = 119, /* [RFC3397] */
- SD_DHCP_OPTION_SIP_SERVER = 120, /* [RFC3361] */
- SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, /* [RFC3442] */
- SD_DHCP_OPTION_CABLELABS_CLIENT_CONFIGURATION = 122, /* [RFC3495] */
- SD_DHCP_OPTION_GEOCONF = 123, /* [RFC6225] */
- SD_DHCP_OPTION_VENDOR_CLASS = 124, /* [RFC3925] */
- SD_DHCP_OPTION_VENDOR_SPECIFIC_INFORMATION = 125, /* [RFC3925] */
- /* option codes 126-127 are unassigned [RFC3679] */
- /* option codes 128-135 are assigned to use by PXE, but they are vendor specific [RFC4578] */
- SD_DHCP_OPTION_PANA_AGENT = 136, /* [RFC5192] */
- SD_DHCP_OPTION_LOST_SERVER_FQDN = 137, /* [RFC5223] */
- SD_DHCP_OPTION_CAPWAP_AC_ADDRESS = 138, /* [RFC5417] */
- SD_DHCP_OPTION_MOS_ADDRESS = 139, /* [RFC5678] */
- SD_DHCP_OPTION_MOS_FQDN = 140, /* [RFC5678] */
- SD_DHCP_OPTION_SIP_SERVICE_DOMAINS = 141, /* [RFC6011] */
- SD_DHCP_OPTION_ANDSF_ADDRESS = 142, /* [RFC6153] */
- SD_DHCP_OPTION_SZTP_REDIRECT = 143, /* [RFC8572] */
- SD_DHCP_OPTION_GEOLOC = 144, /* [RFC6225] */
- SD_DHCP_OPTION_FORCERENEW_NONCE_CAPABLE = 145, /* [RFC6704] */
- SD_DHCP_OPTION_RDNSS_SELECTION = 146, /* [RFC6731] */
- SD_DHCP_OPTION_DOTS_RI = 147, /* [RFC8973] */
- SD_DHCP_OPTION_DOTS_ADDRESS = 148, /* [RFC8973] */
- /* option code 149 is unassigned [RFC3942] */
- SD_DHCP_OPTION_TFTP_SERVER_ADDRESS = 150, /* [RFC5859] */
- SD_DHCP_OPTION_STATUS_CODE = 151, /* [RFC6926] */
- SD_DHCP_OPTION_BASE_TIME = 152, /* [RFC6926] */
- SD_DHCP_OPTION_START_TIME_OF_STATE = 153, /* [RFC6926] */
- SD_DHCP_OPTION_QUERY_START_TIME = 154, /* [RFC6926] */
- SD_DHCP_OPTION_QUERY_END_TIME = 155, /* [RFC6926] */
- SD_DHCP_OPTION_DHCP_STATE = 156, /* [RFC6926] */
- SD_DHCP_OPTION_DATA_SOURCE = 157, /* [RFC6926] */
- SD_DHCP_OPTION_PCP_SERVER = 158, /* [RFC7291] */
- SD_DHCP_OPTION_PORT_PARAMS = 159, /* [RFC7618] */
- /* option code 160 is unassigned [RFC7710][RFC8910] */
- SD_DHCP_OPTION_MUD_URL = 161, /* [RFC8520] */
- /* option codes 162-174 are unassigned [RFC3942] */
- /* option codes 175-177 are temporary assigned. */
- /* option codes 178-207 are unassigned [RFC3942] */
- SD_DHCP_OPTION_PXELINUX_MAGIC = 208, /* [RFC5071] Deprecated */
- SD_DHCP_OPTION_CONFIGURATION_FILE = 209, /* [RFC5071] */
- SD_DHCP_OPTION_PATH_PREFIX = 210, /* [RFC5071] */
- SD_DHCP_OPTION_REBOOT_TIME = 211, /* [RFC5071] */
- SD_DHCP_OPTION_6RD = 212, /* [RFC5969] */
- SD_DHCP_OPTION_ACCESS_DOMAIN = 213, /* [RFC5986] */
- /* option codes 214-219 are unassigned */
- SD_DHCP_OPTION_SUBNET_ALLOCATION = 220, /* [RFC6656] */
- SD_DHCP_OPTION_VIRTUAL_SUBNET_SELECTION = 221, /* [RFC6607] */
- /* option codes 222-223 are unassigned [RFC3942] */
- /* option codes 224-254 are reserved for private use */
- SD_DHCP_OPTION_PRIVATE_BASE = 224,
- SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE = 249, /* [RFC7844] */
- SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY = 252, /* [RFC7844] */
- SD_DHCP_OPTION_PRIVATE_LAST = 254,
- SD_DHCP_OPTION_END = 255, /* [RFC2132] */
-};
-
-/* Suboptions for SD_DHCP_OPTION_RELAY_AGENT_INFORMATION option */
-enum {
- SD_DHCP_RELAY_AGENT_CIRCUIT_ID = 1,
- SD_DHCP_RELAY_AGENT_REMOTE_ID = 2,
-};
-
-typedef struct sd_dhcp_client sd_dhcp_client;
-
-typedef int (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, void *userdata);
-int sd_dhcp_client_set_callback(
- sd_dhcp_client *client,
- sd_dhcp_client_callback_t cb,
- void *userdata);
-
-int sd_dhcp_client_set_request_option(
- sd_dhcp_client *client,
- uint8_t option);
-int sd_dhcp_client_set_request_address(
- sd_dhcp_client *client,
- const struct in_addr *last_address);
-int sd_dhcp_client_set_request_broadcast(
- sd_dhcp_client *client,
- int broadcast);
-int sd_dhcp_client_set_ifindex(
- sd_dhcp_client *client,
- int interface_index);
-int sd_dhcp_client_set_ifname(
- sd_dhcp_client *client,
- const char *interface_name);
-int sd_dhcp_client_get_ifname(sd_dhcp_client *client, const char **ret);
-int sd_dhcp_client_set_mac(
- sd_dhcp_client *client,
- const uint8_t *addr,
- const uint8_t *bcast_addr,
- size_t addr_len,
- uint16_t arp_type);
-int sd_dhcp_client_set_client_id(
- sd_dhcp_client *client,
- uint8_t type,
- const uint8_t *data,
- size_t data_len);
-int sd_dhcp_client_set_iaid_duid(
- sd_dhcp_client *client,
- bool iaid_set,
- uint32_t iaid,
- uint16_t duid_type,
- const void *duid,
- size_t duid_len);
-int sd_dhcp_client_set_iaid_duid_llt(
- sd_dhcp_client *client,
- bool iaid_set,
- uint32_t iaid,
- uint64_t llt_time);
-int sd_dhcp_client_set_duid(
- sd_dhcp_client *client,
- uint16_t duid_type,
- const void *duid,
- size_t duid_len);
-int sd_dhcp_client_set_duid_llt(
- sd_dhcp_client *client,
- uint64_t llt_time);
-int sd_dhcp_client_get_client_id(
- sd_dhcp_client *client,
- uint8_t *type,
- const uint8_t **data,
- size_t *data_len);
-int sd_dhcp_client_set_mtu(
- sd_dhcp_client *client,
- uint32_t mtu);
-int sd_dhcp_client_set_max_attempts(
- sd_dhcp_client *client,
- uint64_t attempt);
-int sd_dhcp_client_set_client_port(
- sd_dhcp_client *client,
- uint16_t port);
-int sd_dhcp_client_set_hostname(
- sd_dhcp_client *client,
- const char *hostname);
-int sd_dhcp_client_set_vendor_class_identifier(
- sd_dhcp_client *client,
- const char *vci);
-int sd_dhcp_client_set_mud_url(
- sd_dhcp_client *client,
- const char *mudurl);
-int sd_dhcp_client_set_user_class(
- sd_dhcp_client *client,
- char * const *user_class);
-int sd_dhcp_client_get_lease(
- sd_dhcp_client *client,
- sd_dhcp_lease **ret);
-int sd_dhcp_client_set_service_type(
- sd_dhcp_client *client,
- int type);
-int sd_dhcp_client_set_fallback_lease_lifetime(
- sd_dhcp_client *client,
- uint32_t fallback_lease_lifetime);
-
-int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v);
-int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v);
-
-int sd_dhcp_client_is_running(sd_dhcp_client *client);
-int sd_dhcp_client_stop(sd_dhcp_client *client);
-int sd_dhcp_client_start(sd_dhcp_client *client);
-int sd_dhcp_client_send_release(sd_dhcp_client *client);
-int sd_dhcp_client_send_decline(sd_dhcp_client *client);
-int sd_dhcp_client_send_renew(sd_dhcp_client *client);
-
-sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client);
-sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client);
-
-/* NOTE: anonymize parameter is used to initialize PRL memory with different
- * options when using RFC7844 Anonymity Profiles */
-int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize);
-
-int sd_dhcp_client_id_to_string(const void *data, size_t len, char **ret);
-
-int sd_dhcp_client_attach_event(
- sd_dhcp_client *client,
- sd_event *event,
- int64_t priority);
-int sd_dhcp_client_detach_event(sd_dhcp_client *client);
-sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client);
-
-_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_client, sd_dhcp_client_unref);
-
-_SD_END_DECLARATIONS;
-
-#endif
diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h b/src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h
deleted file mode 100644
index 578ac6d4db..0000000000
--- a/src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#ifndef foosddhcpleasehfoo
-#define foosddhcpleasehfoo
-
-/***
- Copyright Ā© 2013 Intel Corporation. All rights reserved.
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <inttypes.h>
-#include <net/ethernet.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-
-#include "_sd-common.h"
-
-_SD_BEGIN_DECLARATIONS;
-
-typedef struct sd_dhcp_lease sd_dhcp_lease;
-typedef struct sd_dhcp_route sd_dhcp_route;
-
-sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease);
-sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease);
-
-typedef enum sd_dhcp_lease_server_type_t {
- SD_DHCP_LEASE_DNS,
- SD_DHCP_LEASE_NTP,
- SD_DHCP_LEASE_SIP,
- SD_DHCP_LEASE_POP3,
- SD_DHCP_LEASE_SMTP,
- SD_DHCP_LEASE_LPR,
- _SD_DHCP_LEASE_SERVER_TYPE_MAX,
- _SD_DHCP_LEASE_SERVER_TYPE_INVALID = -EINVAL,
- _SD_ENUM_FORCE_S64(DHCP_LEASE_SERVER_TYPE),
-} sd_dhcp_lease_server_type_t;
-
-int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr);
-int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime);
-int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1);
-int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2);
-int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr);
-int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr);
-int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr);
-int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr);
-int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr);
-int sd_dhcp_lease_get_servers(sd_dhcp_lease *lease, sd_dhcp_lease_server_type_t what, const struct in_addr **addr);
-int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr);
-int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr);
-int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr);
-int sd_dhcp_lease_get_pop3(sd_dhcp_lease *lease, const struct in_addr **addr);
-int sd_dhcp_lease_get_smtp(sd_dhcp_lease *lease, const struct in_addr **addr);
-int sd_dhcp_lease_get_lpr(sd_dhcp_lease *lease, const struct in_addr **addr);
-int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu);
-int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
-int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains);
-int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname);
-int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path);
-int sd_dhcp_lease_get_static_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret);
-int sd_dhcp_lease_get_classless_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret);
-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);
-int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway);
-
-_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_lease, sd_dhcp_lease_unref);
-
-_SD_END_DECLARATIONS;
-
-#endif
diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp-option.h b/src/libnm-systemd-core/src/systemd/sd-dhcp-option.h
deleted file mode 100644
index 71aa479b5e..0000000000
--- a/src/libnm-systemd-core/src/systemd/sd-dhcp-option.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#ifndef foosddhcpoptionhfoo
-#define foosddhcpoptionhfoo
-
-/***
- Copyright Ā© 2013 Intel Corporation. All rights reserved.
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <inttypes.h>
-#include <sys/types.h>
-
-#include "_sd-common.h"
-
-_SD_BEGIN_DECLARATIONS;
-
-typedef struct sd_dhcp_option sd_dhcp_option;
-
-int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret);
-sd_dhcp_option *sd_dhcp_option_ref(sd_dhcp_option *ra);
-sd_dhcp_option *sd_dhcp_option_unref(sd_dhcp_option *ra);
-
-_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_option, sd_dhcp_option_unref);
-
-_SD_END_DECLARATIONS;
-
-#endif
diff --git a/src/libnm-systemd-shared/nm-sd-utils-shared.c b/src/libnm-systemd-shared/nm-sd-utils-shared.c
index 0a35016a40..dad21596cf 100644
--- a/src/libnm-systemd-shared/nm-sd-utils-shared.c
+++ b/src/libnm-systemd-shared/nm-sd-utils-shared.c
@@ -21,58 +21,6 @@ const bool mempool_use_allowed = true;
/*****************************************************************************/
-gboolean
-nm_sd_utils_path_equal(const char *a, const char *b)
-{
- return path_equal(a, b);
-}
-
-char *
-nm_sd_utils_path_simplify(char *path)
-{
- return path_simplify(path);
-}
-
-const char *
-nm_sd_utils_path_startswith(const char *path, const char *prefix)
-{
- return path_startswith(path, prefix);
-}
-
-/*****************************************************************************/
-
-int
-nm_sd_utils_unbase64char(char ch, gboolean accept_padding_equal)
-{
- if (ch == '=' && accept_padding_equal)
- return G_MAXINT;
- return unbase64char(ch);
-}
-
-/**
- * nm_sd_utils_unbase64mem:
- * @p: a valid base64 string. Whitespace is ignored, but invalid encodings
- * will cause the function to fail.
- * @l: the length of @p. @p is not treated as NUL terminated string but
- * merely as a buffer of ascii characters.
- * @secure: whether the temporary memory will be cleared to avoid leaving
- * secrets in memory (see also nm_explicit_bzero()).
- * @mem: (transfer full): the decoded buffer on success.
- * @len: the length of @mem on success.
- *
- * glib provides g_base64_decode(), but that does not report any errors
- * from invalid encodings. Expose systemd's implementation which does
- * reject invalid inputs.
- *
- * Returns: a non-negative code on success. Invalid encoding let the
- * function fail.
- */
-int
-nm_sd_utils_unbase64mem(const char *p, size_t l, gboolean secure, guint8 **mem, size_t *len)
-{
- return unbase64mem_full(p, l, secure, (void **) mem, len);
-}
-
int
nm_sd_dns_name_to_wire_format(const char *domain, guint8 *buffer, size_t len, gboolean canonical)
{
@@ -85,14 +33,6 @@ nm_sd_dns_name_is_valid(const char *s)
return dns_name_is_valid(s);
}
-gboolean
-nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot)
-{
- return hostname_is_valid(s,
- allow_trailing_dot ? VALID_HOSTNAME_TRAILING_DOT
- : (ValidHostnameFlags) 0);
-}
-
char *
nm_sd_dns_name_normalize(const char *s)
{
diff --git a/src/libnm-systemd-shared/nm-sd-utils-shared.h b/src/libnm-systemd-shared/nm-sd-utils-shared.h
index 82a5067863..fefb8a1cdf 100644
--- a/src/libnm-systemd-shared/nm-sd-utils-shared.h
+++ b/src/libnm-systemd-shared/nm-sd-utils-shared.h
@@ -8,25 +8,10 @@
/*****************************************************************************/
-gboolean nm_sd_utils_path_equal(const char *a, const char *b);
-
-char *nm_sd_utils_path_simplify(char *path);
-
-const char *nm_sd_utils_path_startswith(const char *path, const char *prefix);
-
-/*****************************************************************************/
-
-int nm_sd_utils_unbase64char(char ch, gboolean accept_padding_equal);
-
-int nm_sd_utils_unbase64mem(const char *p, size_t l, gboolean secure, guint8 **mem, size_t *len);
-
-/*****************************************************************************/
-
int
nm_sd_dns_name_to_wire_format(const char *domain, guint8 *buffer, size_t len, gboolean canonical);
-int nm_sd_dns_name_is_valid(const char *s);
-gboolean nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot);
+int nm_sd_dns_name_is_valid(const char *s);
char *nm_sd_dns_name_normalize(const char *s);
diff --git a/src/libnmc-base/nm-polkit-listener.c b/src/libnmc-base/nm-polkit-listener.c
index 39a06bc6d4..e7972faa48 100644
--- a/src/libnmc-base/nm-polkit-listener.c
+++ b/src/libnmc-base/nm-polkit-listener.c
@@ -393,7 +393,7 @@ queue_string_to_helper(AuthRequest *request, const char *response)
g_return_if_fail(response);
if (!nm_str_buf_is_initalized(&request->out_buffer))
- nm_str_buf_init(&request->out_buffer, strlen(response) + 2u, TRUE);
+ request->out_buffer = NM_STR_BUF_INIT(strlen(response) + 2u, TRUE);
nm_str_buf_append(&request->out_buffer, response);
nm_str_buf_ensure_trailing_c(&request->out_buffer, '\n');
@@ -587,10 +587,9 @@ create_request(NMPolkitListener *listener,
.cookie = g_strdup(cookie),
.request_any_response = FALSE,
.request_is_completed = FALSE,
+ .in_buffer = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE),
};
- nm_str_buf_init(&request->in_buffer, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE);
-
c_list_link_tail(&listener->request_lst_head, &request->request_lst);
return request;
}
diff --git a/src/n-dhcp4/src/libndhcp4.sym b/src/n-dhcp4/src/libndhcp4.sym
index 4d11734e4d..c6e0dd8672 100644
--- a/src/n-dhcp4/src/libndhcp4.sym
+++ b/src/n-dhcp4/src/libndhcp4.sym
@@ -35,6 +35,7 @@ global:
n_dhcp4_client_lease_unref;
n_dhcp4_client_lease_get_yiaddr;
n_dhcp4_client_lease_get_siaddr;
+ n_dhcp4_client_lease_get_basetime;
n_dhcp4_client_lease_get_lifetime;
n_dhcp4_client_lease_get_server_identifier;
n_dhcp4_client_lease_get_file;
diff --git a/src/n-dhcp4/src/n-dhcp4-c-lease.c b/src/n-dhcp4/src/n-dhcp4-c-lease.c
index bae2f674cd..eaa9627652 100644
--- a/src/n-dhcp4/src/n-dhcp4-c-lease.c
+++ b/src/n-dhcp4/src/n-dhcp4-c-lease.c
@@ -251,7 +251,7 @@ _c_public_ void n_dhcp4_client_lease_get_lifetime(NDhcp4ClientLease *lease, uint
*
* Return: 0 on success,
* N_DHCP4_E_UNSET if the lease doesn't contain a server-identifier, or
- * N_DCHP4_E_INTERNAL if the server-identifier is not valid.
+ * N_DHCP4_E_INTERNAL if the server-identifier is not valid.
*/
_c_public_ int n_dhcp4_client_lease_get_server_identifier(NDhcp4ClientLease *lease, struct in_addr *addr) {
uint8_t *data;
@@ -279,25 +279,25 @@ _c_public_ int n_dhcp4_client_lease_get_server_identifier(NDhcp4ClientLease *lea
*
* Return: 0 on success,
* N_DHCP4_E_UNSET if the lease does not contain a file name, or
- * N_DCHP4_E_INTERNAL if the file name is invalid.
+ * N_DHCP4_E_INTERNAL if the file name is invalid.
*/
_c_public_ int n_dhcp4_client_lease_get_file(NDhcp4ClientLease *lease, const char **file) {
NDhcp4Message *message;
if (lease->message->options[N_DHCP4_OPTION_OVERLOAD].size > 0
&& ((*lease->message->options[N_DHCP4_OPTION_OVERLOAD].value) & N_DHCP4_OVERLOAD_FILE)) {
- /* The field is overloaded to contain other options */
- return N_DHCP4_E_UNSET;
+ /* The field is overloaded to contain other options */
+ return N_DHCP4_E_UNSET;
}
message = &lease->message->message;
if (message->file[0] == '\0')
- return N_DHCP4_E_UNSET;
+ return N_DHCP4_E_UNSET;
if (!memchr(message->file, '\0', sizeof(message->file))) {
- /* The field is NULL-terminated (RFC 2131 section 2) */
- return N_DHCP4_E_INTERNAL;
+ /* The field is NULL-terminated (RFC 2131 section 2) */
+ return N_DHCP4_E_INTERNAL;
}
*file = (const char *) message->file;
@@ -316,7 +316,7 @@ _c_public_ int n_dhcp4_client_lease_get_file(NDhcp4ClientLease *lease, const cha
* be queried, and only options that were explicitly requested can be queried.
*
* Return: 0 on success,
- * N_DCHP4_E_INTERNAL if an invalid option is queried,
+ * N_DHCP4_E_INTERNAL if an invalid option is queried,
* N_DHCP4_E_UNSET if the lease did not contain the option, or
* a negative error code on failure.
*/
diff --git a/src/n-dhcp4/src/test-api.c b/src/n-dhcp4/src/test-api.c
index db3ff935ce..fac3300883 100644
--- a/src/n-dhcp4/src/test-api.c
+++ b/src/n-dhcp4/src/test-api.c
@@ -107,6 +107,7 @@ static void test_api_functions(void) {
(void *)n_dhcp4_client_lease_get_siaddr,
(void *)n_dhcp4_client_lease_get_lifetime,
(void *)n_dhcp4_client_lease_get_server_identifier,
+ (void *)n_dhcp4_client_lease_get_file,
(void *)n_dhcp4_client_lease_query,
(void *)n_dhcp4_client_lease_select,
(void *)n_dhcp4_client_lease_accept,
diff --git a/src/nm-daemon-helper/nm-daemon-helper.c b/src/nm-daemon-helper/nm-daemon-helper.c
index 21a71e3c4a..a101bf9b4f 100644
--- a/src/nm-daemon-helper/nm-daemon-helper.c
+++ b/src/nm-daemon-helper/nm-daemon-helper.c
@@ -2,6 +2,8 @@
/* Copyright (C) 2021 Red Hat, Inc. */
+#include "libnm-std-aux/nm-default-std.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
@@ -10,8 +12,6 @@
#include <nss.h>
#endif
-#include "libnm-std-aux/nm-std-aux.h"
-
enum {
RETURN_SUCCESS = 0,
RETURN_INVALID_CMD = 1,
diff --git a/src/nm-initrd-generator/nmi-cmdline-reader.c b/src/nm-initrd-generator/nmi-cmdline-reader.c
index 412c751067..88760f7574 100644
--- a/src/nm-initrd-generator/nmi-cmdline-reader.c
+++ b/src/nm-initrd-generator/nmi-cmdline-reader.c
@@ -12,7 +12,6 @@
#include "libnm-log-core/nm-logging.h"
#include "libnm-core-intern/nm-core-internal.h"
#include "nm-initrd-generator.h"
-#include "libnm-systemd-shared/nm-sd-utils-shared.h"
/*****************************************************************************/
@@ -586,7 +585,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument)
}
}
- if (client_hostname && !nm_sd_hostname_is_valid(client_hostname, FALSE))
+ if (client_hostname && !nm_hostname_is_valid(client_hostname, FALSE))
client_hostname = NULL;
if (client_hostname) {
diff --git a/src/nm-priv-helper/nm-priv-helper.c b/src/nm-priv-helper/nm-priv-helper.c
index ec064bca2d..e29113b112 100644
--- a/src/nm-priv-helper/nm-priv-helper.c
+++ b/src/nm-priv-helper/nm-priv-helper.c
@@ -9,7 +9,6 @@
#include "libnm-glib-aux/nm-dbus-aux.h"
#include "libnm-glib-aux/nm-io-utils.h"
#include "libnm-glib-aux/nm-logging-base.h"
-#include "libnm-glib-aux/nm-shared-utils.h"
#include "libnm-glib-aux/nm-time-utils.h"
/* nm-priv-helper doesn't link with libnm-core nor libnm-base, but these
diff --git a/src/nmcli/common.c b/src/nmcli/common.c
index f42f76e4c2..710914e211 100644
--- a/src/nmcli/common.c
+++ b/src/nmcli/common.c
@@ -16,6 +16,8 @@
#include <readline/history.h>
#include <readline/readline.h>
#endif
+#include <gio/gunixinputstream.h>
+
#include "libnm-client-aux-extern/nm-libnm-aux.h"
#include "libnmc-base/nm-vpn-helpers.h"
@@ -469,7 +471,8 @@ nmc_find_connection(const GPtrArray *connections,
goto found;
}
- if (NM_IN_STRSET(filter_type, NULL, "filename")) {
+ if (NM_IS_REMOTE_CONNECTION(connections->pdata[i])
+ && NM_IN_STRSET(filter_type, NULL, "filename")) {
v = nm_remote_connection_get_filename(NM_REMOTE_CONNECTION(connections->pdata[i]));
if (complete && (filter_type || *filter_val))
nmc_complete_strings(filter_val, v);
@@ -1273,12 +1276,157 @@ got_client(GObject *source_object, GAsyncResult *res, gpointer user_data)
nm_g_slice_free(call);
}
+typedef struct {
+ GString *str;
+ char buf[512];
+ CmdCall *call;
+} CmdStdinData;
+
+static void read_offline_connection_next(GInputStream *stream, CmdStdinData *data);
+
+static void
+read_offline_connection_chunk(GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GInputStream *stream = G_INPUT_STREAM(source_object);
+ CmdStdinData *data = user_data;
+ CmdCall *call = data->call;
+ gs_unref_object GTask *task = NULL;
+ nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
+ gs_free char *base_dir = NULL;
+ GError *error = NULL;
+ gssize bytes_read;
+ NMConnection *connection;
+ NmCli *nmc;
+
+ bytes_read = g_input_stream_read_finish(stream, res, &error);
+ if (bytes_read > 0) {
+ /* We need to read more. */
+ g_string_append_len(data->str, data->buf, bytes_read);
+ read_offline_connection_next(stream, data);
+ return;
+ }
+
+ /* End reached. */
+
+ task = g_steal_pointer(&call->task);
+ nmc = g_task_get_task_data(task);
+ nmc->should_wait--;
+
+ if (bytes_read == -1) {
+ g_task_return_error(task, error);
+ goto finish;
+ }
+
+ keyfile = g_key_file_new();
+ if (!g_key_file_load_from_data(keyfile,
+ data->str->str,
+ data->str->len,
+ G_KEY_FILE_NONE,
+ &error)) {
+ g_task_return_error(task, error);
+ goto finish;
+ }
+
+ base_dir = g_get_current_dir();
+ connection =
+ nm_keyfile_read(keyfile, base_dir, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
+ if (!connection) {
+ g_task_return_error(task, error);
+ goto finish;
+ }
+
+ g_ptr_array_add(nmc->offline_connections, connection);
+ call->cmd->func(call->cmd, nmc, call->argc, (const char *const *) call->argv);
+ g_task_return_boolean(task, TRUE);
+
+finish:
+ g_strfreev(call->argv);
+ nm_g_slice_free(call);
+ g_string_free(data->str, TRUE);
+ nm_g_slice_free(data);
+}
+
+static void
+read_offline_connection_next(GInputStream *stream, CmdStdinData *data)
+{
+ g_input_stream_read_async(stream,
+ data->buf,
+ sizeof(data->buf),
+ G_PRIORITY_DEFAULT,
+ NULL,
+ read_offline_connection_chunk,
+ data);
+}
+
+static void
+read_offline_connection(CmdCall *call)
+{
+ gs_unref_object GInputStream *stream = NULL;
+ CmdStdinData *data;
+
+ stream = g_unix_input_stream_new(STDIN_FILENO, TRUE);
+ data = g_slice_new(CmdStdinData);
+ data->call = call;
+ data->str = g_string_new_len(NULL, sizeof(data->buf));
+
+ read_offline_connection_next(stream, data);
+}
+
+static NMConnection *
+dummy_offline_connection(void)
+{
+ NMConnection *connection;
+
+ connection = nm_simple_connection_new();
+ nm_connection_add_setting(connection, nm_setting_connection_new());
+ return connection;
+}
+
static void
call_cmd(NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, const char *const *argv)
{
CmdCall *call;
- if (nmc->client || !cmd->needs_client) {
+ if (nmc->offline) {
+ if (!cmd->supports_offline) {
+ g_task_return_new_error(task,
+ NMCLI_ERROR,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: command doesn't support --offline mode."));
+ g_object_unref(task);
+ return;
+ }
+
+ if (!nmc->offline_connections)
+ nmc->offline_connections = g_ptr_array_new_full(1, g_object_unref);
+
+ if (cmd->needs_offline_conn) {
+ g_return_if_fail(nmc->offline_connections->len == 0);
+
+ if (nmc->complete) {
+ g_ptr_array_add(nmc->offline_connections, dummy_offline_connection());
+ cmd->func(cmd, nmc, argc, argv);
+ g_task_return_boolean(task, TRUE);
+ g_object_unref(task);
+ return;
+ }
+
+ nmc->should_wait++;
+ call = g_slice_new(CmdCall);
+ *call = (CmdCall){
+ .cmd = cmd,
+ .argc = argc,
+ .argv = nm_strv_dup(argv, argc, TRUE),
+ .task = task,
+ };
+ read_offline_connection(call);
+ return;
+ } else {
+ cmd->func(cmd, nmc, argc, argv);
+ g_task_return_boolean(task, TRUE);
+ g_object_unref(task);
+ }
+ } else if (nmc->client || !cmd->needs_client) {
/* Check whether NetworkManager is running */
if (cmd->needs_nm_running && !nm_client_get_nm_running(nmc->client)) {
g_task_return_new_error(task,
diff --git a/src/nmcli/connections.c b/src/nmcli/connections.c
index d093823b27..4d9f662bf5 100644
--- a/src/nmcli/connections.c
+++ b/src/nmcli/connections.c
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
- * Copyright (C) 2010 - 2018 Red Hat, Inc.
+ * Copyright (C) 2010 - 2022 Red Hat, Inc.
*/
#include "libnm-client-aux-extern/nm-default-client.h"
@@ -18,6 +18,7 @@
#include <readline/history.h>
#endif
#include <fcntl.h>
+#include <gio/gunixoutputstream.h>
#include "libnm-glib-aux/nm-dbus-aux.h"
#include "libnmc-base/nm-client-utils.h"
@@ -137,6 +138,131 @@ NM_AUTO_DEFINE_FCN(AddConnectionInfo *,
/*****************************************************************************/
+static guint progress_id = 0; /* ID of event source for displaying progress */
+
+static void
+quit(void)
+{
+ if (nm_clear_g_source(&progress_id))
+ nmc_terminal_erase_line();
+ g_main_loop_quit(loop);
+}
+
+typedef struct {
+ char *data;
+ gsize written;
+ gsize length;
+ NmCli *nmc;
+} PrintConnData;
+
+static void print_connection_chunk(GOutputStream *stream, PrintConnData *print_conn_data);
+
+static void
+print_connection_done(GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GOutputStream *stream = G_OUTPUT_STREAM(source_object);
+ PrintConnData *print_conn_data = user_data;
+ NmCli *nmc = print_conn_data->nmc;
+ GError *error = NULL;
+ gssize written;
+
+ written = g_output_stream_write_finish(stream, res, &error);
+ if (written == -1) {
+ g_string_printf(nmc->return_text,
+ _("Error: Error writting connection: %s"),
+ error->message);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ nmc->should_wait--;
+ quit();
+ return;
+ }
+
+ print_conn_data->written += written;
+ if (print_conn_data->written != print_conn_data->length) {
+ g_return_if_fail(written);
+ g_return_if_fail(print_conn_data->written < print_conn_data->length);
+
+ print_connection_chunk(stream, print_conn_data);
+ return;
+ }
+
+ g_free(print_conn_data->data);
+ g_slice_free(PrintConnData, print_conn_data);
+
+ nmc->should_wait--;
+ quit();
+}
+
+static void
+print_connection_chunk(GOutputStream *stream, PrintConnData *print_conn_data)
+{
+ g_output_stream_write_async(stream,
+ print_conn_data->data + print_conn_data->written,
+ print_conn_data->length - print_conn_data->written,
+ G_PRIORITY_DEFAULT,
+ NULL,
+ print_connection_done,
+ print_conn_data);
+}
+
+static void
+nmc_print_connection_and_quit(NmCli *nmc, NMConnection *connection)
+{
+ gs_free_error GError *error = NULL;
+ nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
+ gs_unref_object GOutputStream *stream = NULL;
+ PrintConnData *print_conn_data;
+
+ if (!nm_connection_normalize(connection, NULL, NULL, &error))
+ goto error;
+
+ keyfile = nm_keyfile_write(connection, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
+ if (!keyfile)
+ goto error;
+
+ stream = g_unix_output_stream_new(STDOUT_FILENO, FALSE);
+ print_conn_data = g_slice_new(PrintConnData);
+ print_conn_data->data = g_key_file_to_data(keyfile, &print_conn_data->length, NULL);
+ print_conn_data->written = 0;
+ print_conn_data->nmc = nmc;
+ print_connection_chunk(stream, print_conn_data);
+ return;
+
+error:
+ g_string_printf(nmc->return_text, _("Error: Error writting connection: %s"), error->message);
+ nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ nmc->should_wait--;
+ quit();
+}
+
+static const GPtrArray *
+nmc_get_connections(const NmCli *nmc)
+{
+ if (nmc->offline) {
+ g_return_val_if_fail(!nmc->client, nmc->offline_connections);
+ return nmc->offline_connections;
+ } else {
+ g_return_val_if_fail(nmc->client, NULL);
+ return nm_client_get_connections(nmc->client);
+ }
+}
+
+static const GPtrArray *
+nmc_get_active_connections(const NmCli *nmc)
+{
+ static const GPtrArray offline_active_connections = {.len = 0};
+
+ if (nmc->offline) {
+ g_return_val_if_fail(!nmc->client, &offline_active_connections);
+ return &offline_active_connections;
+ } else {
+ g_return_val_if_fail(nmc->client, &offline_active_connections);
+ return nm_client_get_active_connections(nmc->client);
+ }
+}
+
+/*****************************************************************************/
+
/* Essentially a version of nm_setting_connection_get_connection_type() that
* prefers an alias instead of the settings name when in pretty print mode.
* That is so that we print "wifi" instead of "802-11-wireless" in "nmcli c". */
@@ -942,8 +1068,6 @@ const NmcMetaGenericInfo *const nmc_fields_con_active_details_groups[] = {
#define CON_SHOW_DETAIL_GROUP_PROFILE "profile"
#define CON_SHOW_DETAIL_GROUP_ACTIVE "active"
-static guint progress_id = 0; /* ID of event source for displaying progress */
-
/* for readline TAB completion in editor */
typedef struct {
NmCli *nmc;
@@ -1305,14 +1429,6 @@ usage_connection_migrate(void)
"such as \"keyfile\" (default) or \"ifcfg-rh\".\n\n"));
}
-static void
-quit(void)
-{
- if (nm_clear_g_source(&progress_id))
- nmc_terminal_erase_line();
- g_main_loop_quit(loop);
-}
-
static char *
construct_header_name(const char *base, const char *spec)
{
@@ -1952,7 +2068,7 @@ con_show_get_items(NmCli *nmc, gboolean active_only, gboolean show_active_fields
row_hash = g_hash_table_new(nm_direct_hash, NULL);
- arr = nm_client_get_connections(nmc->client);
+ arr = nmc_get_connections(nmc);
for (i = 0; i < arr->len; i++) {
/* Note: libnm will not expose connection that are invisible
* to the user but currently inactive.
@@ -1971,7 +2087,7 @@ con_show_get_items(NmCli *nmc, gboolean active_only, gboolean show_active_fields
_metagen_con_show_row_data_new_for_connection(c, show_active_fields));
}
- arr = nm_client_get_active_connections(nmc->client);
+ arr = nmc_get_active_connections(nmc);
for (i = 0; i < arr->len; i++) {
NMActiveConnection *ac = arr->pdata[i];
@@ -2119,6 +2235,11 @@ get_connection(NmCli *nmc,
NM_SET_OUT(out_selector, NULL);
NM_SET_OUT(out_value, NULL);
+ if (nmc->offline_connections && nmc->offline_connections->len)
+ return nmc->offline_connections->pdata[0];
+
+ g_return_val_if_fail(!nmc->offline, NULL);
+
if (*argc == 0) {
g_set_error_literal(error,
NMCLI_ERROR,
@@ -2259,7 +2380,7 @@ do_connections_show(const NMCCommand *cmd, NmCli *nmc, int argc, const char *con
} else {
gboolean new_line = FALSE;
gboolean without_fields = (nmc->required_fields == NULL);
- const GPtrArray *active_cons = nm_client_get_active_connections(nmc->client);
+ const GPtrArray *active_cons = nmc_get_active_connections(nmc);
/* multiline mode is default for 'connection show <ID>' */
if (!nmc->mode_specified)
@@ -2315,7 +2436,7 @@ do_connections_show(const NMCCommand *cmd, NmCli *nmc, int argc, const char *con
}
/* Try to find connection by id, uuid or path first */
- connections = nm_client_get_connections(nmc->client);
+ connections = nmc_get_connections(nmc);
con = nmc_find_connection(connections,
selector,
*argv,
@@ -2452,7 +2573,7 @@ get_default_active_connection(NmCli *nmc, NMDevice **device)
g_return_val_if_fail(device, NULL);
g_return_val_if_fail(*device == NULL, NULL);
- connections = nm_client_get_active_connections(nmc->client);
+ connections = nmc_get_active_connections(nmc);
for (i = 0; i < connections->len; i++) {
NMActiveConnection *candidate = g_ptr_array_index(connections, i);
const GPtrArray *devices;
@@ -3276,7 +3397,7 @@ do_connection_down(const NMCCommand *cmd, NmCli *nmc, int argc, const char *cons
}
/* Get active connections */
- active_cons = nm_client_get_active_connections(nmc->client);
+ active_cons = nmc_get_active_connections(nmc);
while (arg_num > 0) {
const char *selector = NULL;
@@ -3926,7 +4047,7 @@ set_default_interface_name(NmCli *nmc, NMSettingConnection *s_con)
const GPtrArray *connections;
gs_free char *ifname = NULL;
- connections = nm_client_get_connections(nmc->client);
+ connections = nmc_get_connections(nmc);
ifname = unique_master_iface_ifname(connections, default_name);
g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, NULL);
}
@@ -4489,7 +4610,7 @@ set_connection_master(NmCli *nmc,
}
slave_type = nm_setting_connection_get_slave_type(s_con);
- connections = nm_client_get_connections(nmc->client);
+ connections = nmc_get_connections(nmc);
value = normalized_master_for_slave(connections, value, slave_type, &slave_type);
if (!set_property(nmc->client,
@@ -5265,12 +5386,9 @@ connection_warnings(NmCli *nmc, NMConnection *connection)
if (deprecated)
g_printerr(_("Warning: %s.\n"), deprecated);
- connections = nm_client_get_connections(nmc->client);
- if (!connections)
- return;
-
- id = nm_connection_get_id(connection);
- found = 0;
+ connections = nmc_get_connections(nmc);
+ id = nm_connection_get_id(connection);
+ found = 0;
for (i = 0; i < connections->len; i++) {
NMConnection *candidate = NM_CONNECTION(connections->pdata[i]);
@@ -5348,15 +5466,6 @@ add_connection(NMClient *client,
user_data);
}
-static void
-update_connection(NMRemoteConnection *connection,
- gboolean temporary,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- nm_remote_connection_commit_changes_async(connection, !temporary, NULL, callback, user_data);
-}
-
static gboolean
is_single_word(const char *line)
{
@@ -5662,6 +5771,20 @@ again:
}
static void
+nmc_add_connection(NmCli *nmc, NMConnection *connection, gboolean temporary)
+{
+ if (nmc->offline) {
+ nmc_print_connection_and_quit(nmc, connection);
+ } else {
+ add_connection(nmc->client,
+ connection,
+ temporary,
+ add_connection_cb,
+ _add_connection_info_new(nmc, NULL, connection));
+ }
+}
+
+static void
do_connection_add(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv)
{
gs_unref_object NMConnection *connection = NULL;
@@ -5748,7 +5871,7 @@ read_properties:
gs_free char *default_name = NULL;
const GPtrArray *connections;
- connections = nm_client_get_connections(nmc->client);
+ connections = nmc_get_connections(nmc);
try_name =
ifname ? g_strdup_printf("%s-%s", get_name_alias_toplevel(type, slave_type), ifname)
: g_strdup(get_name_alias_toplevel(type, slave_type));
@@ -5813,11 +5936,7 @@ read_properties:
}
}
- add_connection(nmc->client,
- connection,
- !save_bool,
- add_connection_cb,
- _add_connection_info_new(nmc, NULL, connection));
+ nmc_add_connection(nmc, connection, !save_bool);
nmc->should_wait++;
finish:
@@ -5839,7 +5958,7 @@ uuid_display_hook(char **array, int len, int max_len)
char *tmp;
const char *id;
for (i = 1; i <= len; i++) {
- connections = nm_client_get_connections(nmc_tab_completion.nmc->client);
+ connections = nmc_get_connections(nmc_tab_completion.nmc);
con = nmc_find_connection(connections, "uuid", array[i], NULL, FALSE);
id = con ? nm_connection_get_id(con) : NULL;
if (id) {
@@ -6173,7 +6292,7 @@ gen_vpn_uuids(const char *text, int state)
const char **uuids;
char *ret;
- connections = nm_client_get_connections(nm_cli_global_readline->client);
+ connections = nmc_get_connections(nm_cli_global_readline);
if (connections->len < 1)
return NULL;
@@ -6190,7 +6309,7 @@ gen_vpn_ids(const char *text, int state)
const char **ids;
char *ret;
- connections = nm_client_get_connections(nm_cli_global_readline->client);
+ connections = nmc_get_connections(nm_cli_global_readline);
if (connections->len < 1)
return NULL;
@@ -8336,7 +8455,11 @@ editor_menu_main(NmCli *nmc, NMConnection *connection, const char *connection_ty
/* Save/update already saved (existing) connection */
nm_connection_replace_settings_from_connection(NM_CONNECTION(rem_con),
connection);
- update_connection(rem_con, temporary, update_connection_editor_cb, NULL);
+ nm_remote_connection_commit_changes_async(rem_con,
+ !temporary,
+ NULL,
+ update_connection_editor_cb,
+ NULL);
handler_id = g_signal_connect(rem_con,
NM_CONNECTION_CHANGED,
@@ -8750,7 +8873,7 @@ do_connection_edit(const NMCCommand *cmd, NmCli *nmc, int argc, const char *cons
/* Use ' ' and '.' as word break characters */
rl_completer_word_break_characters = ". ";
- connections = nm_client_get_connections(nmc->client);
+ connections = nmc_get_connections(nmc);
if (!con) {
if (con_id && !con_uuid && !con_path && !con_filename) {
@@ -8932,10 +9055,23 @@ modify_connection_cb(GObject *connection, GAsyncResult *result, gpointer user_da
}
static void
+nmc_update_connection(NmCli *nmc, NMConnection *connection, gboolean temporary)
+{
+ if (nmc->offline) {
+ nmc_print_connection_and_quit(nmc, connection);
+ } else {
+ nm_remote_connection_commit_changes_async(NM_REMOTE_CONNECTION(connection),
+ !temporary,
+ NULL,
+ modify_connection_cb,
+ nmc);
+ }
+}
+
+static void
do_connection_modify(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv)
{
NMConnection *connection = NULL;
- NMRemoteConnection *rc = NULL;
gs_free_error GError *error = NULL;
gboolean temporary = FALSE;
@@ -8951,25 +9087,19 @@ do_connection_modify(const NMCCommand *cmd, NmCli *nmc, int argc, const char *co
return;
}
- rc = nm_client_get_connection_by_uuid(nmc->client, nm_connection_get_uuid(connection));
- if (!rc) {
- g_string_printf(nmc->return_text,
- _("Error: Unknown connection '%s'."),
- nm_connection_get_uuid(connection));
- nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
- return;
- }
-
- if (!nmc_process_connection_properties(nmc, NM_CONNECTION(rc), &argc, &argv, TRUE, &error)) {
- g_string_assign(nmc->return_text, error->message);
- nmc->return_value = error->code;
- return;
+ /* Don't insist on having argument if we're running in offline mode. */
+ if (!nmc->offline || argc > 0) {
+ if (!nmc_process_connection_properties(nmc, connection, &argc, &argv, TRUE, &error)) {
+ g_string_assign(nmc->return_text, error->message);
+ nmc->return_value = error->code;
+ return;
+ }
}
if (nmc->complete)
return;
- update_connection(rc, temporary, modify_connection_cb, nmc);
+ nmc_update_connection(nmc, connection, temporary);
nmc->should_wait++;
}
@@ -9267,7 +9397,7 @@ do_connection_monitor(const NMCCommand *cmd, NmCli *nmc, int argc, const char *c
/* nmc_do_cmd() should not call this with argc=0. */
g_return_if_fail(!nmc->complete);
- connections = nm_client_get_connections(nmc->client);
+ connections = nmc_get_connections(nmc);
} else {
while (argc > 0) {
if (!get_connection(nmc, &argc, &argv, NULL, NULL, &found_cons, &error)) {
@@ -9768,7 +9898,7 @@ do_connection_migrate(const NMCCommand *cmd, NmCli *nmc, int argc, const char *c
if (!found_cons) {
/* No connections specified explicitly? Fine, add all. */
found_cons = g_ptr_array_new();
- connections = nm_client_get_connections(nmc->client);
+ connections = nmc_get_connections(nmc);
for (i = 0; i < connections->len; i++) {
connection = connections->pdata[i];
g_ptr_array_add(found_cons, connection);
@@ -9815,7 +9945,7 @@ gen_func_connection_names(const char *text, int state)
const char **connection_names;
char *ret;
- connections = nm_client_get_connections(nm_cli_global_readline->client);
+ connections = nmc_get_connections(nm_cli_global_readline);
if (connections->len == 0)
return NULL;
@@ -9841,7 +9971,7 @@ gen_func_active_connection_names(const char *text, int state)
if (!nm_cli_global_readline->client)
return NULL;
- acs = nm_client_get_active_connections(nm_cli_global_readline->client);
+ acs = nmc_get_active_connections(nm_cli_global_readline);
if (!acs || acs->len == 0)
return NULL;
@@ -9905,12 +10035,12 @@ nmc_command_func_connection(const NMCCommand *cmd, NmCli *nmc, int argc, const c
{"show", do_connections_show, usage_connection_show, TRUE, TRUE},
{"up", do_connection_up, usage_connection_up, TRUE, TRUE},
{"down", do_connection_down, usage_connection_down, TRUE, TRUE},
- {"add", do_connection_add, usage_connection_add, TRUE, TRUE},
+ {"add", do_connection_add, usage_connection_add, TRUE, TRUE, TRUE},
{"edit", do_connection_edit, usage_connection_edit, TRUE, TRUE},
{"delete", do_connection_delete, usage_connection_delete, TRUE, TRUE},
{"reload", do_connection_reload, usage_connection_reload, FALSE, FALSE},
{"load", do_connection_load, usage_connection_load, TRUE, TRUE},
- {"modify", do_connection_modify, usage_connection_modify, TRUE, TRUE},
+ {"modify", do_connection_modify, usage_connection_modify, TRUE, TRUE, TRUE, TRUE},
{"clone", do_connection_clone, usage_connection_clone, TRUE, TRUE},
{"import", do_connection_import, usage_connection_import, TRUE, TRUE},
{"export", do_connection_export, usage_connection_export, TRUE, TRUE},
diff --git a/src/nmcli/meson.build b/src/nmcli/meson.build
index fab7329ea0..a122e2af3a 100644
--- a/src/nmcli/meson.build
+++ b/src/nmcli/meson.build
@@ -2,12 +2,10 @@
if enable_nmcli
-# The file is called "nmcli-completion" but should be installed with
-# name "nmcli". Currently it gets renamed by "tools/meson-post-install.sh",
-# but if we depend on meson 0.46.0, we could use "rename" option.
install_data(
'nmcli-completion',
install_dir: join_paths(nm_datadir, 'bash-completion', 'completions'),
+ rename: 'nmcli',
)
executable(
diff --git a/src/nmcli/nmcli.c b/src/nmcli/nmcli.c
index 96b8ec4a13..bc37a7f0f8 100644
--- a/src/nmcli/nmcli.c
+++ b/src/nmcli/nmcli.c
@@ -726,7 +726,7 @@ process_command_line(NmCli *nmc, int argc, char **argv_orig)
{"monitor", nmc_command_func_monitor, NULL, TRUE, FALSE},
{"networking", nmc_command_func_networking, NULL, FALSE, FALSE},
{"radio", nmc_command_func_radio, NULL, FALSE, FALSE},
- {"connection", nmc_command_func_connection, NULL, FALSE, FALSE},
+ {"connection", nmc_command_func_connection, NULL, FALSE, FALSE, TRUE},
{"device", nmc_command_func_device, NULL, FALSE, FALSE},
{"agent", nmc_command_func_agent, NULL, FALSE, FALSE},
{NULL, nmc_command_func_overview, usage, TRUE, TRUE},
@@ -761,15 +761,16 @@ process_command_line(NmCli *nmc, int argc, char **argv_orig)
if (argc == 1 && nmc->complete) {
nmc_complete_strings(argv[0],
+ "--overview",
+ "--offline",
"--terse",
"--pretty",
"--mode",
- "--overview",
"--colors",
"--escape",
"--fields",
- "--nocheck",
"--get-values",
+ "--nocheck",
"--wait",
"--version",
"--help");
@@ -783,6 +784,8 @@ process_command_line(NmCli *nmc, int argc, char **argv_orig)
if (matches_arg(nmc, &argc, &argv, "-overview", NULL)) {
nmc->nmc_config_mutable.overview = TRUE;
+ } else if (matches_arg(nmc, &argc, &argv, "-offline", NULL)) {
+ nmc->offline = TRUE;
} else if (matches_arg(nmc, &argc, &argv, "-terse", NULL)) {
if (nmc->nmc_config.print_output == NMC_PRINT_TERSE) {
g_string_printf(nmc->return_text,
@@ -1011,6 +1014,8 @@ nmc_cleanup(NmCli *nmc)
nm_clear_g_free(&nmc->palette_buffer);
+ nm_clear_pointer(&nmc->offline_connections, g_ptr_array_unref);
+
nmc_polkit_agent_fini(nmc);
}
diff --git a/src/nmcli/nmcli.h b/src/nmcli/nmcli.h
index 157aae9982..922e501418 100644
--- a/src/nmcli/nmcli.h
+++ b/src/nmcli/nmcli.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
- * Copyright (C) 2010 - 2018 Red Hat, Inc.
+ * Copyright (C) 2010 - 2022 Red Hat, Inc.
*/
#ifndef NMC_NMCLI_H
@@ -84,23 +84,26 @@ typedef struct _NmcMetaGenericInfo NmcMetaGenericInfo;
struct _NmcOutputField {
const NMMetaAbstractInfo *info;
- int width; /* Width in screen columns */
- void *value; /* Value of current field - char* or char** (NULL-terminated array) */
- gboolean value_is_array; /* Whether value is char** instead of char* */
- gboolean free_value; /* Whether to free the value */
- NmcOfFlags flags; /* Flags - whether and how to print values/field names/headers */
- NMMetaColor color; /* Use this color to print value */
+
+ int width; /* Width in screen columns */
+ void *value; /* Value of current field - char* or
+ * char** (NULL-terminated array) */
+ bool value_is_array : 1; /* Whether value is char** instead of char* */
+ bool free_value : 1; /* Whether to free the value */
+
+ NmcOfFlags flags; /* Flags - whether and how to print values/field names/headers */
+ NMMetaColor color; /* Use this color to print value */
};
typedef struct _NmcConfig {
- NMCPrintOutput print_output; /* Output mode */
- bool use_colors; /* Whether to use colors for output: option '--color' */
- bool multiline_output; /* Multiline output instead of default tabular */
- bool escape_values; /* Whether to escape ':' and '\' in terse tabular mode */
- bool in_editor; /* Whether running the editor - nmcli con edit' */
- bool
- show_secrets; /* Whether to display secrets (both input and output): option '--show-secrets' */
- bool overview; /* Overview mode (hide default values) */
+ NMCPrintOutput print_output; /* Output mode */
+ bool use_colors; /* Whether to use colors for output: option '--color' */
+ bool multiline_output : 1; /* Multiline output instead of default tabular */
+ bool escape_values : 1; /* Whether to escape ':' and '\' in terse tabular mode */
+ bool in_editor : 1; /* Whether running the editor - nmcli con edit' */
+ bool show_secrets : 1; /* Whether to display secrets (both input
+ * and output): option '--show-secrets' */
+ bool overview : 1; /* Overview mode (hide default values) */
NmcColorPalette palette;
} NmcConfig;
@@ -128,21 +131,27 @@ typedef struct _NmCli {
GHashTable *pwds_hash; /* Hash table with passwords in passwd-file */
struct _NMPolkitListener *pk_listener; /* polkit agent listener */
- int should_wait; /* Semaphore indicating whether nmcli should not end or not yet */
- gboolean nowait_flag; /* '--nowait' option; used for passing to callbacks */
- gboolean mode_specified; /* Whether tabular/multiline mode was specified via '--mode' option */
+ int should_wait; /* Semaphore indicating whether nmcli should not end or not yet */
+
+ bool nowait_flag : 1; /* '--nowait' option; used for passing to callbacks */
+ bool mode_specified : 1; /* Whether tabular/multiline mode was specified via '--mode' option */
+ bool offline : 1; /* Communicate the connection data over stdin/stdout
+ * instead of talking to the daemon. */
+ bool ask : 1; /* Ask for missing parameters: option '--ask' */
+ bool complete : 1; /* Autocomplete the command line */
+ bool editor_status_line : 1; /* Whether to display status line in connection editor */
+ bool editor_save_confirmation : 1; /* Whether to ask for confirmation on
+ * saving connections with 'autoconnect=yes' */
+
union {
const NmcConfig nmc_config;
NmcConfig nmc_config_mutable;
};
- char *required_fields; /* Required fields in output: '--fields' option */
- gboolean ask; /* Ask for missing parameters: option '--ask' */
- gboolean complete; /* Autocomplete the command line */
- gboolean editor_status_line; /* Whether to display status line in connection editor */
- gboolean
- editor_save_confirmation; /* Whether to ask for confirmation on saving connections with 'autoconnect=yes' */
+ char *required_fields; /* Required fields in output: '--fields' option */
char *palette_buffer; /* Buffer with sequences for terminal-colors.d(5)-based coloring. */
+
+ GPtrArray *offline_connections;
} NmCli;
extern const NmCli *const nm_cli_global_readline;
@@ -176,8 +185,15 @@ typedef struct _NMCCommand {
const char *cmd;
void (*func)(const struct _NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv);
void (*usage)(void);
- bool needs_client;
- bool needs_nm_running;
+
+ bool needs_client : 1; /* Ensure a client instance is there before calling
+ * the handler (unless --offline has been given). */
+ bool needs_nm_running : 1; /* Client instance exists *and* the service is
+ * actually present on the bus. */
+ bool supports_offline : 1; /* Run the handler without a client even if the
+ * comand usually requires one if --offline option was used. */
+ bool needs_offline_conn : 1; /* With --online, read in a keyfile from
+ * standard input before dispatching the handler. */
} NMCCommand;
void nmc_command_func_agent(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv);
diff --git a/src/nmtui/nmt-connect-connection-list.c b/src/nmtui/nmt-connect-connection-list.c
index 535cf8fd26..f3197544b5 100644
--- a/src/nmtui/nmt-connect-connection-list.c
+++ b/src/nmtui/nmt-connect-connection-list.c
@@ -101,6 +101,7 @@ static const char *device_sort_order[] = {"NMDeviceEthernet",
NM_SETTING_BRIDGE_SETTING_NAME,
NM_SETTING_IP_TUNNEL_SETTING_NAME,
NM_SETTING_WIREGUARD_SETTING_NAME,
+ NM_SETTING_TUN_SETTING_NAME,
"NMDeviceModem",
"NMDeviceBt"};
static const int device_sort_order_len = G_N_ELEMENTS(device_sort_order);
diff --git a/src/tests/client/test-client.check-on-disk/test_offline.expected b/src/tests/client/test-client.check-on-disk/test_offline.expected
new file mode 100644
index 0000000000..f6f11ba443
--- /dev/null
+++ b/src/tests/client/test-client.check-on-disk/test_offline.expected
@@ -0,0 +1,137 @@
+size: 258
+location: src/tests/client/test-client.py:test_offline()/1
+cmd: $NMCLI g
+lang: C
+returncode: 1
+stderr: 136 bytes
+>>>
+Error: Could not create NMClient object: Key/Value pair 0, 'invalid', in address element 'very:invalid' does not contain an equal sign.
+
+<<<
+size: 319
+location: src/tests/client/test-client.py:test_offline()/2
+cmd: $NMCLI --offline c add type ethernet
+lang: C
+returncode: 0
+stdout: 169 bytes
+>>>
+[connection]
+id=ethernet
+uuid=UUID-WAS-HERE-BUT-IS-NO-MORE-SADLY
+type=ethernet
+
+[ethernet]
+
+[ipv4]
+method=auto
+
+[ipv6]
+addr-gen-mode=stable-privacy
+method=auto
+
+[proxy]
+
+<<<
+size: 183
+location: src/tests/client/test-client.py:test_offline()/3
+cmd: $NMCLI --offline c show
+lang: C
+returncode: 2
+stderr: 47 bytes
+>>>
+Error: command doesn't support --offline mode.
+
+<<<
+size: 178
+location: src/tests/client/test-client.py:test_offline()/4
+cmd: $NMCLI --offline g
+lang: C
+returncode: 2
+stderr: 47 bytes
+>>>
+Error: command doesn't support --offline mode.
+
+<<<
+size: 176
+location: src/tests/client/test-client.py:test_offline()/5
+cmd: $NMCLI --offline
+lang: C
+returncode: 2
+stderr: 47 bytes
+>>>
+Error: command doesn't support --offline mode.
+
+<<<
+size: 443
+location: src/tests/client/test-client.py:test_offline()/6
+cmd: $NMCLI --offline c add type wifi ssid lala 802-1x.eap pwd 802-1x.identity foo 802-1x.password bar
+lang: C
+returncode: 0
+stdout: 232 bytes
+>>>
+[connection]
+id=wifi
+uuid=UUID-WAS-HERE-BUT-IS-NO-MORE-SADLY
+type=wifi
+
+[wifi]
+mode=infrastructure
+ssid=lala
+
+[802-1x]
+eap=pwd;
+identity=foo
+password=bar
+
+[ipv4]
+method=auto
+
+[ipv6]
+addr-gen-mode=stable-privacy
+method=auto
+
+[proxy]
+
+<<<
+size: 481
+location: src/tests/client/test-client.py:test_offline()/7
+cmd: $NMCLI --offline c add type wifi ssid lala 802-1x.eap pwd 802-1x.identity foo 802-1x.password bar 802-1x.password-flags agent-owned
+lang: C
+returncode: 0
+stdout: 236 bytes
+>>>
+[connection]
+id=wifi
+uuid=UUID-WAS-HERE-BUT-IS-NO-MORE-SADLY
+type=wifi
+
+[wifi]
+mode=infrastructure
+ssid=lala
+
+[802-1x]
+eap=pwd;
+identity=foo
+password-flags=1
+
+[ipv4]
+method=auto
+
+[ipv6]
+addr-gen-mode=stable-privacy
+method=auto
+
+[proxy]
+
+<<<
+size: 199
+location: src/tests/client/test-client.py:test_offline()/8
+cmd: $NMCLI --complete-args --offline conn modify ipv6.ad
+lang: C
+returncode: 0
+stdout: 34 bytes
+>>>
+ipv6.addresses
+ipv6.addr-gen-mode
+
+<<<
diff --git a/src/tests/client/test-client.py b/src/tests/client/test-client.py
index d025d12ead..f322a94def 100755
--- a/src/tests/client/test-client.py
+++ b/src/tests/client/test-client.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python
+# coding: utf-8
from __future__ import print_function
@@ -16,7 +17,7 @@ from __future__ import print_function
# When adjusting the tests, or when making changes to nmcli that intentionally
# change the output, the expected output must be regenerated.
#
-# For that, you'd setup your system correctly (see below) and then simply:
+# For that, you'd setup your system correctly (see SETUP below) and then simply:
#
# $ NM_TEST_REGENERATE=1 make check-local-tests-client
# # Or `NM_TEST_REGENERATE=1 make check -j 10`
@@ -24,7 +25,17 @@ from __future__ import print_function
# # The previous step regenerated the expected output. Review the changes
# # and consider whether they are correct. Then commit the changes to git.
#
-# Setup: For regenerating the output, the translations must work. First:
+# With meson, you can do
+# $ meson -Ddocs=true --prefix=/tmp/nm1 build
+# $ ninja -C build
+# $ ninja -C build install
+# $ NM_TEST_REGENERATE=1 ninja -C build test
+#
+# Beware that you need to install the sources, and beware to choose a prefix that doesn't
+# mess up your system (see SETUP below).
+#
+# SETUP: For regenerating the output, the translations must work. First
+# test whether the following works:
#
# 1) LANG=pl_PL.UTF-8 /usr/bin/nmcli --version
# # Ensure that Polish output works for the system-installed nmcli.
@@ -35,6 +46,7 @@ from __future__ import print_function
# # On Debian, you might do:
# # sed -i 's/^# \(pl_PL.UTF-8 .*\)$/\1/p' /etc/locale.gen
# # locale-gen pl_PL.UTF-8
+# # On Fedora, you might install `glibc-langpack-pl` package.
#
# 2) LANG=pl_PL.UTF-8 ./src/nmcli/nmcli --version
# # Ensure that the built nmcli has Polish locale working. If not,
@@ -203,6 +215,13 @@ class Util:
return isinstance(s, t)
@staticmethod
+ def as_bytes(s):
+ if Util.is_string(s):
+ return s.encode("utf-8")
+ assert isinstance(s, bytes)
+ return s
+
+ @staticmethod
def memoize_nullary(nullary_func):
result = []
@@ -335,6 +354,48 @@ class Util:
return None
@staticmethod
+ def _replace_text_match_join(split_arr, replacement):
+ yield split_arr[0]
+ for t in split_arr[1:]:
+ yield (replacement,)
+ yield t
+
+ @staticmethod
+ def ReplaceTextSimple(search, replacement):
+ # This gives a function that can be used by Util.replace_text().
+ # The function replaces an input bytes string @t. It must either return
+ # a bytes string, a list containing bytes strings and/or 1-tuples (the
+ # latter containing one bytes string).
+ # The 1-tuple acts as a placeholder for atomic text, that cannot be replaced
+ # a second time.
+ #
+ # Search for replace_text_fcn in Util.replace_text() where this is called.
+ replacement = Util.as_bytes(replacement)
+
+ if callable(search):
+ search_fcn = search
+ else:
+ search_fcn = lambda: search
+
+ def replace_fcn(t):
+ assert isinstance(t, bytes)
+ search_txt = search_fcn()
+ if search_txt is None:
+ return t
+ search_txt = Util.as_bytes(search_txt)
+ return Util._replace_text_match_join(t.split(search_txt), replacement)
+
+ return replace_fcn
+
+ @staticmethod
+ def ReplaceTextRegex(pattern, replacement):
+ # See ReplaceTextSimple.
+ pattern = Util.as_bytes(pattern)
+ replacement = Util.as_bytes(replacement)
+ p = re.compile(pattern)
+ return lambda t: Util._replace_text_match_join(p.split(t), replacement)
+
+ @staticmethod
def replace_text(text, replace_arr):
if not replace_arr:
return text
@@ -342,27 +403,17 @@ class Util:
if needs_encode:
text = text.encode("utf-8")
text = [text]
- for replace in replace_arr:
- try:
- v_search = replace[0]()
- except TypeError:
- v_search = replace[0]
- assert v_search is None or Util.is_string(v_search)
- if not v_search:
- continue
- v_replace = replace[1]
- v_search = v_search.encode("utf-8")
- v_replace = v_replace.encode("utf-8")
+ for replace_text_fcn in replace_arr:
text2 = []
for t in text:
- if isinstance(t, tuple):
+ # tuples are markers for atomic strings. They won't be replaced a second
+ # time.
+ if not isinstance(t, tuple):
+ t = replace_text_fcn(t)
+ if isinstance(t, bytes) or isinstance(t, tuple):
text2.append(t)
- continue
- t2 = t.split(v_search)
- text2.append(t2[0])
- for t3 in t2[1:]:
- text2.append((v_replace,))
- text2.append(t3)
+ else:
+ text2.extend(t)
text = text2
bb = b"".join([(t[0] if isinstance(t, tuple) else t) for t in text])
if needs_encode:
@@ -657,13 +708,25 @@ class AsyncProcess:
class NmTestBase(unittest.TestCase):
- pass
+ def __init__(self, *args, **kwargs):
+ self._calling_num = {}
+ self._skip_test_for_l10n_diff = []
+ self._async_jobs = []
+ self._results = []
+ self.srv = None
+ return unittest.TestCase.__init__(self, *args, **kwargs)
MAX_JOBS = 15
class TestNmcli(NmTestBase):
+ def ReplaceTextConUuid(self, con_name, replacement):
+ return Util.ReplaceTextSimple(
+ Util.memoize_nullary(lambda: self.srv.findConnectionUuid(con_name)),
+ replacement,
+ )
+
@staticmethod
def _read_expected(filename):
results_expect = []
@@ -837,9 +900,6 @@ class TestNmcli(NmTestBase):
self.fail("invalid language %s" % (lang))
env = {}
- if extra_env is not None:
- for k, v in extra_env.items():
- env[k] = v
for k in ["LD_LIBRARY_PATH", "DBUS_SESSION_BUS_ADDRESS"]:
val = os.environ.get(k, None)
if val is not None:
@@ -856,6 +916,9 @@ class TestNmcli(NmTestBase):
env["NM_TEST_CALLING_NUM"] = str(calling_num)
if fatal_warnings is _DEFAULT_ARG or fatal_warnings:
env["G_DEBUG"] = "fatal-warnings"
+ if extra_env is not None:
+ for k, v in extra_env.items():
+ env[k] = v
args = [conf.get(ENV_NM_TEST_CLIENT_NMCLI_PATH)] + list(args)
@@ -1012,20 +1075,13 @@ class TestNmcli(NmTestBase):
def async_wait(self):
return self.async_start(wait_all=True)
- def _nm_test_pre(self):
- self._calling_num = {}
- self._skip_test_for_l10n_diff = []
- self._async_jobs = []
- self._results = []
-
- self.srv = NMStubServer(self._testMethodName)
-
def _nm_test_post(self):
self.async_wait()
- self.srv.shutdown()
- self.srv = None
+ if self.srv is not None:
+ self.srv.shutdown()
+ self.srv = None
self._calling_num = None
@@ -1130,7 +1186,14 @@ class TestNmcli(NmTestBase):
def nm_test(func):
def f(self):
- self._nm_test_pre()
+ self.srv = NMStubServer(self._testMethodName)
+ func(self)
+ self._nm_test_post()
+
+ return f
+
+ def nm_test_no_dbus(func):
+ def f(self):
func(self)
self._nm_test_post()
@@ -1229,10 +1292,7 @@ class TestNmcli(NmTestBase):
replace_uuids = []
replace_uuids.append(
- (
- Util.memoize_nullary(lambda: self.srv.findConnectionUuid("con-xx1")),
- "UUID-con-xx1-REPLACED-REPLACED-REPLA",
- )
+ self.ReplaceTextConUuid("con-xx1", "UUID-con-xx1-REPLACED-REPLACED-REPLA")
)
self.call_nmcli(
@@ -1245,9 +1305,8 @@ class TestNmcli(NmTestBase):
for con_name, apn in con_gsm_list:
replace_uuids.append(
- (
- Util.memoize_nullary(lambda: self.srv.findConnectionUuid(con_name)),
- "UUID-" + con_name + "-REPLACED-REPLACED-REPL",
+ self.ReplaceTextConUuid(
+ con_name, "UUID-" + con_name + "-REPLACED-REPLACED-REPL"
)
)
@@ -1278,10 +1337,7 @@ class TestNmcli(NmTestBase):
)
replace_uuids.append(
- (
- Util.memoize_nullary(lambda: self.srv.findConnectionUuid("ethernet")),
- "UUID-ethernet-REPLACED-REPLACED-REPL",
- )
+ self.ReplaceTextConUuid("ethernet", "UUID-ethernet-REPLACED-REPLACED-REPL")
)
self.call_nmcli(
@@ -1410,10 +1466,7 @@ class TestNmcli(NmTestBase):
replace_uuids = []
replace_uuids.append(
- (
- Util.memoize_nullary(lambda: self.srv.findConnectionUuid("con-xx1")),
- "UUID-con-xx1-REPLACED-REPLACED-REPLA",
- )
+ self.ReplaceTextConUuid("con-xx1", "UUID-con-xx1-REPLACED-REPLACED-REPLA")
)
self.call_nmcli(
@@ -1459,10 +1512,7 @@ class TestNmcli(NmTestBase):
self.async_wait()
replace_uuids.append(
- (
- Util.memoize_nullary(lambda: self.srv.findConnectionUuid("con-vpn-1")),
- "UUID-con-vpn-1-REPLACED-REPLACED-REP",
- )
+ self.ReplaceTextConUuid("con-vpn-1", "UUID-con-vpn-1-REPLACED-REPLACED-REP")
)
self.call_nmcli(
@@ -1672,6 +1722,104 @@ class TestNmcli(NmTestBase):
replace_cmd=replace_uuids,
)
+ @nm_test_no_dbus
+ def test_offline(self):
+
+ # Make sure we're not using D-Bus
+ no_dbus_env = {
+ "DBUS_SYSTEM_BUS_ADDRESS": "very:invalid",
+ "DBUS_SESSION_BUS_ADDRESS": "very:invalid",
+ }
+
+ # This check just makes sure the above works and the
+ # "nmcli g" command indeed fails talking to D-Bus
+ self.call_nmcli(
+ ["g"],
+ extra_env=no_dbus_env,
+ replace_stderr=[
+ Util.ReplaceTextRegex(
+ # depending on glib version, it prints `%s', '%s', or ā€œ%sā€.
+ # depending on libc version, it converts unicode to ? or *.
+ r"Key/Value pair 0, [`*?']invalid[*?'], in address element [`*?']very:invalid[*?'] does not contain an equal sign",
+ "Key/Value pair 0, 'invalid', in address element 'very:invalid' does not contain an equal sign",
+ )
+ ],
+ )
+
+ replace_uuids = [
+ Util.ReplaceTextRegex(
+ r"\buuid=[-a-f0-9]+\b", "uuid=UUID-WAS-HERE-BUT-IS-NO-MORE-SADLY"
+ )
+ ]
+
+ self.call_nmcli(
+ ["--offline", "c", "add", "type", "ethernet"],
+ extra_env=no_dbus_env,
+ replace_stdout=replace_uuids,
+ )
+
+ self.call_nmcli(
+ ["--offline", "c", "show"],
+ extra_env=no_dbus_env,
+ )
+
+ self.call_nmcli(
+ ["--offline", "g"],
+ extra_env=no_dbus_env,
+ )
+
+ self.call_nmcli(
+ ["--offline"],
+ extra_env=no_dbus_env,
+ )
+
+ self.call_nmcli(
+ [
+ "--offline",
+ "c",
+ "add",
+ "type",
+ "wifi",
+ "ssid",
+ "lala",
+ "802-1x.eap",
+ "pwd",
+ "802-1x.identity",
+ "foo",
+ "802-1x.password",
+ "bar",
+ ],
+ extra_env=no_dbus_env,
+ replace_stdout=replace_uuids,
+ )
+
+ self.call_nmcli(
+ [
+ "--offline",
+ "c",
+ "add",
+ "type",
+ "wifi",
+ "ssid",
+ "lala",
+ "802-1x.eap",
+ "pwd",
+ "802-1x.identity",
+ "foo",
+ "802-1x.password",
+ "bar",
+ "802-1x.password-flags",
+ "agent-owned",
+ ],
+ extra_env=no_dbus_env,
+ replace_stdout=replace_uuids,
+ )
+
+ self.call_nmcli(
+ ["--complete-args", "--offline", "conn", "modify", "ipv6.ad"],
+ extra_env=no_dbus_env,
+ )
+
###############################################################################
diff --git a/tools/meson-post-install.sh b/tools/meson-post-install.sh
index 897a8c5c76..88e30ccfc1 100755
--- a/tools/meson-post-install.sh
+++ b/tools/meson-post-install.sh
@@ -14,11 +14,6 @@ install_systemdunitdir="${11}"
[ -n "$DESTDIR" ] && DESTDIR="${DESTDIR%%/}/"
-if [ -f "${DESTDIR}${nm_datadir}/bash-completion/completions/nmcli-completion" ]; then
- mv "${DESTDIR}${nm_datadir}/bash-completion/completions/nmcli-completion" \
- "${DESTDIR}${nm_datadir}/bash-completion/completions/nmcli"
-fi
-
if [ -x "${DESTDIR}${nm_bindir}/nmtui" ]; then
for alias in nmtui-connect nmtui-edit nmtui-hostname; do
ln -sf nmtui "${DESTDIR}${nm_bindir}/$alias"