From 0018d1f3cf71d680d7b6bceda55a5717244d8b26 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Tue, 16 Aug 2022 18:24:19 +0200 Subject: New upstream version 1.39.90 --- src/c-list/src/c-list.h | 25 + src/c-rbtree/src/c-rbtree.c | 201 +- src/c-rbtree/src/c-rbtree.h | 355 +-- src/c-stdaux/src/c-stdaux.h | 603 +++-- src/core/NetworkManagerUtils.c | 11 +- src/core/devices/bluetooth/nm-device-bt.c | 25 +- src/core/devices/nm-device-bond.c | 209 +- src/core/devices/nm-device-bridge.c | 148 +- src/core/devices/nm-device-veth.c | 15 +- src/core/devices/nm-device-vrf.c | 54 +- src/core/devices/nm-device-wireguard.c | 2 +- src/core/devices/nm-device.c | 582 +++-- src/core/devices/nm-device.h | 19 +- src/core/devices/ovs/nm-device-ovs-bridge.c | 18 +- src/core/devices/ovs/nm-device-ovs-port.c | 120 +- src/core/devices/ovs/nm-ovs-factory.c | 3 +- src/core/devices/ovs/nm-ovsdb.c | 11 +- src/core/devices/team/nm-device-team.c | 170 +- src/core/devices/wifi/nm-device-wifi.c | 30 +- src/core/devices/wifi/tests/test-devices-wifi.c | 34 +- src/core/devices/wwan/nm-modem-ofono.c | 2 +- src/core/dhcp/nm-dhcp-client.c | 745 +++++-- src/core/dhcp/nm-dhcp-client.h | 8 + src/core/dhcp/nm-dhcp-helper.c | 125 +- src/core/dhcp/nm-dhcp-manager.c | 59 +- src/core/dhcp/nm-dhcp-nettools.c | 315 ++- src/core/dhcp/nm-dhcp-systemd.c | 725 +----- src/core/dhcp/nm-dhcp-utils.c | 197 +- src/core/dhcp/nm-dhcp-utils.h | 51 +- src/core/dhcp/tests/test-dhcp-utils.c | 48 +- src/core/dns/nm-dns-dnsmasq.c | 123 +- src/core/dns/nm-dns-manager.c | 202 +- src/core/dns/nm-dns-manager.h | 9 +- src/core/dns/nm-dns-plugin.c | 161 +- src/core/dns/nm-dns-plugin.h | 13 +- src/core/dns/nm-dns-systemd-resolved.c | 425 +++- src/core/dns/nm-dns-unbound.c | 84 - src/core/dns/nm-dns-unbound.h | 27 - src/core/main.c | 22 +- src/core/meson.build | 1 - src/core/nm-config-data.c | 9 +- src/core/nm-config.c | 229 +- src/core/nm-config.h | 11 +- src/core/nm-connectivity.c | 4 +- src/core/nm-core-utils.c | 18 +- src/core/nm-dhcp-config.c | 23 + src/core/nm-dhcp-config.h | 3 +- src/core/nm-dispatcher.c | 78 +- src/core/nm-firewall-utils.c | 3 +- src/core/nm-hostname-manager.c | 132 +- src/core/nm-hostname-manager.h | 10 +- src/core/nm-l3-config-data.c | 48 +- src/core/nm-l3-config-data.h | 4 + src/core/nm-l3-ipv4ll.c | 4 +- src/core/nm-l3-ipv6ll.c | 4 +- src/core/nm-l3cfg.c | 338 ++- src/core/nm-l3cfg.h | 17 +- src/core/nm-manager.c | 150 +- src/core/nm-manager.h | 4 + src/core/nm-netns.c | 48 +- src/core/nm-netns.h | 2 +- src/core/nm-policy.c | 2 +- src/core/platform/nm-fake-platform.c | 9 + src/core/platform/tests/monitor.c | 31 +- src/core/platform/tests/test-common.c | 16 +- src/core/platform/tests/test-common.h | 5 + src/core/platform/tests/test-link.c | 9 +- src/core/platform/tests/test-nmp-object.c | 4 +- src/core/platform/tests/test-platform-general.c | 60 + src/core/platform/tests/test-route.c | 275 ++- src/core/platform/tests/test-tc.c | 9 +- src/core/settings/nm-settings.c | 162 +- .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 93 +- .../settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c | 3 + .../settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h | 2 +- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 37 +- src/core/settings/plugins/ifcfg-rh/shvar.c | 3 + .../ifcfg-System_test-bridge-component-b.cexpected | 2 +- .../network-scripts/ifcfg-Test_User_1.cexpected | 2 +- .../ifcfg-Test_Write_Bond_Main.cexpected | 2 +- .../ifcfg-Test_Write_Permissions.cexpected | 2 +- .../ifcfg-Test_Write_Proxy_Basic.cexpected | 2 +- .../ifcfg-Test_Write_Routing_Rules.cexpected | 3 +- .../ifcfg-Test_Write_VLAN_reorder_hdr.cexpected | 2 +- .../ifcfg-Test_Write_WiFi_AP_Mode.cexpected | 2 +- .../ifcfg-Test_Write_WiFi_Band_A.cexpected | 2 +- .../ifcfg-Test_Write_WiFi_Hidden.cexpected | 2 +- .../ifcfg-Test_Write_WiFi_MAC_always.cexpected | 2 +- .../ifcfg-Test_Write_WiFi_MAC_default.cexpected | 2 +- .../ifcfg-Test_Write_WiFi_MAC_missing.cexpected | 2 +- .../ifcfg-Test_Write_WiFi_MAC_never.cexpected | 2 +- .../ifcfg-Test_Write_Wifi_LEAP.cexpected | 2 +- .../ifcfg-Test_Write_Wifi_WEP_104_ASCII.cexpected | 2 +- ...ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected | 2 +- .../ifcfg-Test_Write_Wired_Static_Routes.cexpected | 1 + .../ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected | 2 +- .../ifcfg-Test_Write_Wired_match.cexpected | 1 + .../tests/network-scripts/ifcfg-dcb-test.cexpected | 2 +- .../ifcfg-random_wifi_connection.cexpected | 1 + .../ifcfg-random_wifi_connection_2.cexpected | 1 + .../ifcfg-test-ip6-disabled.cexpected | 1 + .../tests/network-scripts/ifcfg-test-link_local | 3 + .../ifcfg-test-sriov-write.cexpected | 2 +- .../ifcfg-test-tc-write-empty.cexpected | 2 +- .../network-scripts/ifcfg-test-tc-write.cexpected | 2 +- .../ifcfg-test_roundtrip_ethtool-1.cexpected | 2 +- .../ifcfg-test_roundtrip_ethtool-2.cexpected | 2 +- .../ifcfg-test_roundtrip_ethtool-3.cexpected | 2 +- .../ifcfg-test_roundtrip_ethtool-4.cexpected | 2 +- .../ifcfg-test_roundtrip_ethtool-5.cexpected | 2 +- ...fg-test_write_wired_auto_negotiate_on.cexpected | 2 +- .../network-scripts/route-test-wired-static-routes | 2 +- .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 65 +- .../plugins/ifupdown/nms-ifupdown-parser.c | 2 +- .../settings/plugins/keyfile/nms-keyfile-plugin.c | 10 +- .../plugins/keyfile/tests/test-keyfile-settings.c | 10 +- src/core/supplicant/nm-supplicant-interface.c | 2 +- src/core/tests/config/test-config.c | 6 +- src/core/tests/test-core-with-expect.c | 10 +- src/core/tests/test-core.c | 30 +- src/core/tests/test-l3cfg.c | 2 +- src/core/tests/test-systemd.c | 159 -- src/core/tests/test-utils.c | 4 +- src/libnm-client-impl/libnm.ver | 19 +- src/libnm-client-impl/meson.build | 1 + src/libnm-client-impl/nm-client.c | 16 +- src/libnm-client-impl/nm-conn-utils.c | 593 +++++ src/libnm-client-impl/nm-default-libnm.h | 10 + src/libnm-client-impl/nm-device-macvlan.c | 4 +- src/libnm-client-impl/nm-device-olpc-mesh.c | 3 +- src/libnm-client-impl/nm-device-vxlan.c | 8 +- src/libnm-client-impl/nm-device-wifi-p2p.c | 2 +- src/libnm-client-impl/nm-device-wifi.c | 2 +- src/libnm-client-impl/nm-device-wimax.c | 3 +- src/libnm-client-impl/nm-libnm-utils.h | 4 - src/libnm-client-impl/nm-property-infos-dbus.xml | 2 +- .../nm-property-infos-ifcfg-rh.xml | 6 +- src/libnm-client-impl/nm-property-infos-nmcli.xml | 26 + src/libnm-client-impl/nm-settings-docs-gir.xml | 943 ++++---- src/libnm-client-public/NetworkManager.h | 109 +- src/libnm-client-public/meson.build | 2 +- src/libnm-client-public/nm-access-point.h | 1 + src/libnm-client-public/nm-active-connection.h | 21 +- src/libnm-client-public/nm-checkpoint.h | 1 + src/libnm-client-public/nm-client.h | 3 +- src/libnm-client-public/nm-conn-utils.h | 22 + src/libnm-client-public/nm-device-6lowpan.h | 1 + src/libnm-client-public/nm-device-adsl.h | 1 + src/libnm-client-public/nm-device-bond.h | 1 + src/libnm-client-public/nm-device-bridge.h | 1 + src/libnm-client-public/nm-device-bt.h | 1 + src/libnm-client-public/nm-device-dummy.h | 1 + src/libnm-client-public/nm-device-ethernet.h | 1 + src/libnm-client-public/nm-device-generic.h | 1 + src/libnm-client-public/nm-device-infiniband.h | 1 + src/libnm-client-public/nm-device-ip-tunnel.h | 1 + src/libnm-client-public/nm-device-macsec.h | 1 + src/libnm-client-public/nm-device-macvlan.h | 1 + src/libnm-client-public/nm-device-modem.h | 1 + src/libnm-client-public/nm-device-olpc-mesh.h | 1 + src/libnm-client-public/nm-device-ovs-bridge.h | 1 + src/libnm-client-public/nm-device-ovs-interface.h | 1 + src/libnm-client-public/nm-device-ovs-port.h | 1 + src/libnm-client-public/nm-device-ppp.h | 1 + src/libnm-client-public/nm-device-team.h | 1 + src/libnm-client-public/nm-device-tun.h | 1 + src/libnm-client-public/nm-device-veth.h | 1 + src/libnm-client-public/nm-device-vlan.h | 1 + src/libnm-client-public/nm-device-vrf.h | 1 + src/libnm-client-public/nm-device-vxlan.h | 1 + src/libnm-client-public/nm-device-wifi-p2p.h | 1 + src/libnm-client-public/nm-device-wifi.h | 1 + src/libnm-client-public/nm-device-wimax.h | 1 + src/libnm-client-public/nm-device-wireguard.h | 1 + src/libnm-client-public/nm-device-wpan.h | 1 + src/libnm-client-public/nm-device.h | 1 + src/libnm-client-public/nm-dhcp-config.h | 1 + src/libnm-client-public/nm-enum-types.c.template | 38 +- src/libnm-client-public/nm-ip-config.h | 1 + src/libnm-client-public/nm-object.h | 7 +- src/libnm-client-public/nm-remote-connection.h | 1 + src/libnm-client-public/nm-secret-agent-old.h | 2 - src/libnm-client-public/nm-types.h | 56 - src/libnm-client-public/nm-vpn-connection.h | 1 + src/libnm-client-public/nm-vpn-editor.h | 1 - src/libnm-client-public/nm-vpn-plugin-old.h | 4 +- src/libnm-client-public/nm-vpn-service-plugin.h | 4 +- src/libnm-client-public/nm-wifi-p2p-peer.h | 1 + src/libnm-client-public/nm-wimax-nsp.h | 1 + src/libnm-core-aux-intern/nm-libnm-core-utils.c | 148 ++ src/libnm-core-aux-intern/nm-libnm-core-utils.h | 108 + src/libnm-core-impl/nm-connection.c | 18 +- src/libnm-core-impl/nm-keyfile-utils.c | 6 +- src/libnm-core-impl/nm-keyfile.c | 44 +- src/libnm-core-impl/nm-setting-8021x.c | 4 +- src/libnm-core-impl/nm-setting-bond.c | 42 +- src/libnm-core-impl/nm-setting-bridge.c | 11 +- src/libnm-core-impl/nm-setting-connection.c | 223 +- src/libnm-core-impl/nm-setting-ethtool.c | 4 +- src/libnm-core-impl/nm-setting-ip-config.c | 34 +- src/libnm-core-impl/nm-setting-ip4-config.c | 115 +- src/libnm-core-impl/nm-setting-ip6-config.c | 101 +- src/libnm-core-impl/nm-setting-wireguard.c | 5 +- src/libnm-core-impl/nm-setting-wireless.c | 12 +- src/libnm-core-impl/nm-team-utils.c | 4 +- src/libnm-core-impl/nm-utils.c | 21 +- src/libnm-core-impl/tests/test-general.c | 250 ++- src/libnm-core-impl/tests/test-setting.c | 10 +- src/libnm-core-intern/nm-core-internal.h | 6 +- src/libnm-core-intern/nm-keyfile-utils.h | 4 - src/libnm-core-public/nm-dbus-interface.h | 45 + src/libnm-core-public/nm-dbus-types.xml | 60 + src/libnm-core-public/nm-setting-connection.h | 60 +- src/libnm-core-public/nm-setting-ip-config.h | 4 + src/libnm-core-public/nm-setting-ip4-config.h | 26 + src/libnm-core-public/nm-setting-ip6-config.h | 14 +- src/libnm-core-public/nm-version-macros.h | 5 +- src/libnm-core-public/nm-version-macros.h.in | 1 + src/libnm-core-public/nm-version.h | 16 +- src/libnm-core-public/nm-vpn-dbus-interface.h | 2 +- src/libnm-glib-aux/nm-default-glib.h | 44 +- src/libnm-glib-aux/nm-enum-utils.c | 2 +- src/libnm-glib-aux/nm-errno.c | 1 + src/libnm-glib-aux/nm-errno.h | 1 + src/libnm-glib-aux/nm-glib.h | 27 + src/libnm-glib-aux/nm-hash-utils.h | 24 +- src/libnm-glib-aux/nm-io-utils.c | 285 +++ src/libnm-glib-aux/nm-io-utils.h | 11 + src/libnm-glib-aux/nm-logging-fwd.h | 11 +- src/libnm-glib-aux/nm-macros-internal.h | 20 +- src/libnm-glib-aux/nm-ref-string.h | 2 +- src/libnm-glib-aux/nm-shared-utils.c | 734 +++++- src/libnm-glib-aux/nm-shared-utils.h | 248 ++- src/libnm-glib-aux/nm-str-buf.h | 120 +- src/libnm-glib-aux/nm-test-utils.h | 3 +- src/libnm-glib-aux/nm-uuid.c | 36 +- src/libnm-glib-aux/tests/test-shared-general.c | 844 ++++++- src/libnm-log-core/nm-logging.c | 2 +- src/libnm-platform/meson.build | 2 +- src/libnm-platform/nm-linux-platform.c | 2332 ++++++++++++++------ src/libnm-platform/nm-netlink.c | 654 +++--- src/libnm-platform/nm-netlink.h | 170 +- src/libnm-platform/nm-platform.c | 696 +++++- src/libnm-platform/nm-platform.h | 230 +- src/libnm-platform/nmp-base.h | 3 + src/libnm-platform/nmp-global-tracker.c | 1261 +++++++++++ src/libnm-platform/nmp-global-tracker.h | 84 + src/libnm-platform/nmp-object.c | 204 +- src/libnm-platform/nmp-object.h | 31 +- src/libnm-platform/nmp-route-manager.c | 844 ------- src/libnm-platform/nmp-route-manager.h | 79 - src/libnm-platform/tests/test-nm-platform.c | 5 +- src/libnm-platform/wifi/nm-wifi-utils-nl80211.c | 45 +- src/libnm-platform/wifi/nm-wifi-utils-nl80211.h | 2 +- src/libnm-platform/wifi/nm-wifi-utils.c | 6 +- src/libnm-platform/wifi/nm-wifi-utils.h | 5 +- src/libnm-platform/wpan/nm-wpan-utils.c | 40 +- src/libnm-platform/wpan/nm-wpan-utils.h | 5 +- src/libnm-std-aux/c-list-util.c | 74 + src/libnm-std-aux/c-list-util.h | 15 + src/libnm-std-aux/nm-default-std.h | 97 +- src/libnm-std-aux/nm-linux-compat.h | 2 + src/libnm-std-aux/nm-std-aux.h | 414 ++-- src/libnm-std-aux/nm-std-utils.h | 5 +- src/libnm-systemd-core/meson.build | 8 - src/libnm-systemd-core/nm-sd-utils-dhcp.c | 40 - src/libnm-systemd-core/nm-sd-utils-dhcp.h | 19 - src/libnm-systemd-core/nm-sd.c | 1 - src/libnm-systemd-core/nm-sd.h | 12 - .../src/libsystemd-network/arp-util.c | 142 -- .../src/libsystemd-network/arp-util.h | 36 - .../src/libsystemd-network/dhcp-identifier.c | 58 +- .../src/libsystemd-network/dhcp-identifier.h | 7 +- .../src/libsystemd-network/dhcp-internal.h | 84 - .../src/libsystemd-network/dhcp-lease-internal.h | 90 - .../src/libsystemd-network/dhcp-network.c | 257 --- .../src/libsystemd-network/dhcp-option.c | 443 ---- .../src/libsystemd-network/dhcp-packet.c | 196 -- .../src/libsystemd-network/dhcp-protocol.h | 108 - .../src/libsystemd-network/dhcp6-internal.h | 3 +- .../src/libsystemd-network/dhcp6-option.c | 30 +- .../src/libsystemd-network/lldp-neighbor.c | 6 +- .../src/libsystemd-network/network-internal.c | 243 -- .../src/libsystemd-network/network-internal.h | 31 - .../src/libsystemd-network/sd-dhcp-client.c | 2285 ------------------- .../src/libsystemd-network/sd-dhcp-lease.c | 1508 ------------- .../src/libsystemd-network/sd-dhcp6-client.c | 127 +- .../src/libsystemd-network/sd-dhcp6-lease.c | 40 +- .../src/libsystemd/sd-event/event-util.c | 14 - .../src/libsystemd/sd-event/event-util.h | 5 +- .../src/libsystemd/sd-event/sd-event.c | 164 +- .../src/libsystemd/sd-id128/id128-util.c | 28 +- .../src/libsystemd/sd-id128/id128-util.h | 2 - .../src/libsystemd/sd-id128/sd-id128.c | 26 +- src/libnm-systemd-core/src/systemd/_sd-common.h | 4 +- .../src/systemd/sd-dhcp-client.h | 345 --- src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h | 91 - .../src/systemd/sd-dhcp-option.h | 38 - .../src/systemd/sd-dhcp6-client.h | 17 +- .../src/systemd/sd-dhcp6-lease.h | 2 +- .../src/systemd/sd-dhcp6-option.h | 2 +- src/libnm-systemd-core/src/systemd/sd-event.h | 2 +- src/libnm-systemd-core/src/systemd/sd-id128.h | 6 +- src/libnm-systemd-core/src/systemd/sd-lldp-rx.h | 6 +- src/libnm-systemd-core/src/systemd/sd-lldp.h | 14 +- src/libnm-systemd-core/src/systemd/sd-ndisc.h | 11 +- src/libnm-systemd-shared/meson.build | 3 + src/libnm-systemd-shared/nm-sd-utils-shared.c | 60 - src/libnm-systemd-shared/nm-sd-utils-shared.h | 17 +- .../sd-adapt-shared/locale-util.h | 3 - .../sd-adapt-shared/nm-sd-adapt-shared.h | 4 + src/libnm-systemd-shared/src/basic/alloc-util.h | 38 +- src/libnm-systemd-shared/src/basic/env-util.c | 2 +- .../src/basic/ether-addr-util.c | 9 + .../src/basic/ether-addr-util.h | 2 + src/libnm-systemd-shared/src/basic/fd-util.c | 2 + src/libnm-systemd-shared/src/basic/fileio.c | 31 +- src/libnm-systemd-shared/src/basic/fs-util.c | 21 +- src/libnm-systemd-shared/src/basic/glyph-util.c | 139 ++ src/libnm-systemd-shared/src/basic/glyph-util.h | 60 + src/libnm-systemd-shared/src/basic/hash-funcs.c | 14 +- src/libnm-systemd-shared/src/basic/hash-funcs.h | 8 +- src/libnm-systemd-shared/src/basic/hashmap.c | 45 +- src/libnm-systemd-shared/src/basic/hashmap.h | 7 +- src/libnm-systemd-shared/src/basic/hostname-util.c | 6 +- src/libnm-systemd-shared/src/basic/in-addr-util.c | 54 +- src/libnm-systemd-shared/src/basic/in-addr-util.h | 56 +- src/libnm-systemd-shared/src/basic/list.h | 3 - src/libnm-systemd-shared/src/basic/locale-util.c | 376 ++++ src/libnm-systemd-shared/src/basic/locale-util.h | 56 + src/libnm-systemd-shared/src/basic/log.h | 12 +- src/libnm-systemd-shared/src/basic/macro.h | 60 +- src/libnm-systemd-shared/src/basic/mempool.c | 17 - src/libnm-systemd-shared/src/basic/mempool.h | 3 +- .../src/basic/missing_syscall.h | 2 + src/libnm-systemd-shared/src/basic/ordered-set.h | 4 + src/libnm-systemd-shared/src/basic/parse-util.c | 32 +- src/libnm-systemd-shared/src/basic/parse-util.h | 1 - src/libnm-systemd-shared/src/basic/path-util.c | 124 +- src/libnm-systemd-shared/src/basic/path-util.h | 22 +- src/libnm-systemd-shared/src/basic/process-util.c | 38 +- src/libnm-systemd-shared/src/basic/process-util.h | 2 + src/libnm-systemd-shared/src/basic/random-util.c | 278 +-- src/libnm-systemd-shared/src/basic/random-util.h | 11 +- src/libnm-systemd-shared/src/basic/set.h | 18 +- src/libnm-systemd-shared/src/basic/socket-util.c | 99 +- src/libnm-systemd-shared/src/basic/socket-util.h | 8 +- src/libnm-systemd-shared/src/basic/stat-util.c | 153 +- src/libnm-systemd-shared/src/basic/stat-util.h | 52 +- src/libnm-systemd-shared/src/basic/string-util.c | 27 + src/libnm-systemd-shared/src/basic/string-util.h | 38 +- src/libnm-systemd-shared/src/basic/strv.c | 40 +- src/libnm-systemd-shared/src/basic/strv.h | 43 +- src/libnm-systemd-shared/src/basic/time-util.c | 46 +- .../src/fundamental/macro-fundamental.h | 138 +- src/libnm-systemd-shared/src/fundamental/sha256.c | 293 +++ src/libnm-systemd-shared/src/fundamental/sha256.h | 29 + .../src/fundamental/string-util-fundamental.c | 78 +- .../src/fundamental/string-util-fundamental.h | 70 +- .../src/fundamental/types-fundamental.h | 39 - src/libnm-systemd-shared/src/shared/dns-domain.c | 108 +- src/libnm-systemd-shared/src/shared/dns-domain.h | 6 +- src/libnmc-base/nm-client-utils.c | 4 +- src/libnmc-base/nm-polkit-listener.c | 5 +- src/libnmc-base/nm-vpn-helpers.c | 581 +---- src/libnmc-base/nm-vpn-helpers.h | 2 - src/libnmc-setting/meson.build | 8 +- src/libnmc-setting/nm-meta-setting-desc.c | 162 +- src/libnmc-setting/nm-meta-setting-desc.h | 2 +- src/libnmc-setting/settings-docs-input.xml | 444 +++- src/libnmc-setting/settings-docs.h | 216 +- src/libnmc-setting/settings-docs.h.in | 216 +- src/libnmc-setting/settings-docs.xsl | 49 - src/libnmc-setting/tests/test-libnmc-setting.c | 10 +- src/linux-headers/mptcp.h | 232 ++ src/n-dhcp4/src/n-dhcp4-c-lease.c | 64 +- src/n-dhcp4/src/n-dhcp4-c-probe.c | 52 +- src/n-dhcp4/src/n-dhcp4-client.c | 4 +- src/n-dhcp4/src/n-dhcp4-private.h | 1 + src/nm-cloud-setup/nmcs-provider-aliyun.c | 2 +- src/nm-daemon-helper/nm-daemon-helper.c | 4 +- src/nm-dispatcher/nm-dispatcher.c | 34 +- src/nm-initrd-generator/nm-initrd-generator.c | 176 +- src/nm-initrd-generator/nmi-cmdline-reader.c | 11 +- src/nm-initrd-generator/nmi-dt-reader.c | 4 +- src/nm-initrd-generator/nmi-ibft-reader.c | 2 +- src/nm-online/nm-online.c | 46 +- src/nm-priv-helper/nm-priv-helper.c | 1 - src/nmcli/common.c | 163 +- src/nmcli/connections.c | 475 ++-- src/nmcli/devices.c | 407 +++- src/nmcli/general.c | 5 +- src/nmcli/generate-docs-nm-settings-nmcli.xml | 18 +- src/nmcli/generate-docs-nm-settings-nmcli.xml.in | 18 +- src/nmcli/meson.build | 4 +- src/nmcli/nmcli.c | 11 +- src/nmcli/nmcli.h | 160 +- src/nmtui/nmt-connect-connection-list.c | 23 +- .../test-client.check-on-disk/test_002.expected | 12 +- .../test-client.check-on-disk/test_003.expected | 1064 +++++---- .../test-client.check-on-disk/test_004.expected | 1356 +++++++----- .../test_offline.expected | 137 ++ src/tests/client/test-client.py | 342 ++- 403 files changed, 21045 insertions(+), 16215 deletions(-) delete mode 100644 src/core/dns/nm-dns-unbound.c delete mode 100644 src/core/dns/nm-dns-unbound.h create mode 100644 src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-link_local create mode 100644 src/libnm-client-impl/nm-conn-utils.c create mode 100644 src/libnm-client-public/nm-conn-utils.h delete mode 100644 src/libnm-client-public/nm-types.h create mode 100644 src/libnm-platform/nmp-global-tracker.c create mode 100644 src/libnm-platform/nmp-global-tracker.h delete mode 100644 src/libnm-platform/nmp-route-manager.c delete mode 100644 src/libnm-platform/nmp-route-manager.h delete mode 100644 src/libnm-systemd-core/nm-sd-utils-dhcp.c delete mode 100644 src/libnm-systemd-core/nm-sd-utils-dhcp.h delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/arp-util.c delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/arp-util.h delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/dhcp-protocol.h delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/network-internal.c delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/network-internal.h delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c delete mode 100644 src/libnm-systemd-core/src/systemd/sd-dhcp-client.h delete mode 100644 src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h delete mode 100644 src/libnm-systemd-core/src/systemd/sd-dhcp-option.h delete mode 100644 src/libnm-systemd-shared/sd-adapt-shared/locale-util.h create mode 100644 src/libnm-systemd-shared/src/basic/glyph-util.c create mode 100644 src/libnm-systemd-shared/src/basic/glyph-util.h create mode 100644 src/libnm-systemd-shared/src/basic/locale-util.c create mode 100644 src/libnm-systemd-shared/src/basic/locale-util.h create mode 100644 src/libnm-systemd-shared/src/fundamental/sha256.c create mode 100644 src/libnm-systemd-shared/src/fundamental/sha256.h delete mode 100644 src/libnm-systemd-shared/src/fundamental/types-fundamental.h delete mode 100644 src/libnmc-setting/settings-docs.xsl create mode 100644 src/linux-headers/mptcp.h create mode 100644 src/tests/client/test-client.check-on-disk/test_offline.expected (limited to 'src') diff --git a/src/c-list/src/c-list.h b/src/c-list/src/c-list.h index 69de0b31..711b54d6 100644 --- a/src/c-list/src/c-list.h +++ b/src/c-list/src/c-list.h @@ -259,6 +259,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-rbtree/src/c-rbtree.c b/src/c-rbtree/src/c-rbtree.c index 28de4d95..fbe7c85b 100644 --- a/src/c-rbtree/src/c-rbtree.c +++ b/src/c-rbtree/src/c-rbtree.c @@ -1,5 +1,6 @@ /* * RB-Tree Implementation + * * This implements the insertion/removal of elements in RB-Trees. You're highly * recommended to have an RB-Tree documentation at hand when reading this. Both * insertion and removal can be split into a handful of situations that can @@ -57,12 +58,21 @@ static_assert(alignof(CRBTree) <= C_RBTREE_MAX_ALIGN, "Invalid RBTree alignment" static_assert(alignof(CRBTree) >= 4, "Invalid CRBTree alignment"); /** - * c_rbnode_leftmost() - return leftmost child - * @n: current node, or NULL + * DOC: Traversal + * + * If you prefer open-coding the tree traversal over the built-in iterators, + * c-rbtree provides a set of helpers to find starting position and end nodes + * for different kind of tree traversals. + */ +/**/ + +/** + * c_rbnode_leftmost() - Return leftmost child + * @n: Current node, or NULL * - * This returns the leftmost child of @n. If @n is NULL, this will return NULL. - * In all other cases, this function returns a valid pointer. That is, if @n - * does not have any left children, this returns @n. + * This returns the leftmost child of ``n``. If ``n`` is NULL, this will return + * NULL. In all other cases, this function returns a valid pointer. That is, if + * ``n`` does not have any left children, this returns ``n``. * * Worst case runtime (n: number of elements in tree): O(log(n)) * @@ -76,12 +86,12 @@ _c_public_ CRBNode *c_rbnode_leftmost(CRBNode *n) { } /** - * c_rbnode_rightmost() - return rightmost child - * @n: current node, or NULL + * c_rbnode_rightmost() - Return rightmost child + * @n: Current node, or NULL * - * This returns the rightmost child of @n. If @n is NULL, this will return - * NULL. In all other cases, this function returns a valid pointer. That is, if - * @n does not have any right children, this returns @n. + * This returns the rightmost child of ``n``. If ``n`` is NULL, this will + * return NULL. In all other cases, this function returns a valid pointer. That + * is, if ``n`` does not have any right children, this returns ``n``. * * Worst case runtime (n: number of elements in tree): O(log(n)) * @@ -95,12 +105,12 @@ _c_public_ CRBNode *c_rbnode_rightmost(CRBNode *n) { } /** - * c_rbnode_leftdeepest() - return left-deepest child - * @n: current node, or NULL + * c_rbnode_leftdeepest() - Return left-deepest child + * @n: Current node, or NULL * - * This returns the left-deepest child of @n. If @n is NULL, this will return - * NULL. In all other cases, this function returns a valid pointer. That is, if - * @n does not have any children, this returns @n. + * This returns the left-deepest child of ``n``. If ``n`` is NULL, this will + * return NULL. In all other cases, this function returns a valid pointer. That + * is, if ``n`` does not have any children, this returns ``n``. * * The left-deepest child is defined as the deepest child without any left * (grand-...)siblings. @@ -124,12 +134,12 @@ _c_public_ CRBNode *c_rbnode_leftdeepest(CRBNode *n) { } /** - * c_rbnode_rightdeepest() - return right-deepest child - * @n: current node, or NULL + * c_rbnode_rightdeepest() - Return right-deepest child + * @n: Current node, or NULL * - * This returns the right-deepest child of @n. If @n is NULL, this will return - * NULL. In all other cases, this function returns a valid pointer. That is, if - * @n does not have any children, this returns @n. + * This returns the right-deepest child of ``n``. If ``n`` is NULL, this will + * return NULL. In all other cases, this function returns a valid pointer. That + * is, if ``n`` does not have any children, this returns ``n``. * * The right-deepest child is defined as the deepest child without any right * (grand-...)siblings. @@ -153,11 +163,11 @@ _c_public_ CRBNode *c_rbnode_rightdeepest(CRBNode *n) { } /** - * c_rbnode_next() - return next node - * @n: current node, or NULL + * c_rbnode_next() - Return next node + * @n: Current node, or NULL * * An RB-Tree always defines a linear order of its elements. This function - * returns the logically next node to @n. If @n is NULL, the last node or + * returns the logically next node to ``n``. If ``n`` is NULL, the last node or * unlinked, this returns NULL. * * Worst case runtime (n: number of elements in tree): O(log(n)) @@ -179,12 +189,12 @@ _c_public_ CRBNode *c_rbnode_next(CRBNode *n) { } /** - * c_rbnode_prev() - return previous node - * @n: current node, or NULL + * c_rbnode_prev() - Return previous node + * @n: Current node, or NULL * * An RB-Tree always defines a linear order of its elements. This function - * returns the logically previous node to @n. If @n is NULL, the first node or - * unlinked, this returns NULL. + * returns the logically previous node to ``n``. If ``n`` is NULL, the first + * node or unlinked, this returns NULL. * * Worst case runtime (n: number of elements in tree): O(log(n)) * @@ -205,11 +215,11 @@ _c_public_ CRBNode *c_rbnode_prev(CRBNode *n) { } /** - * c_rbnode_next_postorder() - return next node in post-order - * @n: current node, or NULL + * c_rbnode_next_postorder() - Return next node in post-order + * @n: Current node, or NULL * - * This returns the next node to @n, based on a left-to-right post-order - * traversal. If @n is NULL, the root node, or unlinked, this returns NULL. + * This returns the next node to ``n``, based on a left-to-right post-order + * traversal. If ``n`` is NULL, the root node, or unlinked, this returns NULL. * * This implements a left-to-right post-order traversal: First visit the left * child of a node, then the right, and lastly the node itself. Children are @@ -217,6 +227,8 @@ _c_public_ CRBNode *c_rbnode_prev(CRBNode *n) { * * This function can be used to implement a left-to-right post-order traversal: * + * :: + * * for (n = c_rbtree_first_postorder(t); n; n = c_rbnode_next_postorder(n)) * visit(n); * @@ -238,18 +250,21 @@ _c_public_ CRBNode *c_rbnode_next_postorder(CRBNode *n) { } /** - * c_rbnode_prev_postorder() - return previous node in post-order - * @n: current node, or NULL + * c_rbnode_prev_postorder() - Return previous node in post-order + * @n: Current node, or NULL * - * This returns the previous node to @n, based on a left-to-right post-order - * traversal. That is, it is the inverse operation to c_rbnode_next_postorder(). - * If @n is NULL, the left-deepest node, or unlinked, this returns NULL. + * This returns the previous node to ``n``, based on a left-to-right post-order + * traversal. That is, it is the inverse operation to + * :c:func:`c_rbnode_next_postorder()`. If ``n`` is NULL, the left-deepest + * node, or unlinked, this returns NULL. * * This function returns the logical previous node in a directed post-order * traversal. That is, it effectively does a pre-order traversal (since a * reverse post-order traversal is a pre-order traversal). This function does * NOT do a right-to-left post-order traversal! In other words, the following - * invariant is guaranteed, if c_rbnode_next_postorder(n) is non-NULL: + * invariant is guaranteed, if ``c_rbnode_next_postorder(n)`` is non-NULL: + * + * :: * * n == c_rbnode_prev_postorder(c_rbnode_next_postorder(n)) * @@ -257,6 +272,8 @@ _c_public_ CRBNode *c_rbnode_next_postorder(CRBNode *n) { * using the fact that a reverse post-order traversal is also a valid pre-order * traversal: * + * :: + * * for (n = c_rbtree_last_postorder(t); n; n = c_rbnode_prev_postorder(n)) * visit(n); * @@ -288,11 +305,12 @@ _c_public_ CRBNode *c_rbnode_prev_postorder(CRBNode *n) { } /** - * c_rbtree_first() - return first node - * @t: tree to operate on + * c_rbtree_first() - Return first node + * @t: Tree to operate on * * An RB-Tree always defines a linear order of its elements. This function - * returns the logically first node in @t. If @t is empty, NULL is returned. + * returns the logically first node in ``t``. If ``t`` is empty, NULL is + * returned. * * Fixed runtime (n: number of elements in tree): O(log(n)) * @@ -304,11 +322,12 @@ _c_public_ CRBNode *c_rbtree_first(CRBTree *t) { } /** - * c_rbtree_last() - return last node - * @t: tree to operate on + * c_rbtree_last() - Return last node + * @t: Tree to operate on * * An RB-Tree always defines a linear order of its elements. This function - * returns the logically last node in @t. If @t is empty, NULL is returned. + * returns the logically last node in ``t``. If ``t`` is empty, NULL is + * returned. * * Fixed runtime (n: number of elements in tree): O(log(n)) * @@ -320,8 +339,8 @@ _c_public_ CRBNode *c_rbtree_last(CRBTree *t) { } /** - * c_rbtree_first_postorder() - return first node in post-order - * @t: tree to operate on + * c_rbtree_first_postorder() - Return first node in post-order + * @t: Tree to operate on * * This returns the first node of a left-to-right post-order traversal. That * is, it returns the left-deepest leaf. If the tree is empty, this returns @@ -340,8 +359,8 @@ _c_public_ CRBNode *c_rbtree_first_postorder(CRBTree *t) { } /** - * c_rbtree_last_postorder() - return last node in post-order - * @t: tree to operate on + * c_rbtree_last_postorder() - Return last node in post-order + * @t: Tree to operate on * * This returns the last node of a left-to-right post-order traversal. That is, * it always returns the root node, or NULL if the tree is empty. @@ -358,9 +377,18 @@ _c_public_ CRBNode *c_rbtree_last_postorder(CRBTree *t) { return t->root; } +/** + * DOC: Tree Modification + * + * Insertion into and removal from an RB-Tree require rebalancing to make sure + * the tree stays balanced. The following functions ensure the tree integrity + * is kept. + */ +/**/ + static inline void c_rbtree_store(CRBNode **ptr, CRBNode *addr) { /* - * We use volatile accesses whenever we STORE @left or @right members + * We use volatile accesses whenever we STORE left or right members * of a node. This guarantees that any parallel, lockless lookup gets * to see those stores in the correct order, which itself guarantees * that there're no temporary loops during tree rotation. @@ -437,6 +465,8 @@ static inline CRBTree *c_rbnode_push_root(CRBNode *n, CRBTree *t) { * The sole purpose of this function is to shortcut left/right conditionals * like this: * + * :: + * * if (old == old->parent->left) * old->parent->left = new; * else @@ -457,12 +487,12 @@ static inline void c_rbnode_swap_child(CRBNode *old, CRBNode *new) { } /** - * c_rbtree_move() - move tree - * @to: destination tree - * @from: source tree + * c_rbtree_move() - Move tree + * @to: Destination tree + * @from: Source tree * - * This imports the entire tree from @from into @to. @to must be empty! @from - * will be empty afterwards. + * This imports the entire tree from ``from`` into ``to``. ``to`` must be + * empty! ``from`` will be empty afterwards. * * Note that this operates in O(1) time. Only the root-entry is updated to * point to the new tree-root. @@ -672,21 +702,21 @@ static inline void c_rbtree_paint(CRBNode *n) { } /** - * c_rbnode_link() - link node into tree - * @p: parent node to link under - * @l: left/right slot of @p to link at - * @n: node to add + * c_rbnode_link() - Link node into tree + * @p: Parent node to link under + * @l: Left/right slot of ``p`` to link at + * @n: Node to add * - * This links @n into an tree underneath another node. The caller must provide - * the exact spot where to link the node. That is, the caller must traverse the - * tree based on their search order. Once they hit a leaf where to insert the - * node, call this function to link it and rebalance the tree. + * This links ``n`` into an tree underneath another node. The caller must + * provide the exact spot where to link the node. That is, the caller must + * traverse the tree based on their search order. Once they hit a leaf where to + * insert the node, call this function to link it and rebalance the tree. * * For this to work, the caller must provide a pointer to the parent node. If - * the tree might be empty, you must resort to c_rbtree_add(). + * the tree might be empty, you must resort to :c:func:`c_rbtree_add()`. * - * In most cases you are better off using c_rbtree_add(). See there for details - * how tree-insertion works. + * In most cases you are better off using :c:func:`c_rbtree_add()`. See there + * for details how tree-insertion works. */ _c_public_ void c_rbnode_link(CRBNode *p, CRBNode **l, CRBNode *n) { c_assert(p); @@ -703,18 +733,19 @@ _c_public_ void c_rbnode_link(CRBNode *p, CRBNode **l, CRBNode *n) { } /** - * c_rbtree_add() - add node to tree - * @t: tree to operate one - * @p: parent node to link under, or NULL - * @l: left/right slot of @p (or root) to link at - * @n: node to add - * - * This links @n into the tree given as @t. The caller must provide the exact - * spot where to link the node. That is, the caller must traverse the tree - * based on their search order. Once they hit a leaf where to insert the node, - * call this function to link it and rebalance the tree. + * c_rbtree_add() - Add node to tree + * @t: Tree to operate one + * @p: Parent node to link under, or NULL + * @l: Left/right slot of @p (or root) to link at + * @n: Node to add + * + * This links @n into the tree given as ``t``. The caller must provide the + * exact spot where to link the node. That is, the caller must traverse the + * tree based on their search order. Once they hit a leaf where to insert the + * node, call this function to link it and rebalance the tree. * - * A typical insertion would look like this (@t is your tree, @n is your node): + * A typical insertion would look like this (``t`` is your tree, ``n`` is your + * node):: * * CRBNode **i, *p; * @@ -731,7 +762,7 @@ _c_public_ void c_rbnode_link(CRBNode *p, CRBNode **l, CRBNode *n) { * c_rbtree_add(t, p, i, n); * * Once the node is linked into the tree, a simple lookup on the same tree can - * be coded like this: + * be coded like this:: * * CRBNode *i; * @@ -747,11 +778,13 @@ _c_public_ void c_rbnode_link(CRBNode *p, CRBNode **l, CRBNode *n) { * } * * When you add nodes to a tree, the memory contents of the node do not matter. - * That is, there is no need to initialize the node via c_rbnode_init(). + * That is, there is no need to initialize the node via + * :c:func:`c_rbnode_init()`. * However, if you relink nodes multiple times during their lifetime, it is - * usually very convenient to use c_rbnode_init() and c_rbnode_unlink() (rather - * than c_rbnode_unlink_stale()). In those cases, you should validate that a - * node is unlinked before you call c_rbtree_add(). + * usually very convenient to use :c:func:`c_rbnode_init()` and + * :c:func:`c_rbnode_unlink()` (rather than :c:func:`c_rbnode_unlink_stale()`). + * In those cases, you should validate that a node is unlinked before you call + * :c:func:`c_rbtree_add()`. */ _c_public_ void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n) { c_assert(t); @@ -968,14 +1001,14 @@ static inline void c_rbnode_rebalance(CRBNode *n) { } /** - * c_rbnode_unlink_stale() - remove node from tree - * @n: node to remove + * c_rbnode_unlink_stale() - Remove node from tree + * @n: Node to remove * * This removes the given node from its tree. Once unlinked, the tree is * rebalanced. * - * This does *NOT* reset @n to being unlinked. If you need this, use - * c_rbtree_unlink(). + * This does *NOT* reset ``n`` to being unlinked. If you need this, use + * :c:func:`c_rbtree_unlink()`. */ _c_public_ void c_rbnode_unlink_stale(CRBNode *n) { CRBTree *t; diff --git a/src/c-rbtree/src/c-rbtree.h b/src/c-rbtree/src/c-rbtree.h index d4d0fe45..2d9a1d20 100644 --- a/src/c-rbtree/src/c-rbtree.h +++ b/src/c-rbtree/src/c-rbtree.h @@ -1,31 +1,36 @@ #pragma once -/** - * Standalone Red-Black-Tree Implementation in Standard ISO-C11 - * - * This library provides an RB-Tree API, that is fully implemented in ISO-C11 - * and has no external dependencies. Furthermore, tree traversal, memory - * allocations, and key comparisons are completely controlled by the API user. - * The implementation only provides the RB-Tree specific rebalancing and - * coloring. - * - * A tree is represented by the "CRBTree" structure. It contains a *single* - * field, which is a pointer to the root node. If NULL, the tree is empty. If - * non-NULL, there is at least a single element in the tree. - * - * Each node of the tree is represented by the "CRBNode" structure. It has - * three fields. The @left and @right members can be accessed by the API user - * directly to traverse the tree. The third member is a combination of the - * parent pointer and a set of flags. - * API users are required to embed the CRBNode object into their own objects - * and then use offsetof() (i.e., container_of() and friends) to turn CRBNode - * pointers into pointers to their own structure. +/* + * c-rbtree: Standalone Red-Black-Tree Implementation in Standard ISO-C11 + * + * Main public header of the c-rbtree library. */ #ifdef __cplusplus extern "C" { #endif +/** + * DOC: + * + * The ``c-rbtree.h`` header exposes the full API of the c-rbtree library. It + * provides access to the Red-Black Tree structure as well as helper functions + * to perform standard tree operations. + * + * A tree is represented by the :c:struct:`CRBTree` structure. It contains a + * *single* field, which is a pointer to the root node. If NULL, the tree is + * empty. If non-NULL, there is at least a single element in the tree. + * + * Each node of the tree is represented by the :c:struct:`CRBNode` structure. + * It has three fields. The ``left`` and ``right`` members can be accessed by + * the API user directly to traverse the tree. The third member is a + * combination of the parent pointer and a set of flags. API users are required + * to embed the :c:struct:`CRBNode` object into their own objects and then use + * ``offsetof()`` (i.e., ``container_of()`` and friends) to turn + * :c:struct:`CRBNode` pointers into pointers to their own enclosing type: + */ +/**/ + #include #include #include @@ -38,36 +43,56 @@ typedef struct CRBTree CRBTree; #define C_RBNODE_ROOT (0x2UL) #define C_RBNODE_FLAG_MASK (0x3UL) +/** + * DOC: Tree Structure + * + * The tree structure of c-rbtree is directly exposed in its API. Callers are + * allowed to access the node and tree structures directly to traverse the + * tree. Tree modifications, however, should be performed via the functions + * provided by the library. + */ +/**/ + /** * struct CRBNode - Node of a Red-Black Tree - * @__parent_and_flags: internal state - * @left: left child, or NULL - * @right: right child, or NULL * - * Each node in an RB-Tree must embed a CRBNode object. This object contains - * pointers to its left and right child, which can be freely accessed by the - * API user at any time. They are NULL, if the node does not have a left/right - * child. + * Each node in an RB-Tree must embed a :c:struct:`CRBNode` object. This object + * contains pointers to its left and right child, which can be freely accessed + * by the API user at any time. They are NULL, if the node does not have a + * left/right child. * - * The @__parent_and_flags field must never be accessed directly. It encodes + * The ``__parent_and_flags`` field must never be accessed directly. It encodes * the pointer to the parent node, and the color of the node. Use the accessor * functions instead. * - * There is no reason to initialize a CRBNode object before linking it. - * However, if you need a boolean state that tells you whether the node is - * linked or not, you should initialize the node via c_rbnode_init() or - * C_RBNODE_INIT. + * There is no reason to initialize a :c:struct:`CRBNode` object before linking + * it. However, if you need a boolean state that tells you whether the node is + * linked or not, you should initialize the node via :c:func:`c_rbnode_init()` + * or :c:macro:`C_RBNODE_INIT()`. */ struct CRBNode { + /** Anonymous union for alignment guarantees */ union { + /** Internal state encoding the parent pointer and state */ unsigned long __parent_and_flags; /* enforce >=4-byte alignment for @__parent_and_flags */ alignas(4) unsigned char __align_dummy; }; + /** Left child, or NULL */ CRBNode *left; + /** Right child, or NULL */ CRBNode *right; }; +/** + * C_RBNODE_INIT() - Initialize RBNode Object + * @_var: Backpointer to the variable + * + * Set the contents of the specified node to its unlinked, unused state, ready + * to be linked into a tree. + * + * Return: Evaluates to the initializer for `_var`. + */ #define C_RBNODE_INIT(_var) { .__parent_and_flags = (unsigned long)&(_var) } CRBNode *c_rbnode_leftmost(CRBNode *n); @@ -83,23 +108,31 @@ void c_rbnode_link(CRBNode *p, CRBNode **l, CRBNode *n); void c_rbnode_unlink_stale(CRBNode *n); /** - * struct CRBTree - Red-Black Tree - * @root: pointer to the root node, or NULL + * struct CRBTree - Red-Black Tree Top-Level Structure * * Each Red-Black Tree is rooted in an CRBTree object. This object contains a * pointer to the root node of the tree. The API user is free to access the - * @root member at any time, and use it to traverse the tree. + * ``root`` member at any time, and use it to traverse the tree. * * To initialize an RB-Tree, set it to NULL / all zero. */ struct CRBTree { + /** Anonymous union for alignment guarantees */ union { + /** Pointer to the root node, or NULL */ CRBNode *root; /* enforce >=4-byte alignment for @root */ alignas(4) unsigned char __align_dummy; }; }; +/** + * C_RBTREE_INIT() - Initialize RBTree Object + * + * Set the contents of the specified tree to its pristine, empty state. + * + * Return: Evaluates to the initializer for a :c:struct:`CRBTree` object. + */ #define C_RBTREE_INIT {} CRBNode *c_rbtree_first(CRBTree *t); @@ -111,49 +144,59 @@ void c_rbtree_move(CRBTree *to, CRBTree *from); void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n); /** - * c_rbnode_init() - mark a node as unlinked - * @n: node to operate on + * c_rbnode_init() - Mark a node as unlinked + * @n: Node to operate on * - * This marks the node @n as unlinked. The node will be set to a valid state + * This marks the node ``n`` as unlinked. The node will be set to a valid state * that can never happen if the node is linked in a tree. Furthermore, this * state is fully known to the implementation, and as such handled gracefully * in all cases. * - * You are *NOT* required to call this on your node. c_rbtree_add() can handle - * uninitialized nodes just fine. However, calling this allows to use - * c_rbnode_is_linked() to check for the state of a node. Furthermore, - * iterators and accessors can be called on initialized (yet unlinked) nodes. + * You are *NOT* required to call this on your node. :c:func:`c_rbtree_add()` + * ca handle uninitialized nodes just fine. However, calling this allows to use + * :c:func:`c_rbnode_is_linked()` to check for the state of a node. + * Furthermore, iterators and accessors can be called on initialized (yet + * unlinked) nodes. * - * Use the C_RBNODE_INIT macro if you want to initialize static variables. + * Use the :c:macro:`C_RBNODE_INIT` macro if you want to initialize static + * variables. */ static inline void c_rbnode_init(CRBNode *n) { *n = (CRBNode)C_RBNODE_INIT(*n); } /** - * c_rbnode_entry() - get parent container of tree node - * @_what: tree node, or NULL - * @_t: type of parent container - * @_m: member name of tree node in @_t + * c_rbnode_entry() - Get parent container of tree node + * @_what: Tree node, or NULL + * @_t: Type of parent container + * @_m: Member name of tree node in ``_t`` * - * If the tree node @_what is embedded into a surrounding structure, this will - * turn the tree node pointer @_what into a pointer to the parent container - * (using offsetof(3), or sometimes called container_of(3)). + * If the tree node ``_what`` is embedded into a surrounding structure, this + * will turn the tree node pointer ``_what`` into a pointer to the parent + * container (using ``offsetof(3)``, or sometimes called + * ``container_of(3)``). * - * If @_what is NULL, this will also return NULL. + * If ``_what`` is NULL, this will also return NULL. * * Return: Pointer to parent container, or NULL. */ -#define c_rbnode_entry(_what, _t, _m) \ - ((_t *)(void *)(((unsigned long)(void *)(_what) ?: \ +#define c_rbnode_entry(_what, _t, _m) \ + /* \ + * 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(...))`. \ + */ \ + ((_t *)(void *)(((unsigned long)(void *)(_what) ?: \ offsetof(_t, _m)) - offsetof(_t, _m))) /** - * c_rbnode_parent() - return parent pointer - * @n node to access + * c_rbnode_parent() - Return parent pointer + * @n: Node to access * - * This returns a pointer to the parent of the given node @n. If @n does not - * have a parent, NULL is returned. If @n is not linked, @n itself is returned. + * This returns a pointer to the parent of the given node ``n``. If ``n`` does + * not have a parent, NULL is returned. If ``n`` is not linked, ``n`` itself is + * returned. * * You should not call this on unlinked or uninitialized nodes! If you do, you * better know its semantics. @@ -167,8 +210,8 @@ static inline CRBNode *c_rbnode_parent(CRBNode *n) { } /** - * c_rbnode_is_linked() - check whether a node is linked - * @n: node to check, or NULL + * c_rbnode_is_linked() - Check whether a node is linked + * @n: Node to check, or NULL * * This checks whether the passed node is linked. If you pass NULL, or if the * node is not linked into a tree, this will return false. Otherwise, this @@ -176,9 +219,9 @@ static inline CRBNode *c_rbnode_parent(CRBNode *n) { * * Note that you must have either linked the node or initialized it, before * calling this function. Never call this function on uninitialized nodes. - * Furthermore, removing a node via c_rbnode_unlink_stale() does *NOT* mark the - * node as unlinked. You have to call c_rbnode_init() yourself after removal, or - * use the c_rbnode_unlink() helper. + * Furthermore, removing a node via :c:func:`c_rbnode_unlink_stale()` does *NOT* + * mark the node as unlinked. You have to call :c:func:`c_rbnode_init()` + * yourself after removal, or use :c:func:`c_rbnode_unlink()`. * * Return: true if the node is linked, false if not. */ @@ -187,13 +230,15 @@ static inline _Bool c_rbnode_is_linked(CRBNode *n) { } /** - * c_rbnode_unlink() - safely remove node from tree and reinitialize it - * @n: node to remove, or NULL + * c_rbnode_unlink() - Safely remove node from tree and reinitialize it + * @n: Node to remove, or NULL + * + * This is almost the same as :c:func:`c_rbnode_unlink_stale()`, but extends it + * slightly, to be more convenient to use in many cases: * - * This is almost the same as c_rbnode_unlink_stale(), but extends it slightly, to be - * more convenient to use in many cases: - * - if @n is unlinked or NULL, this is a no-op - * - @n is reinitialized after being removed + * - If ``n`` is unlinked or NULL, this is a no-op. + * + * - ``n`` is reinitialized after being removed. */ static inline void c_rbnode_unlink(CRBNode *n) { if (c_rbnode_is_linked(n)) { @@ -203,20 +248,20 @@ static inline void c_rbnode_unlink(CRBNode *n) { } /** - * c_rbtree_init() - initialize a new RB-Tree - * @t: tree to operate on + * c_rbtree_init() - Initialize a new RB-Tree + * @t: Tree to operate on * * This initializes a new, empty RB-Tree. An RB-Tree must be initialized before * any other functions are called on it. Alternatively, you can zero its memory - * or assign C_RBTREE_INIT. + * or assign :c:macro:`C_RBTREE_INIT`. */ static inline void c_rbtree_init(CRBTree *t) { *t = (CRBTree)C_RBTREE_INIT; } /** - * c_rbtree_is_empty() - check whether an RB-tree is empty - * @t: tree to operate on + * c_rbtree_is_empty() - Check whether an RB-tree is empty + * @t: Tree to operate on * * This checks whether the passed RB-Tree is empty. * @@ -227,35 +272,43 @@ static inline _Bool c_rbtree_is_empty(CRBTree *t) { } /** - * CRBCompareFunc - compare a node to a key - * @t: tree where the node is linked to - * @k: key to compare - * @n: node to compare + * DOC: Search + * + * While the API supports direct traversal via the open-coded structures, it + * can be cumbersome to use at times. If you, instead, provide a callback to + * compare entries in the tree, you can use the following helpers to search the + * tree for specific entries, or slots to insert new entries. + */ +/**/ + +/** + * CRBCompareFunc - Function type to compare a node to a key * * If you use the tree-traversal helpers (which are optional), you need to * provide this callback so they can compare nodes in a tree to the key you * look for. * - * The tree @t is provided as optional context to this callback. The key you - * look for is provided as @k, the current node that should be compared to is - * provided as @n. This function should work like strcmp(), that is, return <0 - * if @key orders before @n, 0 if both compare equal, and >0 if it orders after - * @n. + * The tree is provided as optional context ``t`` to this callback. The key you + * look for is provided as ``k``, the current node that should be compared to + * is provided as ``n``. This function should work like ``strcmp()``, that is, + * return <0 if ``key`` orders before ``n``, 0 if both compare equal, and >0 if + * it orders after ``n``. */ typedef int (*CRBCompareFunc) (CRBTree *t, void *k, CRBNode *n); /** - * c_rbtree_find_node() - find node - * @t: tree to search through - * @f: comparison function - * @k: key to search for - * - * This searches through @t for a node that compares equal to @k. The function - * @f must be provided by the caller, which is used to compare nodes to @k. See - * the documentation of CRBCompareFunc for details. - * - * If there are multiple entries that compare equal to @k, this will return a - * pseudo-randomly picked node. If you need stable lookup functions for trees + * c_rbtree_find_node() - Find node + * @t: Tree to search through + * @f: Comparison function + * @k: Key to search for + * + * This searches through ``t`` for a node that compares equal to ``k``. The + * function ``f`` must be provided by the caller, which is used to compare + * nodes to ``k``. See the documentation of :c:type:`CRBCompareFunc` for + * details. + * + * If there are multiple entries that compare equal to ``k``, this will return + * a pseudo-randomly picked node. If you need stable lookup functions for trees * where duplicate entries are allowed, you better code your own lookup. * * Return: Pointer to matching node, or NULL. @@ -281,19 +334,21 @@ static inline CRBNode *c_rbtree_find_node(CRBTree *t, CRBCompareFunc f, const vo } /** - * c_rbtree_find_entry() - find entry - * @_t: tree to search through - * @_f: comparison function - * @_k: key to search for - * @_s: type of the structure that embeds the nodes - * @_m: name of the node-member in type @_t - * - * This is very similar to c_rbtree_find_node(), but instead of returning a - * pointer to the CRBNode, it returns a pointer to the surrounding object. This - * object must embed the CRBNode object. The type of the surrounding object - * must be given as @_s, and the name of the embedded CRBNode member as @_m. - * - * See c_rbtree_find_node() and c_rbnode_entry() for more details. + * c_rbtree_find_entry() - Find entry + * @_t: Tree to search through + * @_f: Comparison function + * @_k: Key to search for + * @_s: Type of the structure that embeds the nodes + * @_m: Name of the node-member in type @_t + * + * This is very similar to :c:func:`c_rbtree_find_node()`, but instead of + * returning a pointer to the :c:struct:`CRBNode`, it returns a pointer to the + * surrounding object. This object must embed the :c:struct:`CRBNode` object. + * The type of the surrounding object must be given as ``_s``, and the name of + * the embedded :c:struct:`CRBNode` member as ``_m``. + * + * See :c:func:`c_rbtree_find_node()` and :c:macro:`c_rbnode_entry()` for more + * details. * * Return: Pointer to found entry, NULL if not found. */ @@ -301,22 +356,23 @@ static inline CRBNode *c_rbtree_find_node(CRBTree *t, CRBCompareFunc f, const vo c_rbnode_entry(c_rbtree_find_node((_t), (_f), (_k)), _s, _m) /** - * c_rbtree_find_slot() - find slot to insert new node - * @t: tree to search through - * @f: comparison function - * @k: key to search for - * @p: output storage for parent pointer - * - * This searches through @t just like c_rbtree_find_node() does. However, - * instead of returning a pointer to a node that compares equal to @k, this - * searches for a slot to insert a node with key @k. A pointer to the slot is - * returned, and a pointer to the parent of the slot is stored in @p. Both - * can be passed directly to c_rbtree_add(), together with your node to insert. - * - * If there already is a node in the tree, that compares equal to @k, this will - * return NULL and store the conflicting node in @p. In all other cases, - * this will return a pointer (non-NULL) to the empty slot to insert the node - * at. @p will point to the parent node of that slot. + * c_rbtree_find_slot() - Find slot to insert new node + * @t: Tree to search through + * @f: Comparison function + * @k: Key to search for + * @p: Output storage for parent pointer + * + * This searches through ``t`` just like :c:func:`c_rbtree_find_node()` does. + * However, instead of returning a pointer to a node that compares equal to + * ``k``, this searches for a slot to insert a node with key ``k``. A pointer + * to the slot is returned, and a pointer to the parent of the slot is stored + * in ``p``. Both can be passed directly to :c:func:`c_rbtree_add()`, together + * with your node to insert. + * + * If there already is a node in the tree, that compares equal to ``k``, this + * will return NULL and store the conflicting node in ``p``. In all other + * cases, this will return a pointer (non-NULL) to the empty slot to insert the + * node at. ``p`` will point to the parent node of that slot. * * If you want trees that allow duplicate nodes, you better code your own * insertion function. @@ -347,34 +403,35 @@ static inline CRBNode **c_rbtree_find_slot(CRBTree *t, CRBCompareFunc f, const v } /** - * c_rbtree_for_each*() - iterators - * - * The c_rbtree_for_each*() macros provide simple for-loop wrappers to iterate - * an RB-Tree. They come in a set of flavours: - * - * - "entry": This combines c_rbnode_entry() with the loop iterator, so the - * iterator always has the type of the surrounding object, rather - * than CRBNode. - * - * - "safe": The loop iterator always keeps track of the next element to - * visit. This means, you can safely modify the current element, - * while retaining loop-integrity. - * You still must not touch any other entry of the tree. Otherwise, - * the loop-iterator will be corrupted. Also remember to only - * modify the tree in a way compatible with your iterator-order. - * That is, if you use in-order iteration (default), you can unlink - * your current object, including re-balancing the tree. However, - * if you use post-order, you must not trigger a tree rebalance - * operation, since it is not an invariant of post-order iteration. - * - * - "postorder": Rather than the default in-order iteration, this iterates - * the tree in post-order. - * - * - "unlink": This unlinks the current element from the tree before the loop - * code is run. Note that the tree is not rebalanced. That is, - * you must never break out of the loop. If you do so, the tree - * is corrupted. + * DOC: Iterators + * + * The ``c_rbtree_for_each*()`` macros provide simple for-loop wrappers to + * iterate an RB-Tree. They come in a set of flavours: + * + * :entry: This combines :c:macro:`c_rbnode_entry()` with the loop iterator, so + * the iterator always has the type of the surrounding object, rather + * than :c:type:`CRBNode`. + * + * :safe: The loop iterator always keeps track of the next element to + * visit. This means, you can safely modify the current element, + * while retaining loop-integrity. + * You still must not touch any other entry of the tree. Otherwise, + * the loop-iterator will be corrupted. Also remember to only + * modify the tree in a way compatible with your iterator-order. + * That is, if you use in-order iteration (default), you can unlink + * your current object, including re-balancing the tree. However, + * if you use post-order, you must not trigger a tree rebalance + * operation, since it is not an invariant of post-order iteration. + * + * :postorder: Rather than the default in-order iteration, this iterates + * the tree in post-order. + * + * :unlink: This unlinks the current element from the tree before the loop + * code is run. Note that the tree is not rebalanced. That is, + * you must never break out of the loop. If you do so, the tree + * is corrupted. */ +/**/ #define c_rbtree_for_each(_iter, _tree) \ for (_iter = c_rbtree_first(_tree); \ diff --git a/src/c-stdaux/src/c-stdaux.h b/src/c-stdaux/src/c-stdaux.h index 1cdbbbcf..80db7f9a 100644 --- a/src/c-stdaux/src/c-stdaux.h +++ b/src/c-stdaux/src/c-stdaux.h @@ -1,12 +1,23 @@ #pragma once /* - * Auxiliary macros and functions for the C standard library + * c-stdaux: Auxiliary macros and functions for the C standard library * - * The `c-stdaux.h` header contains a collection of auxiliary macros and helper - * functions around the functionality provided by the different C standard - * library implementations, as well as other specifications implemented by - * them. + * Main public header of the c-stdaux library. All includes of this header are + * part of the API! + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * DOC: + * + * The ``c-stdaux.h`` header contains a collection of auxiliary macros and + * helper functions around the functionality provided by the different C + * standard library implementations, as well as other specifications + * implemented by them. * * Most of the helpers provided here provide aliases for common library and * compiler features. Furthermore, several helpers simply provide other calling @@ -16,17 +27,27 @@ * * The namespace used by this project is: * - * * `c_*` for all common C symbols or definitions that behave like proper C + * - ``c_*`` for all common C symbols or definitions that behave like proper C * entities (e.g., macros that protect against double-evaluation would use - * lower-case names) + * lower-case names). * - * * `C_*` for all constants, as well as macros that may not be safe against + * - ``C_*`` for all constants, as well as macros that may not be safe against * double evaluation. + * + * - ``c_internal_*`` and ``C_INTERNAL_*`` for all internal symbols that + * should not be invoked by the caller and are not part of the API + * guarantees. */ +/**/ -#ifdef __cplusplus -extern "C" { -#endif +/** + * DOC: Guaranteed Includes + * + * The ``c-stdaux.h`` header includes a set of C Standard Library headers as + * well as UNIX headers. All those includes are guaranteed and part of the API. + * See the actual header for a comprehensive list. + */ +/**/ #include #include @@ -36,9 +57,6 @@ extern "C" { #include #include #include -#if 0 /* NM_IGNORED */ -#include -#endif /* NM_IGNORED */ #include #include #include @@ -50,44 +68,152 @@ extern "C" { #include #include -/* - * Shortcuts for gcc attributes. See GCC manual for details. They're 1-to-1 - * mappings to the GCC equivalents. No additional magic here. They are - * supported by other compilers as well. +/** + * DOC: Compiler Attributes + * + * The GCC compiler uses the ``__attribute__((__xyz__()))`` syntax to annotate + * language entities with special attributes. Aliases are provided by this + * header which map one-to-one to the respective compiler attributes. + * + * These attributes are not supported by all compilers, but are always provided + * by this header. They are pre-processor macros and do not affect the + * compilation, unless used. Note that most compilers support these, not just + * GCC. + */ +/**/ + +/** + * _c_cleanup_() - Cleanup attribute + * @_x: Cleanup function to use + * + * Alias for ``__attribute__((__cleanup__(_x)))``. */ #define _c_cleanup_(_x) __attribute__((__cleanup__(_x))) + +/** + * _c_const_() - Const attribute + * + * Alias for ``__attribute__((__const__))``. + */ #define _c_const_ __attribute__((__const__)) + +/** + * _c_deprecated_() - Deprecated attribute + * + * Alias for ``__attribute__((__deprecated__))``. + */ #define _c_deprecated_ __attribute__((__deprecated__)) + +/** + * _c_hidden_() - Hidden attribute + * + * Alias for ``__attribute__((__visibility__("hidden")))``. + */ #define _c_hidden_ __attribute__((__visibility__("hidden"))) -#define _c_likely_(_x) (__builtin_expect(!!(_x), 1)) + +/** + * _c_packed_() - Packed attribute + * + * Alias for ``__attribute__((__packed__))``. + */ #define _c_packed_ __attribute__((__packed__)) + +/** + * _c_printf_() - Printf attribute + * @_a: Format expression argument index + * @_b: First format-parameter argument index + * + * Alias for ``__attribute__((__format__(printf, _a, _b)))``. + */ #define _c_printf_(_a, _b) __attribute__((__format__(printf, _a, _b))) + +/** + * _c_public_() - Public attribute + * + * Alias for ``__attribute__((__visibility__("default")))``. + */ #define _c_public_ __attribute__((__visibility__("default"))) + +/** + * _c_pure_() - Pure attribute + * + * Alias for ``__attribute__((__pure__))``. + */ #define _c_pure_ __attribute__((__pure__)) + +/** + * _c_sentinel_() - Sentinel attribute + * + * Alias for ``__attribute__((__sentinel__))``. + */ #define _c_sentinel_ __attribute__((__sentinel__)) -#define _c_unlikely_(_x) (__builtin_expect(!!(_x), 0)) + +/** + * _c_unused_() - Unused attribute + * + * Alias for ``__attribute__((__unused__))``. + */ #define _c_unused_ __attribute__((__unused__)) /** - * C_EXPR_ASSERT() - create expression with assertion - * @_expr: expression to evaluate to - * @_assertion: arbitrary assertion - * @_message: message associated with the assertion + * DOC: Compiler Intrinsics + * + * Aliases for common compiler extensions and intrinsics are provided similar + * to the compiler attributes. They are pure preprocessor aliases and do not + * affect compilation unless used. + */ +/**/ + +/** + * _c_likely_() - Likely attribute + * @_x: Expression to evaluate * - * This macro simply evaluates to @_expr. That is, it can be used in any - * context that expects an expression like @_expr. Additionally, it takes an - * assertion as @_assertion and evaluates it through _Static_assert(), using - * @_message as debug message. + * Alias for ``__builtin_expect(!!(_x), 1)``. * - * The _Static_assert() builtin of C11 is defined as statement and thus cannot - * be used in expressions. This macro circumvents this restriction. + * Return: The expression ``_x`` is evaluated and returned. + */ +#define _c_likely_(_x) (__builtin_expect(!!(_x), 1)) + +/** + * _c_unlikely_() - Unlikely attribute + * @_x: Expression to evaluate * - * Return: Evaluates to @_expr. + * Alias for ``__builtin_expect(!!(_x), 0)``. + * + * Return: The expression ``_x`` is evaluated and returned. */ +#define _c_unlikely_(_x) (__builtin_expect(!!(_x), 0)) + +/** + * DOC: Utility Macros + * + * A set of utility macros is provided which aids in creating safe macros + * suitable for use in other pre-processor statements as well as in C + * expressions. + */ +/**/ + +/** + * C_EXPR_ASSERT() - Create expression with assertion + * @_expr: Expression to evaluate to + * @_assertion: Arbitrary assertion + * @_message: Message associated with the assertion + * + * This macro simply evaluates to ``_expr``. That is, it can be used in any + * context that expects an expression like ``_expr``. Additionally, it takes an + * assertion as ``_assertion`` and evaluates it through ``_Static_assert()``, + * using ``_message`` as debug message. + * + * The ``_Static_assert()`` builtin of C11 is defined as statement and thus + * cannot be used in expressions. This macro circumvents this restriction. + * + * Return: Evaluates to ``_expr``. + */ +#define C_EXPR_ASSERT(_expr, _assertion, _message) C_INTERNAL_EXPR_ASSERT((_expr), (_assertion), _message) #if defined(__COVERITY__) // Coverity cannot const-fold __builtin_choose_expr() -# define C_EXPR_ASSERT(_expr, _assertion, _message) (_expr) +# define C_INTERNAL_EXPR_ASSERT(_expr, _assertion, _message) (_expr) #else -# define C_EXPR_ASSERT(_expr, _assertion, _message) \ +# define C_INTERNAL_EXPR_ASSERT(_expr, _assertion, _message) \ /* indentation and line-split to get better diagnostics */ \ (__builtin_choose_expr( \ !!(1 + 0 * sizeof( \ @@ -101,8 +227,8 @@ _Static_assert(_assertion, _message); \ #endif /** - * C_STRINGIFY() - stringify a token, but evaluate it first - * @_x: token to evaluate and stringify + * C_STRINGIFY() - Stringify a token, but evaluate it first + * @_x: Token to evaluate and stringify * * Return: Evaluates to a constant string literal */ @@ -110,9 +236,9 @@ _Static_assert(_assertion, _message); \ #define C_INTERNAL_STRINGIFY(_x) #_x /** - * C_CONCATENATE() - concatenate two tokens, but evaluate them first - * @_x: first token - * @_y: second token + * C_CONCATENATE() - Concatenate two tokens, but evaluate them first + * @_x: First token + * @_y: Second token * * Return: Evaluates to a constant identifier */ @@ -120,8 +246,8 @@ _Static_assert(_assertion, _message); \ #define C_INTERNAL_CONCATENATE(_x, _y) _x ## _y /** - * C_EXPAND() - expand a tuple to a series of its values - * @_x: tuple to expand + * C_EXPAND() - Expand a tuple to a series of its values + * @_x: Tuple to expand * * Return: Evaluates to the expanded tuple */ @@ -129,29 +255,32 @@ _Static_assert(_assertion, _message); \ #define C_INTERNAL_EXPAND(...) __VA_ARGS__ /** - * C_VAR() - generate unique variable name - * @_x: name of variable, optional - * @_uniq: unique prefix, usually provided by __COUNTER__, optional + * C_VAR() - Generate unique variable name + * @_x: Name of variable, optional + * @_uniq: Unique prefix, usually provided by ``__COUNTER__``, optional * * This macro shall be used to generate unique variable names, that will not be * shadowed by recursive macro invocations. It is effectively a - * C_CONCATENATE of both arguments, but also provides a globally separated - * prefix and makes the code better readable. + * :c:macro:`C_CONCATENATE` of both arguments, but also provides a globally + * separated prefix and makes the code better readable. * - * The second argument is optional. If not given, __LINE__ is implied, and as - * such the macro will generate the same identifier if used multiple times on - * the same code-line (or within a macro). This should be used if recursive + * The second argument is optional. If not given, ``__LINE__`` is implied, and + * as such the macro will generate the same identifier if used multiple times + * on the same code-line (or within a macro). This should be used if recursive * calls into the macro are not expected. In fact, no argument is necessary in - * this case, as a mere `C_VAR` will evaluate to a valid variable name. + * this case, as a mere ``C_VAR`` will evaluate to a valid variable name. * * This helper may be used by macro implementations that might reasonable well * be called in a stacked fasion, like: * + * .. code-block:: c + * * c_max(foo, c_max(bar, baz)) * - * Such a stacked call of c_max() might cause compiler warnings of shadowed - * variables in the definition of c_max(). By using C_VAR(), such warnings - * can be silenced as each evaluation of c_max() uses unique variable names. + * Such a stacked call of :c:macro:`c_max()` might cause compiler warnings of + * shadowed variables in the definition of :c:macro:`c_max()`. By using + * ``C_VAR()``, such warnings can be silenced as each evaluation of + * :c:macro:`c_max()` uses unique variable names. * * Return: This evaluates to a constant identifier. */ @@ -161,28 +290,28 @@ _Static_assert(_assertion, _message); \ #define C_VAR2(_x, _uniq) C_CONCATENATE(c_internal_var_unique_, C_CONCATENATE(_uniq, _x)) /** - * C_CC_MACRO1() - provide safe environment to a macro - * @_call: macro to call - * @_x1: first argument - * @...: further arguments to forward unmodified to @_call + * C_CC_MACRO1() - Provide safe environment to a macro + * @_call: Macro to call + * @_x1: First argument + * @...: Further arguments to forward unmodified to ``_call`` * * This function simplifies the implementation of macros. Whenever you - * implement a macro, provide the internal macro name as @_call and its - * argument as @_x1. Inside of your internal macro, you... + * implement a macro, provide the internal macro name as ``_call`` and its + * argument as ``_x1``. Inside of your internal macro, you... * - * - ...are safe against multiple evaluation errors, since C_CC_MACRO1 will - * store the initial parameters in temporary variables. + * - are safe against multiple evaluation errors, since ``C_CC_MACRO1`` + * will store the initial parameters in temporary variables. * - * - ...support constant folding, as C_CC_MACRO1 takes care to invoke your - * macro with the original values, if they are compile-time constant. + * - support constant folding, as ``C_CC_MACRO1`` takes care to invoke your + * macro with the original values, if they are compile-time constant. * - * - ...have unique variable names for recursive callers and will not run into - * variable-shadowing-warnings accidentally. + * - have unique variable names for recursive callers and will not run into + * variable-shadowing-warnings accidentally. * - * - ...have properly typed arguments as C_CC_MACRO1 stores the original - * arguments in an `__auto_type` temporary variable. + * - have properly typed arguments as ``C_CC_MACRO1`` stores the original + * arguments in an ``__auto_type`` temporary variable. * - * Return: Result of @_call is returned. + * Return: Result of ``_call`` is returned. */ #define C_CC_MACRO1(_call, _x1, ...) C_INTERNAL_CC_MACRO1(_call, __COUNTER__, (_x1), ## __VA_ARGS__) #define C_INTERNAL_CC_MACRO1(_call, _x1q, _x1, ...) \ @@ -195,15 +324,15 @@ _Static_assert(_assertion, _message); \ })) /** - * C_CC_MACRO2() - provide safe environment to a macro - * @_call: macro to call - * @_x1: first argument - * @_x2: second argument - * @...: further arguments to forward unmodified to @_call + * C_CC_MACRO2() - Provide safe environment to a macro + * @_call: Macro to call + * @_x1: First argument + * @_x2: Second argument + * @...: Further arguments to forward unmodified to ``_call`` * - * This is the 2-argument equivalent of C_CC_MACRO1(). + * This is the 2-argument equivalent of :c:macro:`C_CC_MACRO1()`. * - * Return: Result of @_call is returned. + * Return: Result of ``_call`` is returned. */ #define C_CC_MACRO2(_call, _x1, _x2, ...) C_INTERNAL_CC_MACRO2(_call, __COUNTER__, (_x1), __COUNTER__, (_x2), ## __VA_ARGS__) #define C_INTERNAL_CC_MACRO2(_call, _x1q, _x1, _x2q, _x2, ...) \ @@ -217,16 +346,16 @@ _Static_assert(_assertion, _message); \ })) /** - * C_CC_MACRO3() - provide safe environment to a macro - * @_call: macro to call - * @_x1: first argument - * @_x2: second argument - * @_x3: third argument - * @...: further arguments to forward unmodified to @_call + * C_CC_MACRO3() - Provide safe environment to a macro + * @_call: Macro to call + * @_x1: First argument + * @_x2: Second argument + * @_x3: Third argument + * @...: Further arguments to forward unmodified to ``_call`` * - * This is the 3-argument equivalent of C_CC_MACRO1(). + * This is the 3-argument equivalent of :c:macro:`C_CC_MACRO1()`. * - * Return: Result of @_call is returned. + * Return: Result of ``_call`` is returned. */ #define C_CC_MACRO3(_call, _x1, _x2, _x3, ...) C_INTERNAL_CC_MACRO3(_call, __COUNTER__, (_x1), __COUNTER__, (_x2), __COUNTER__, (_x3), ## __VA_ARGS__) #define C_INTERNAL_CC_MACRO3(_call, _x1q, _x1, _x2q, _x2, _x3q, _x3, ...) \ @@ -241,8 +370,17 @@ _Static_assert(_assertion, _message); \ })) /** - * C_ARRAY_SIZE() - calculate number of array elements at compile time - * @_x: array to calculate size of + * DOC: Standard Library Utilities + * + * The C Standard Library lacks some crucial and basic support functions. This + * section describes the set of helpers provided as extension to the standard + * library. + */ +/**/ + +/** + * C_ARRAY_SIZE() - Calculate number of array elements at compile time + * @_x: Array to calculate size of * * Return: Evaluates to a constant integer expression. */ @@ -260,9 +398,8 @@ _Static_assert(_assertion, _message); \ ) /** - * C_DECIMAL_MAX() - calculate maximum length of the decimal - * representation of an integer - * @_type: integer variable/type + * C_DECIMAL_MAX() - Calculate maximum length of a decimal representation + * @_type: Integer variable/type * * This calculates the bytes required for the decimal representation of an * integer of the given type. It accounts for a possible +/- prefix, but it @@ -294,28 +431,41 @@ _Static_assert(_assertion, _message); \ ) /** - * c_container_of() - cast a member of a structure out to the containing structure - * @_ptr: pointer to the member or NULL - * @_type: type of the container struct this is embedded in - * @_member: name of the member within the struct + * c_container_of() - Cast a member of a structure out to the containing type + * @_ptr: Pointer to the member or NULL + * @_type: Type of the container struct this is embedded in + * @_member: Name of the member within the struct * - * This uses `offsetof(3)` to turn a pointer to a structure-member into a + * This uses ``offsetof(3)`` to turn a pointer to a structure-member into a * pointer to the surrounding structure. * * Return: Pointer to the surrounding object. */ #define c_container_of(_ptr, _type, _member) C_CC_MACRO1(C_CONTAINER_OF, (_ptr), _type, _member) #define C_CONTAINER_OF(_ptr, _type, _member) \ - __extension__ ({ \ - /* trigger warning if types do not match */ \ - (void)(&((_type *)0)->_member == (_ptr)); \ - _ptr ? (_type*)( (char*)_ptr - offsetof(_type, _member) ) : NULL; \ - }) + C_EXPR_ASSERT( \ + (_ptr ? (_type*)c_internal_container_of((void *)_ptr, offsetof(_type, _member)) : NULL), \ + __builtin_types_compatible_p( \ + __typeof__(*(_ptr)), \ + __typeof__(((_type){})._member) \ + ) || __builtin_types_compatible_p( \ + __typeof__(_ptr), \ + __typeof__(NULL) \ + ), \ + "Invalid use of C_CONTAINER_OF()" \ + ) +static inline void *c_internal_container_of(void *ptr, size_t offset) { + /* + * Arithmetic on NULL is UB, even if in dead-code. Hide it in a proper + * C function, so the macro never emits it as code. + */ + return (char *)ptr - offset; +} /** - * c_max() - compute maximum of two values - * @_a: value A - * @_b: value B + * c_max() - Compute maximum of two values + * @_a: Value A + * @_b: Value B * * Calculate the maximum of both passed values. Both arguments are evaluated * exactly once, under all circumstances. Furthermore, if both values are @@ -331,9 +481,9 @@ _Static_assert(_assertion, _message); \ #define C_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b)) /** - * c_min() - compute minimum of two values - * @_a: value A - * @_b: value B + * c_min() - Compute minimum of two values + * @_a: Value A + * @_b: Value B * * Calculate the minimum of both passed values. Both arguments are evaluated * exactly once, under all circumstances. Furthermore, if both values are @@ -349,32 +499,32 @@ _Static_assert(_assertion, _message); \ #define C_MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b)) /** - * c_less_by() - calculate clamped difference of two values - * @_a: minuend - * @_b: subtrahend + * c_less_by() - Calculate clamped difference of two values + * @_a: Minuend + * @_b: Subtrahend * - * Calculate [_a - _b], but clamp the result to 0. Both arguments are evaluated - * exactly once, under all circumstances. Furthermore, if both values are - * constant expressions, the result will be constant as well. + * Calculate ``_a - _b``, but clamp the result to 0. Both arguments are + * evaluated exactly once, under all circumstances. Furthermore, if both values + * are constant expressions, the result will be constant as well. * * The comparison of their values is performed with the types given by the * caller. It is the caller's responsibility to convert them to suitable types * if necessary. * - * Return: This computes [_a - _b], if [_a > _b]. Otherwise, 0 is returned. + * Return: This computes ``_a - _b``, if ``_a > _b``. Otherwise, 0 is returned. */ #define c_less_by(_a, _b) C_CC_MACRO2(C_LESS_BY, (_a), (_b)) #define C_LESS_BY(_a, _b) ((_a) > (_b) ? (_a) - (_b) : 0) /** - * c_clamp() - clamp value to lower and upper boundary - * @_x: value to clamp - * @_low: lower boundary - * @_high: higher boundary + * c_clamp() - Clamp value to lower and upper boundary + * @_x: Value to clamp + * @_low: Lower boundary + * @_high: Higher boundary * - * This clamps @_x to the lower and higher bounds given as @_low and @_high. - * All arguments are evaluated exactly once, and yield a constant expression if - * all arguments are constant as well. + * This clamps ``_x`` to the lower and higher bounds given as ``_low`` and + * ``_high``. All arguments are evaluated exactly once, and yield a constant + * expression if all arguments are constant as well. * * The comparison of their values is performed with the types given by the * caller. It is the caller's responsibility to convert them to suitable types @@ -386,18 +536,18 @@ _Static_assert(_assertion, _message); \ #define C_CLAMP(_x, _low, _high) ((_x) > (_high) ? (_high) : (_x) < (_low) ? (_low) : (_x)) /** - * c_div_round_up() - calculate integer quotient but round up - * @_x: dividend - * @_y: divisor + * c_div_round_up() - Calculate integer quotient but round up + * @_x: Dividend + * @_y: Divisor * - * Calculates [x / y] but rounds up the result to the next integer. All + * Calculates ``x / y`` but rounds up the result to the next integer. All * arguments are evaluated exactly once, and yield a constant expression if all * arguments are constant. * - * Note: - * [(x + y - 1) / y] suffers from an integer overflow, even though the + * **Note:** + * ``(x + y - 1) / y`` suffers from an integer overflow, even though the * computation should be possible in the given type. Therefore, we use - * [x / y + !!(x % y)]. Note that on most CPUs a division returns both the + * ``x / y + !!(x % y)``. Note that on most CPUs a division returns both the * quotient and the remainder, so both should be equally fast. Furthermore, if * the divisor is a power of two, the compiler will optimize it, anyway. * @@ -411,34 +561,35 @@ _Static_assert(_assertion, _message); \ #define C_DIV_ROUND_UP(_x, _y) ((_x) / (_y) + !!((_x) % (_y))) /** - * c_align_to() - align value to a multiple - * @_val: value to align - * @_to: align to multiple of this + * c_align_to() - Align value to a multiple + * @_val: Value to align + * @_to: Align to multiple of this * - * This aligns @_val to a multiple of @_to. If @_val is already a multiple of - * @_to, @_val is returned unchanged. This function operates within the - * boundaries of the type of @_val and @_to. Make sure to cast them if needed. + * This aligns ``_val`` to a multiple of ``_to``. If ``_val`` is already a + * multiple of ``_to``, ``_val`` is returned unchanged. This function operates + * within the boundaries of the type of ``_val`` and ``_to``. Make sure to cast + * them if needed. * * The arguments of this macro are evaluated exactly once. If both arguments * are a constant expression, this also yields a constant return value. * - * Note that @_to must be a power of 2, otherwise the behavior will not match - * expectations. + * Note that ``_to`` must be a power of 2, otherwise the behavior will not + * match expectations. * - * Return: @_val aligned to a multiple of @_to + * Return: ``_val`` aligned to a multiple of ``_to``. */ #define c_align_to(_val, _to) C_CC_MACRO2(C_ALIGN_TO, (_val), (_to)) #define C_ALIGN_TO(_val, _to) (((_val) + (_to) - 1) & ~((_to) - 1)) /** - * c_assert() - runtime assertions - * @expr_result: result of an expression + * c_assert() - Runtime assertions + * @expr_result: Result of an expression * - * This function behaves like the standard `assert(3)` macro. That is, if - * `NDEBUG` is defined, it is a no-op. In all other cases it will assert that + * This function behaves like the standard ``assert(3)`` macro. That is, if + * ``NDEBUG`` is defined, it is a no-op. In all other cases it will assert that * the result of the passed expression is true. * - * Unlike the standard `assert(3)` macro, this function always evaluates its + * Unlike the standard ``assert(3)`` macro, this function always evaluates its * argument. This means side-effects will always be evaluated! However, if the * macro is used with constant expressions, the compiler will be able to * optimize it away. @@ -449,13 +600,13 @@ _Static_assert(_assertion, _message); \ }) /** - * c_errno() - return valid errno + * c_errno() - Return valid errno * - * This helper should be used to shut up gcc if you know 'errno' is valid (ie., - * errno is > 0). Instead of "return -errno;", use - * "return -c_errno();" It will suppress bogus gcc warnings in case it assumes - * 'errno' might be 0 (or <0) and thus the caller's error-handling might not be - * triggered. + * This helper should be used to shut up gcc if you know ``errno`` is valid + * (ie., ``errno`` is greater than 0). Instead of ``return -errno;``, use + * ``return -c_errno();`` It will suppress bogus gcc warnings in case it + * assumes ``errno`` might be 0 (or smaller than 0) and thus the caller's + * error-handling might not be triggered. * * This helper should be avoided whenever possible. However, occasionally we * really want to shut up gcc (especially with static/inline functions). In @@ -472,62 +623,196 @@ static inline int c_errno(void) { return _c_likely_(errno > 0) ? errno : ENOTRECOVERABLE; } -/* - * Common Destructors +/** + * c_memset() - Fill memory region with constant byte + * @p: Pointer to memory region, if non-empty + * @c: Value to fill with + * @n: Size of the memory region in bytes + * + * This function works like ``memset(3)`` if ``n`` is non-zero. If ``n`` is + * zero, this function is a no-op. Therefore, unlike ``memset(3)`` it is safe + * to call this function with ``NULL`` as ``p`` if ``n`` is 0. + * + * Return: ``p`` is returned. + */ +static inline void *c_memset(void *p, int c, size_t n) { + if (n > 0) + memset(p, c, n); + return p; +} + +/** + * c_memzero() - Clear memory area + * @p: Pointer to memory region, if non-empty + * @n: Size of the memory region in bytes + * + * Clear a memory area to 0. If the memory area is empty, this is a no-op. + * Similar to ``c_memset()``, this function allows ``p`` to be ``NULL`` if the + * area is empty. + * + * Return: ``p`` is returned. + */ +static inline void *c_memzero(void *p, size_t n) { + return c_memset(p, 0, n); +} + +/** + * c_memcpy() - Copy memory area + * @dst: Pointer to target area + * @src: Pointer to source area + * @n: Length of area to copy + * + * Copy the memory of size ``n`` from ``src`` to ``dst``, just as ``memcpy(3)`` + * does, except this function allows either to be ``NULL`` if ``n`` is zero. In + * the latter case, the operation is a no-op. + * + * Return: ``p`` is returned. + */ +static inline void *c_memcpy(void *dst, const void *src, size_t n) { + if (n > 0) + memcpy(dst, src, n); + return dst; +} + +/** + * c_memcmp() - Compare memory areas + * @s1: Pointer to one area + * @s2: Pointer to other area + * @n: Length of area to compare + * + * Compare the memory of size ``n`` of ``s1`` and ``s2``, just as ``memcmp(3)`` + * does, except this function allows either to be ``NULL`` if ``n`` is zero. * - * Followingly, there're a bunch of common 'static inline' destructors, which - * simply call the function that they're named after, but return "INVALID" - * instead of "void". This allows direct assignment to any member-field and/or - * variable they're defined in, like: + * Return: Comparison result for ordering is returned. + */ +static inline int c_memcmp(const void *s1, const void *s2, size_t n) { + if (n > 0) + return memcmp(s1, s2, n); + return 0; +} + +/** + * DOC: Common Destructors * - * foo = c_free(foo); + * A set of destructors is provided which extends standard library destructors + * to adhere to some adjuvant rules. In particular, they return an invalid + * value of the particular object, rather than void. This allows direct + * assignment to any member-field and/or variable they are defined in, like: * - * or + * .. code-block:: c * - * foo->bar = c_close(foo->bar); + * foo = c_free(foo); + * foo->bar = c_close(foo->bar); * * Furthermore, all those destructors can be safely called with the "INVALID" * value as argument, and they will be a no-op. */ +/**/ +/** + * c_free() - Destructor-wrapper for free() + * @p: Value to pass to destructor, or NULL + * + * Wrapper around ``free()``, but always returns ``NULL``. + * + * Return: NULL is returned. + */ static inline void *c_free(void *p) { free(p); return NULL; } +/** + * c_close() - Destructor-wrapper for close() + * @fd: File-descriptor to pass to destructor, or negative value + * + * Wrapper around ``close()``, but a no-op if a negative value is provided. + * Always returns ``-1``. + * + * Return: -1 is returned. + */ static inline int c_close(int fd) { if (fd >= 0) close(fd); return -1; } +/** + * c_fclose() - Destructor-wrapper for fclose() + * @f: File handle to pass to destructor, or NULL + * + * Wrapper around ``fclose()``, but a no-op if ``NULL`` is passed. Always + * returns ``NULL``. + * + * Return: NULL is returned. + */ static inline FILE *c_fclose(FILE *f) { if (f) fclose(f); return NULL; } +/** + * c_closedir() - Destructor-wrapper for closedir) + * @d: Directory handle to pass to destructor, or NULL + * + * Wrapper around ``closedir()``, but a no-op if ``NULL`` is passed. Always + * returns ``NULL``. + * + * Return: NULL is returned. + */ static inline DIR *c_closedir(DIR *d) { if (d) closedir(d); return NULL; } -/* - * Common Cleanup Helpers +/** + * DOC: Common Cleanup Helpers * - * A bunch of _c_cleanup_(foobarp) helpers that are used all over the place. - * Note that all of those have the "if (IS_INVALID(foobar))" check inline, so - * compilers can optimize most of the cleanup-paths in a function. However, if - * the function they call already does this _inline_, then it might be skipped. + * A set of helpers that aid in creating functions suitable for use with + * :c:macro:`_c_cleanup_()`. Furthermore, a collection of predefined cleanup + * functions of a set of standard library objects ready for use with + * :c:macro:`_c_cleanup_()`. + * Those cleanup helpers are always suffixed with a ``p``. + * + * The helpers that are provided are: + * + * - ``c_freep()``: Wrapper around :c:func:`c_free()`. + * - ``c_closep()``: Wrapper around :c:func:`c_close()`. + * - ``c_fclosep()``: Wrapper around :c:func:`c_fclose()`. + * - ``c_closedirp()``: Wrapper around :c:func:`c_closedir()`. */ +/**/ +/** + * C_DEFINE_CLEANUP() - Define cleanup helper + * @_type: Type of object to cleanup + * @_func: Destructor of the respective type + * + * Define a C static inline function that takes a single argument of type + * `_type` and calls `_func` on it, if its dereferenced value of its argument + * evaluates to true. Otherwise, it is a no-op. + * + * This macro allows for very simple and fast creation of cleanup helpers for + * use with ``_c_cleanup_()``, based on any destructor and type you provide to + * it. + */ #define C_DEFINE_CLEANUP(_type, _func) \ static inline void _func ## p(_type *p) { \ if (*p) \ _func(*p); \ } struct c_internal_trailing_semicolon +/** + * C_DEFINE_DIRECT_CLEANUP() - Define direct cleanup helper + * @_type: Type of object to cleanup + * @_func: Destructor of the respective type + * + * This works like :c:macro:`C_DEFINE_CLEANUP()` but does not check the + * dereferenced value of its argument. It always unconditionally invokes the + * destructor. + */ #define C_DEFINE_DIRECT_CLEANUP(_type, _func) \ static inline void _func ## p(_type *p) { \ _func(*p); \ diff --git a/src/core/NetworkManagerUtils.c b/src/core/NetworkManagerUtils.c index 5727aac8..8b0b4845 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; @@ -1389,16 +1388,20 @@ nm_utils_ip_route_attribute_to_platform(int addr_family, r->r_rtm_flags = ((onlink) ? (unsigned) RTNH_F_ONLINK : 0u); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_ADVMSS, r->mss, UINT32, uint32, 0); GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_WINDOW, r->window, UINT32, uint32, 0); GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_CWND, r->cwnd, UINT32, uint32, 0); GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_INITCWND, r->initcwnd, UINT32, uint32, 0); GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_INITRWND, r->initrwnd, UINT32, uint32, 0); GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_MTU, r->mtu, UINT32, uint32, 0); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_RTO_MIN, r->rto_min, UINT32, uint32, 0); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_QUICKACK, r->quickack, BOOLEAN, boolean, FALSE); GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, r->lock_window, BOOLEAN, boolean, FALSE); GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, r->lock_cwnd, BOOLEAN, boolean, FALSE); GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, r->lock_initcwnd, BOOLEAN, boolean, FALSE); GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, r->lock_initrwnd, BOOLEAN, boolean, FALSE); GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, r->lock_mtu, BOOLEAN, boolean, FALSE); + GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_LOCK_ADVMSS, r->lock_mss, BOOLEAN, boolean, FALSE); if ((variant = nm_ip_route_get_attribute(s_route, NM_IP_ROUTE_ATTRIBUTE_SRC)) && g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) { @@ -1691,7 +1694,7 @@ nm_utils_platform_capture_ip_setting(NMPlatform *platform, return NM_SETTING(g_steal_pointer(&s_ip)); } - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex); + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex); nm_platform_iter_obj_for_each (&iter, platform, &lookup, &obj) { const NMPlatformIPXAddress *address = NMP_OBJECT_CAST_IPX_ADDRESS(obj); nm_auto_unref_ip_address NMIPAddress *s_addr = NULL; @@ -1745,7 +1748,7 @@ nm_utils_platform_capture_ip_setting(NMPlatform *platform, } g_object_set(s_ip, NM_SETTING_IP_CONFIG_METHOD, method, NULL); - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4), ifindex); + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4), ifindex); nm_platform_iter_obj_for_each (&iter, platform, &lookup, &obj) { const NMPlatformIPXRoute *route = NMP_OBJECT_CAST_IPX_ROUTE(obj); nm_auto_unref_ip_route NMIPRoute *s_route = NULL; diff --git a/src/core/devices/bluetooth/nm-device-bt.c b/src/core/devices/bluetooth/nm-device-bt.c index 39b5c4ec..a8258123 100644 --- a/src/core/devices/bluetooth/nm-device-bt.c +++ b/src/core/devices/bluetooth/nm-device-bt.c @@ -262,6 +262,7 @@ complete_connection(NMDevice *device, const char *ctype; gboolean is_dun = FALSE; gboolean is_pan = FALSE; + gboolean is_nap = FALSE; NMSettingGsm *s_gsm; NMSettingCdma *s_cdma; NMSettingSerial *s_serial; @@ -281,6 +282,8 @@ complete_connection(NMDevice *device, is_dun = TRUE; else if (!strcmp(ctype, NM_SETTING_BLUETOOTH_TYPE_PANU)) is_pan = TRUE; + else if (!strcmp(ctype, NM_SETTING_BLUETOOTH_TYPE_NAP)) + is_nap = TRUE; } else { if (s_gsm || s_cdma) is_dun = TRUE; @@ -288,7 +291,27 @@ complete_connection(NMDevice *device, is_pan = TRUE; } - if (is_pan) { + if (is_nap) { + /* Make sure the device supports NAP */ + if (!(priv->capabilities & NM_BT_CAPABILITY_NAP)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("NAP requested, but Bluetooth device does not support NAP")); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_BLUETOOTH_SETTING_NAME, + NM_SETTING_BLUETOOTH_TYPE); + return FALSE; + } + + g_object_set(G_OBJECT(s_bt), + NM_SETTING_BLUETOOTH_TYPE, + NM_SETTING_BLUETOOTH_TYPE_NAP, + NULL); + + fallback_prefix = _("NAP connection"); + } else if (is_pan) { /* Make sure the device supports PAN */ if (!(priv->capabilities & NM_BT_CAPABILITY_NAP)) { g_set_error_literal(error, diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 16896d57..41473abe 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -9,6 +9,8 @@ #include #include +#include +#include #include "NetworkManagerUtils.h" #include "nm-device-private.h" @@ -16,6 +18,7 @@ #include "nm-device-factory.h" #include "libnm-core-aux-intern/nm-libnm-core-utils.h" #include "libnm-core-intern/nm-core-internal.h" +#include "nm-manager.h" #include "nm-setting-bond-port.h" #define _NMLOG_DEVICE_TYPE NMDeviceBond @@ -312,7 +315,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,54 +349,147 @@ 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 -apply_bonding_config(NMDeviceBond *self) +static guint8 +_bond_arp_ip_target_to_platform(const char *value, in_addr_t out[static NM_BOND_MAX_ARP_TARGETS]) { - NMDevice *device = NM_DEVICE(self); - NMSettingBond *s_bond; - NMBondMode mode; - const char *mode_str; - gs_free char *device_bond_mode = NULL; + gs_free const char **ip = NULL; + in_addr_t in_a; + int i; + int added = 0; - s_bond = nm_device_get_applied_setting(device, NM_TYPE_SETTING_BOND); - g_return_val_if_fail(s_bond, FALSE); + ip = nm_utils_bond_option_arp_ip_targets_split(value); - mode_str = nm_setting_bond_get_option_or_default(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); + if (!ip) + return added; - /* Set mode first, as some other options (e.g. arp_interval) are valid - * only for certain modes. - */ - device_bond_mode = nm_platform_sysctl_master_get_option(nm_device_get_platform(device), - nm_device_get_ifindex(device), - NM_SETTING_BOND_OPTION_MODE); - /* Need to release all slaves before we can change bond mode */ - if (!nm_streq0(device_bond_mode, mode_str)) - nm_device_master_release_slaves_all(device); + for (i = 0; ip[i]; i++) { + if (added > NM_BOND_MAX_ARP_TARGETS - 1) + break; + if (!nm_utils_parse_inaddr_bin(AF_INET, ip[i], NULL, &in_a)) + nm_assert_not_reached(); /* verify() already validated the IP addresses */ + + out[added++] = in_a; + } + return added; +} - set_bond_attr_or_default(device, s_bond, NM_SETTING_BOND_OPTION_MODE); +static int +_setting_bond_primary_opt_as_ifindex(NMSettingBond *s_bond) +{ + const char *primary_str; + int ifindex = 0; - set_bond_arp_ip_targets(device, s_bond); + primary_str = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_PRIMARY); - set_bond_attrs_or_default(device, s_bond, NM_MAKE_STRV(OPTIONS_APPLY_SUBSET)); - return TRUE; + if (primary_str != NULL) + ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, primary_str); + + return ifindex; +} + +static void +_platform_lnk_bond_init_from_setting(NMSettingBond *s_bond, NMPlatformLnkBond *props) +{ + const char *opt_value; + + *props = (NMPlatformLnkBond){ + .mode = _nm_setting_bond_mode_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE)), + .primary = _setting_bond_primary_opt_as_ifindex(s_bond), + .miimon = _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_MIIMON), + .updelay = _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_UPDELAY), + .downdelay = _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY), + .arp_interval = + _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL), + .resend_igmp = + _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_RESEND_IGMP), + .min_links = _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_MIN_LINKS), + .lp_interval = + _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_LP_INTERVAL), + .packets_per_port = + _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE), + .peer_notif_delay = + _nm_setting_bond_opt_value_as_u32(s_bond, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY), + .arp_all_targets = _nm_setting_bond_arp_all_targets_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS)), + .arp_validate = _nm_setting_bond_arp_validate_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_VALIDATE)), + .ad_actor_sys_prio = + _nm_setting_bond_opt_value_as_u16(s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO), + .ad_user_port_key = + _nm_setting_bond_opt_value_as_u16(s_bond, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY), + .primary_reselect = _nm_setting_bond_primary_reselect_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT)), + .fail_over_mac = _nm_setting_bond_fail_over_mac_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_FAIL_OVER_MAC)), + .xmit_hash_policy = _nm_setting_bond_xmit_hash_policy_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY)), + .num_grat_arp = + _nm_setting_bond_opt_value_as_u8(s_bond, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP), + .all_ports_active = + _nm_setting_bond_opt_value_as_u8(s_bond, NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE), + .lacp_rate = _nm_setting_bond_lacp_rate_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_LACP_RATE)), + .ad_select = _nm_setting_bond_ad_select_from_string( + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_AD_SELECT)), + }; + + nm_ether_addr_from_string( + &props->ad_actor_system, + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM)); + + opt_value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_USE_CARRIER); + if (opt_value != NULL) + props->use_carrier = _nm_utils_ascii_str_to_bool(opt_value, FALSE); + + opt_value = + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB); + if (opt_value != NULL) + props->tlb_dynamic_lb = _nm_utils_ascii_str_to_bool(opt_value, FALSE); + + opt_value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); + if (opt_value != NULL) + props->arp_ip_targets_num = + _bond_arp_ip_target_to_platform(opt_value, props->arp_ip_target); + + props->miimon_has = !props->arp_interval && !props->arp_validate; + props->updelay_has = props->miimon_has && props->miimon; + props->downdelay_has = props->miimon_has && props->miimon; + props->peer_notif_delay_has = (props->miimon || props->arp_interval) && props->peer_notif_delay; + props->arp_all_targets_has = props->arp_interval && props->arp_all_targets; + props->resend_igmp_has = props->resend_igmp != 1; + props->lp_interval = props->lp_interval != 1; + props->tlb_dynamic_lb_has = NM_IN_SET(props->mode, NM_BOND_MODE_TLB, NM_BOND_MODE_ALB); } static NMActStageReturn act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) { - NMDeviceBond *self = NM_DEVICE_BOND(device); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + NMConnection *connection; + NMSettingBond *s_bond; + NMPlatformLnkBond props; + int r; + int ifindex = nm_device_get_ifindex(device); + + connection = nm_device_get_applied_connection(device); + g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); + + s_bond = nm_connection_get_setting_bond(connection); + g_return_val_if_fail(s_bond, NM_ACT_STAGE_RETURN_FAILURE); + + _platform_lnk_bond_init_from_setting(s_bond, &props); /* Interface must be down to set bond options */ nm_device_take_down(device, TRUE); - if (!apply_bonding_config(self)) + r = nm_platform_link_bond_change(nm_device_get_platform(device), ifindex, &props); + if (r < 0) { ret = NM_ACT_STAGE_RETURN_FAILURE; - else { + NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + } else { if (!nm_device_hw_addr_set_cloned(device, nm_device_get_applied_connection(device), FALSE)) ret = NM_ACT_STAGE_RETURN_FAILURE; } @@ -424,8 +520,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 +544,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 +552,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 +574,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 +592,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 +614,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)); } } } @@ -529,12 +631,19 @@ create_and_realize(NMDevice *device, const NMPlatformLink **out_plink, GError **error) { - const char *iface = nm_device_get_iface(device); - int r; + const char *iface = nm_device_get_iface(device); + NMSettingBond *s_bond; + NMPlatformLnkBond props; + int r; g_assert(iface); - r = nm_platform_link_bond_add(nm_device_get_platform(device), iface, out_plink); + s_bond = nm_connection_get_setting_bond(connection); + nm_assert(s_bond); + + _platform_lnk_bond_init_from_setting(s_bond, &props); + + r = nm_platform_link_bond_add(nm_device_get_platform(device), iface, &props, out_plink); if (r < 0) { g_set_error(error, NM_DEVICE_ERROR, @@ -612,7 +721,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 +772,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 9bf7ac01..31cf361e 100644 --- a/src/core/devices/nm-device-bridge.c +++ b/src/core/devices/nm-device-bridge.c @@ -836,30 +836,33 @@ _platform_lnk_bridge_init_from_setting(NMSettingBridge *s_bridge, NMPlatformLnkB to_sysfs_group_address_sys(nm_setting_bridge_get_group_address(s_bridge), &props->group_addr); } -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) +static gboolean +link_config(NMDevice *device, NMConnection *connection) { - NMConnection *connection; + int ifindex = nm_device_get_ifindex(device); NMSettingBridge *s_bridge; NMPlatformLnkBridge props; - int r; - int ifindex = nm_device_get_ifindex(device); - - connection = nm_device_get_applied_connection(device); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); s_bridge = nm_connection_get_setting_bridge(connection); - g_return_val_if_fail(s_bridge, NM_ACT_STAGE_RETURN_FAILURE); + g_return_val_if_fail(s_bridge, FALSE); _platform_lnk_bridge_init_from_setting(s_bridge, &props); - r = nm_platform_link_bridge_change(nm_device_get_platform(device), ifindex, &props); - if (r < 0) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } + if (nm_platform_link_bridge_change(nm_device_get_platform(device), ifindex, &props) < 0) + return FALSE; + + return bridge_set_vlan_options(device, s_bridge); +} + +static NMActStageReturn +act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) +{ + NMConnection *connection; + + connection = nm_device_get_applied_connection(device); + g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - if (!bridge_set_vlan_options(device, s_bridge)) { + if (!link_config(device, connection)) { NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); return NM_ACT_STAGE_RETURN_FAILURE; } @@ -974,8 +977,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 +994,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); @@ -1010,25 +1019,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; @@ -1041,10 +1050,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; } @@ -1054,12 +1063,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)); } } @@ -1085,10 +1094,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)) { @@ -1113,6 +1118,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. @@ -1142,6 +1152,72 @@ create_and_realize(NMDevice *device, /*****************************************************************************/ +static gboolean +can_reapply_change(NMDevice *device, + const char *setting_name, + NMSetting *s_old, + NMSetting *s_new, + GHashTable *diffs, + GError **error) +{ + /* Delegate changes to other settings to parent class */ + if (!nm_streq(setting_name, NM_SETTING_BRIDGE_SETTING_NAME)) { + return NM_DEVICE_CLASS(nm_device_bridge_parent_class) + ->can_reapply_change(device, setting_name, s_old, s_new, diffs, error); + } + + return nm_device_hash_check_invalid_keys(diffs, + NM_SETTING_BRIDGE_SETTING_NAME, + error, + NM_SETTING_BRIDGE_STP, + NM_SETTING_BRIDGE_PRIORITY, + NM_SETTING_BRIDGE_FORWARD_DELAY, + NM_SETTING_BRIDGE_HELLO_TIME, + NM_SETTING_BRIDGE_MAX_AGE, + NM_SETTING_BRIDGE_AGEING_TIME, + NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, + NM_SETTING_BRIDGE_MULTICAST_HASH_MAX, + NM_SETTING_BRIDGE_MULTICAST_LAST_MEMBER_COUNT, + NM_SETTING_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL, + NM_SETTING_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL, + NM_SETTING_BRIDGE_MULTICAST_SNOOPING, + NM_SETTING_BRIDGE_MULTICAST_ROUTER, + NM_SETTING_BRIDGE_MULTICAST_QUERIER, + NM_SETTING_BRIDGE_MULTICAST_QUERIER_INTERVAL, + NM_SETTING_BRIDGE_MULTICAST_QUERY_INTERVAL, + NM_SETTING_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL, + NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR, + NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT, + NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL, + NM_SETTING_BRIDGE_GROUP_ADDRESS, + NM_SETTING_BRIDGE_VLAN_PROTOCOL, + NM_SETTING_BRIDGE_VLAN_STATS_ENABLED, + NM_SETTING_BRIDGE_VLAN_FILTERING, + NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID, + NM_SETTING_BRIDGE_VLANS); +} + +static void +reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_new) +{ + NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); + NMSettingBridge *s_bridge; + + NM_DEVICE_CLASS(nm_device_bridge_parent_class)->reapply_connection(device, con_old, con_new); + + _LOGD(LOGD_BRIDGE, "reapplying bridge settings"); + s_bridge = nm_connection_get_setting_bridge(con_new); + g_return_if_fail(s_bridge); + + /* Make sure bridge_set_vlan_options() called by link_config() + * sets vlan_filtering and default_pvid anew. */ + self->vlan_configured = FALSE; + + link_config(device, con_new); +} + +/*****************************************************************************/ + static void nm_device_bridge_init(NMDeviceBridge *self) { @@ -1183,9 +1259,11 @@ 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; + device_class->can_reapply_change = can_reapply_change; + device_class->reapply_connection = reapply_connection; } /*****************************************************************************/ diff --git a/src/core/devices/nm-device-veth.c b/src/core/devices/nm-device-veth.c index 8c95a293..63dfd8bb 100644 --- a/src/core/devices/nm-device-veth.c +++ b/src/core/devices/nm-device-veth.c @@ -82,6 +82,8 @@ create_and_realize(NMDevice *device, GError **error) { const char *iface = nm_device_get_iface(device); + const char *peer; + NMDevice *peer_device; NMSettingVeth *s_veth; int r; @@ -96,10 +98,15 @@ create_and_realize(NMDevice *device, return FALSE; } - r = nm_platform_link_veth_add(nm_device_get_platform(device), - iface, - nm_setting_veth_get_peer(s_veth), - out_plink); + peer = nm_setting_veth_get_peer(s_veth); + peer_device = nm_manager_get_device(NM_MANAGER_GET, peer, NM_DEVICE_TYPE_VETH); + if (peer_device) { + /* The veth device and its peer already exist. No need to create it again. */ + if (nm_streq0(nm_device_get_iface(nm_device_parent_get_device(peer_device)), iface)) + return TRUE; + } + + r = nm_platform_link_veth_add(nm_device_get_platform(device), iface, peer, out_plink); if (r < 0) { g_set_error(error, NM_DEVICE_ERROR, diff --git a/src/core/devices/nm-device-vrf.c b/src/core/devices/nm-device-vrf.c index ae80e1d4..2aef0e3d 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-wireguard.c b/src/core/devices/nm-device-wireguard.c index bdb96cb2..179c2a22 100644 --- a/src/core/devices/nm-device-wireguard.c +++ b/src/core/devices/nm-device-wireguard.c @@ -18,7 +18,7 @@ #include "nm-device-private.h" #include "libnm-platform/nm-platform.h" #include "libnm-platform/nmp-object.h" -#include "libnm-platform/nmp-route-manager.h" +#include "libnm-platform/nmp-global-tracker.h" #include "nm-device-factory.h" #include "nm-active-connection.h" #include "nm-act-request.h" diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 6b854517..c51da9ac 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -41,7 +41,7 @@ #include "libnm-platform/nm-platform.h" #include "libnm-platform/nm-platform-utils.h" #include "libnm-platform/nmp-object.h" -#include "libnm-platform/nmp-route-manager.h" +#include "libnm-platform/nmp-global-tracker.h" #include "ndisc/nm-ndisc.h" #include "ndisc/nm-lndp-ndisc.h" @@ -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 { @@ -392,6 +393,8 @@ typedef struct _NMDevicePrivate { guint device_link_changed_id; guint device_ip_link_changed_id; + GSource *delay_activation_source; + NMDeviceState state; NMDeviceStateReason state_reason; struct { @@ -604,6 +607,7 @@ typedef struct _NMDevicePrivate { const NMDeviceIPState state; NMDeviceIPState state_; }; + gulong dnsmgr_update_pending_signal_id; } ip_data; union { @@ -1394,6 +1398,56 @@ _prop_get_connection_dns_over_tls(NMDevice *self) NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT); } +static NMMptcpFlags +_prop_get_connection_mptcp_flags(NMDevice *self) +{ + NMConnection *connection; + NMMptcpFlags mptcp_flags = NM_MPTCP_FLAGS_NONE; + + g_return_val_if_fail(NM_IS_DEVICE(self), NM_MPTCP_FLAGS_DISABLED); + + connection = nm_device_get_applied_connection(self); + if (connection) { + mptcp_flags = + nm_setting_connection_get_mptcp_flags(nm_connection_get_setting_connection(connection)); + if (mptcp_flags != NM_MPTCP_FLAGS_NONE) + mptcp_flags = nm_mptcp_flags_normalize(mptcp_flags); + } + + if (mptcp_flags == NM_MPTCP_FLAGS_NONE) { + guint64 v; + + v = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("connection.mptcp-flags"), + self, + 0, + G_MAXINT64, + NM_MPTCP_FLAGS_NONE); + /* We filter out all invalid settings and accept it. Somewhat intentionally, we don't do a + * strict parsing of the value to support forward compatibility. */ + if (v != NM_MPTCP_FLAGS_NONE) + mptcp_flags = nm_mptcp_flags_normalize(v); + } + + if (mptcp_flags == NM_MPTCP_FLAGS_NONE) { + gint32 v; + + v = nm_platform_sysctl_get_int32(nm_device_get_platform(self), + NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/mptcp/enabled"), + -1); + if (v > 0) { + /* if MPTCP is enabled via the sysctl, we use the default. */ + mptcp_flags = _NM_MPTCP_FLAGS_DEFAULT; + } else + mptcp_flags = NM_MPTCP_FLAGS_DISABLED; + } + + nm_assert(mptcp_flags != NM_MPTCP_FLAGS_NONE + && mptcp_flags == nm_mptcp_flags_normalize(mptcp_flags)); + + return mptcp_flags; +} + static guint32 _prop_get_ipvx_route_table(NMDevice *self, int addr_family) { @@ -1508,6 +1562,53 @@ _prop_get_connection_lldp(NMDevice *self) return lldp == NM_SETTING_CONNECTION_LLDP_ENABLE_RX; } +static NMSettingIP4LinkLocal +_prop_get_ipv4_link_local(NMDevice *self) +{ + NMSettingIP4Config *s_ip4; + NMSettingIP4LinkLocal link_local; + + s_ip4 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP4_CONFIG); + if (!s_ip4) + return NM_SETTING_IP4_LL_DISABLED; + + link_local = nm_setting_ip4_config_get_link_local(s_ip4); + + if (link_local == NM_SETTING_IP4_LL_DEFAULT) { + /* For connections without a ipv4.link-local property configured the global configuration + might defines the default value for ipv4.link-local. */ + link_local = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("ipv4.link-local"), + self, + NM_SETTING_IP4_LL_AUTO, + NM_SETTING_IP4_LL_ENABLED, + NM_SETTING_IP4_LL_DEFAULT); + if (link_local == NM_SETTING_IP4_LL_DEFAULT) { + /* If there is no global configuration for ipv4.link-local assume auto */ + link_local = NM_SETTING_IP4_LL_AUTO; + } else if (link_local == NM_SETTING_IP4_LL_ENABLED + && nm_streq(nm_setting_ip_config_get_method((NMSettingIPConfig *) s_ip4), + NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { + /* ipv4.method=disabled has higher priority than the global ipv4.link-local=enabled */ + link_local = NM_SETTING_IP4_LL_DISABLED; + } else if (link_local == NM_SETTING_IP4_LL_DISABLED + && nm_streq(nm_setting_ip_config_get_method((NMSettingIPConfig *) s_ip4), + NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { + /* ipv4.method=link-local has higher priority than the global ipv4.link-local=disabled */ + link_local = NM_SETTING_IP4_LL_ENABLED; + } + } + + if (link_local == NM_SETTING_IP4_LL_AUTO) { + link_local = nm_streq(nm_setting_ip_config_get_method((NMSettingIPConfig *) s_ip4), + NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL) + ? NM_SETTING_IP4_LL_ENABLED + : NM_SETTING_IP4_LL_DISABLED; + } + + return link_local; +} + static guint32 _prop_get_ipv4_dad_timeout(NMDevice *self) { @@ -2118,6 +2219,50 @@ _prop_get_ipv6_ip6_privacy(NMDevice *self) return _ip6_privacy_clamp(ip6_privacy); } +static NMSettingIP6ConfigAddrGenMode +_prop_get_ipv6_addr_gen_mode(NMDevice *self) +{ + NMSettingIP6ConfigAddrGenMode addr_gen_mode; + NMSettingIP6Config *s_ip6; + gint64 c; + + g_return_val_if_fail(self, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY); + + s_ip6 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP6_CONFIG); + if (s_ip6) { + addr_gen_mode = nm_setting_ip6_config_get_addr_gen_mode(s_ip6); + if (NM_IN_SET(addr_gen_mode, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY)) + return addr_gen_mode; + } else + addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT; + + nm_assert(NM_IN_SET(addr_gen_mode, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT)); + + c = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("ipv6.addr-gen-mode"), + self, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT, + -1); + if (c != -1) + addr_gen_mode = c; + + if (addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT) + addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY; + else if (addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64) + addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64; + + nm_assert(NM_IN_SET(addr_gen_mode, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY)); + + return addr_gen_mode; +} + static const char * _prop_get_x_cloned_mac_address(NMDevice *self, NMConnection *connection, gboolean is_wifi) { @@ -2678,6 +2823,7 @@ nm_device_create_l3_config_data_from_connection(NMDevice *self, NMConnection *co nm_l3_config_data_set_llmnr(l3cd, _prop_get_connection_llmnr(self)); nm_l3_config_data_set_dns_over_tls(l3cd, _prop_get_connection_dns_over_tls(self)); nm_l3_config_data_set_ip6_privacy(l3cd, _prop_get_ipv6_ip6_privacy(self)); + nm_l3_config_data_set_mptcp_flags(l3cd, _prop_get_connection_mptcp_flags(self)); return l3cd; } @@ -2929,6 +3075,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) { @@ -3321,6 +3474,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), @@ -5896,43 +6070,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; + return; - 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); - - 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); @@ -5952,8 +6099,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); } /** @@ -5986,7 +6196,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); @@ -6007,13 +6217,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); @@ -6344,7 +6555,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; } @@ -7540,8 +7751,9 @@ slave_state_changed(NMDevice *slave, } if (release) { - configure = priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED - && nm_device_sys_iface_state_get(slave) != NM_DEVICE_SYS_IFACE_STATE_EXTERNAL; + configure = (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED + && nm_device_sys_iface_state_get(slave) != NM_DEVICE_SYS_IFACE_STATE_EXTERNAL) + || nm_device_sys_iface_state_get(slave) == NM_DEVICE_SYS_IFACE_STATE_MANAGED; nm_device_master_release_slave(self, slave, @@ -7577,7 +7789,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); @@ -7806,6 +8018,9 @@ nm_device_slave_notify_release(NMDevice *self, NMDeviceStateReason reason) g_return_if_fail(priv->master); + if (!priv->is_enslaved) + return; + if (priv->state > NM_DEVICE_STATE_DISCONNECTED && priv->state <= NM_DEVICE_STATE_ACTIVATED) { switch (nm_device_state_reason_check(reason)) { case NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED: @@ -7835,14 +8050,12 @@ nm_device_slave_notify_release(NMDevice *self, NMDeviceStateReason reason) } else _LOGI(LOGD_DEVICE, "released from master device %s", nm_device_get_iface(priv->master)); - if (priv->is_enslaved) { - priv->is_enslaved = FALSE; + priv->is_enslaved = FALSE; - _notify(self, PROP_MASTER); + _notify(self, PROP_MASTER); - nm_clear_pointer(&NM_DEVICE_GET_PRIVATE(priv->master)->ports_variant, g_variant_unref); - nm_gobject_notify_together(priv->master, PROP_PORTS, PROP_SLAVES); - } + nm_clear_pointer(&NM_DEVICE_GET_PRIVATE(priv->master)->ports_variant, g_variant_unref); + nm_gobject_notify_together(priv->master, PROP_PORTS, PROP_SLAVES); } /** @@ -8161,13 +8374,13 @@ device_has_config(NMDevice *self) head_entry = nm_platform_lookup( nm_device_get_platform(self), - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP4_ADDRESS, pllink->ifindex)); + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_IP4_ADDRESS, pllink->ifindex)); if (head_entry) return TRUE; head_entry = nm_platform_lookup( nm_device_get_platform(self), - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, pllink->ifindex)); + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, pllink->ifindex)); if (head_entry) return TRUE; @@ -9329,13 +9542,13 @@ lldp_setup(NMDevice *self, NMTernary enabled) static void _routing_rules_sync(NMDevice *self, NMTernary set_mode) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMPRouteManager *route_manager = nm_netns_get_route_manager(nm_device_get_netns(self)); - NMDeviceClass *klass = NM_DEVICE_GET_CLASS(self); - gboolean untrack_only_dirty = FALSE; - gboolean keep_deleted_rules; - gpointer user_tag_1; - gpointer user_tag_2; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMPGlobalTracker *global_tracker = nm_netns_get_global_tracker(nm_device_get_netns(self)); + NMDeviceClass *klass = NM_DEVICE_GET_CLASS(self); + gboolean untrack_only_dirty = FALSE; + gboolean keep_deleted_rules; + gpointer user_tag_1; + gpointer user_tag_2; /* take two arbitrary user-tag pointers that belong to @self. */ user_tag_1 = &priv->v4_route_table; @@ -9367,13 +9580,13 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode) nm_ip_routing_rule_to_platform(rule, &plrule); /* We track this rule, but we also make it explicitly not weakly-tracked - * (meaning to untrack NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG at + * (meaning to untrack NMP_GLOBAL_TRACKER_EXTERN_WEAKLY_TRACKED_USER_TAG at * the same time). */ - nmp_route_manager_track_rule(route_manager, - &plrule, - 10, - user_tag_1, - NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); + nmp_global_tracker_track_rule(global_tracker, + &plrule, + 10, + user_tag_1, + NMP_GLOBAL_TRACKER_EXTERN_WEAKLY_TRACKED_USER_TAG); } } @@ -9383,25 +9596,25 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode) extra_rules = klass->get_extra_rules(self); if (extra_rules) { for (i = 0; i < extra_rules->len; i++) { - nmp_route_manager_track_rule( - route_manager, + nmp_global_tracker_track_rule( + global_tracker, NMP_OBJECT_CAST_ROUTING_RULE(extra_rules->pdata[i]), 10, user_tag_2, - NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); + NMP_GLOBAL_TRACKER_EXTERN_WEAKLY_TRACKED_USER_TAG); } } } } - nmp_route_manager_untrack_all(route_manager, user_tag_1, !untrack_only_dirty, TRUE); + nmp_global_tracker_untrack_all(global_tracker, user_tag_1, !untrack_only_dirty, TRUE); if (klass->get_extra_rules) - nmp_route_manager_untrack_all(route_manager, user_tag_2, !untrack_only_dirty, TRUE); + nmp_global_tracker_untrack_all(global_tracker, user_tag_2, !untrack_only_dirty, TRUE); keep_deleted_rules = FALSE; if (set_mode == NM_TERNARY_DEFAULT) { /* when exiting NM, we leave the device up and the rules configured. - * We just call nmp_route_manager_sync() to forget about the synced rules, + * We just call nmp_global_tracker_sync() to forget about the synced rules, * but we don't actually delete them. * * FIXME: that is a problem after restart of NetworkManager, because these @@ -9415,7 +9628,7 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode) * file and track them after restart again. */ keep_deleted_rules = TRUE; } - nmp_route_manager_sync(route_manager, NMP_OBJECT_TYPE_ROUTING_RULE, keep_deleted_rules); + nmp_global_tracker_sync(global_tracker, NMP_OBJECT_TYPE_ROUTING_RULE, keep_deleted_rules); } static gboolean @@ -10045,6 +10258,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), @@ -10190,7 +10404,11 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) .vendor_class_identifier = vendor_class_identifier, .use_fqdn = hostname_is_fqdn, .reject_servers = reject_servers, - .v4.request_broadcast = request_broadcast, + .v4 = + { + .request_broadcast = request_broadcast, + .acd_timeout_msec = _prop_get_ipv4_dad_timeout(self), + }, }; priv->ipdhcp_data_4.client = @@ -10205,22 +10423,25 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) duid = _prop_get_ipv6_dhcp_duid(self, connection, hwaddr, &enforce_duid); config = (NMDhcpClientConfig){ - .addr_family = AF_INET6, - .l3cfg = nm_device_get_l3cfg(self), - .iface = nm_device_get_ip_iface(self), - .uuid = nm_connection_get_uuid(connection), - .send_hostname = nm_setting_ip_config_get_dhcp_send_hostname(s_ip), - .hostname = nm_setting_ip_config_get_dhcp_hostname(s_ip), - .hostname_flags = _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET6), - .client_id = duid, - .mud_url = _prop_get_connection_mud_url(self, s_con), - .timeout = no_lease_timeout_sec, - .anycast_address = _device_get_dhcp_anycast_address(self), - .v6.enforce_duid = enforce_duid, - .v6.iaid = iaid, - .v6.iaid_explicit = iaid_explicit, - .v6.info_only = (priv->ipdhcp_data_6.v6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF), - .v6.needed_prefixes = priv->ipdhcp_data_6.v6.needed_prefixes, + .addr_family = AF_INET6, + .l3cfg = nm_device_get_l3cfg(self), + .iface = nm_device_get_ip_iface(self), + .uuid = nm_connection_get_uuid(connection), + .send_hostname = nm_setting_ip_config_get_dhcp_send_hostname(s_ip), + .hostname = nm_setting_ip_config_get_dhcp_hostname(s_ip), + .hostname_flags = _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET6), + .client_id = duid, + .mud_url = _prop_get_connection_mud_url(self, s_con), + .timeout = no_lease_timeout_sec, + .anycast_address = _device_get_dhcp_anycast_address(self), + .v6 = + { + .enforce_duid = enforce_duid, + .iaid = iaid, + .iaid_explicit = iaid_explicit, + .info_only = (priv->ipdhcp_data_6.v6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF), + .needed_prefixes = priv->ipdhcp_data_6.v6.needed_prefixes, + }, }; priv->ipdhcp_data_6.client = @@ -10635,7 +10856,6 @@ _dev_ipll6_start(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); NMConnection *connection; - NMSettingIP6Config *s_ip6 = NULL; gboolean assume; const char *ifname; NML3IPv6LLState llstate; @@ -10656,14 +10876,10 @@ _dev_ipll6_start(NMDevice *self) } connection = nm_device_get_applied_connection(self); - if (connection) - s_ip6 = NM_SETTING_IP6_CONFIG(nm_connection_get_setting_ip6_config(connection)); assume = nm_device_sys_iface_state_is_external_or_assume(self); - if (s_ip6 - && nm_setting_ip6_config_get_addr_gen_mode(s_ip6) - == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) { + if (_prop_get_ipv6_addr_gen_mode(self) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) { NMUtilsStableType stable_type; const char *stable_id; @@ -10866,9 +11082,10 @@ _commit_mtu(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); NMDeviceMtuSource source = NM_DEVICE_MTU_SOURCE_NONE; + NMSettingIPConfig *s_ip6; const NML3ConfigData *l3cd; guint32 ip6_mtu_orig; - guint32 ip6_mtu; + guint32 ip6_mtu = 0; guint32 mtu_desired_orig; guint32 mtu_desired; guint32 mtu_plat; @@ -10953,10 +11170,9 @@ _commit_mtu(NMDevice *self) } } - if (mtu_desired && mtu_desired < 1280) { - NMSettingIPConfig *s_ip6; + s_ip6 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP6_CONFIG); - s_ip6 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP6_CONFIG); + if (mtu_desired && mtu_desired < 1280) { if (s_ip6 && !NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip6), NM_SETTING_IP6_CONFIG_METHOD_IGNORE, @@ -10971,7 +11187,12 @@ _commit_mtu(NMDevice *self) } } - ip6_mtu = priv->ip6_mtu; + if (s_ip6) + ip6_mtu = nm_setting_ip6_config_get_mtu(NM_SETTING_IP6_CONFIG(s_ip6)); + + if (!ip6_mtu) + ip6_mtu = priv->ip6_mtu; + if (!ip6_mtu && priv->mtu_source == NM_DEVICE_MTU_SOURCE_NONE) { /* initially, if the IPv6 MTU is not specified, grow it as large as the * link MTU @mtu_desired. Only exception is, if @mtu_desired is so small @@ -11353,7 +11574,7 @@ _dev_ipac6_start(NMDevice *self) .ifname = nm_device_get_ip_iface(self), .stable_type = stable_type, .network_id = stable_id, - .addr_gen_mode = nm_setting_ip6_config_get_addr_gen_mode(s_ip), + .addr_gen_mode = _prop_get_ipv6_addr_gen_mode(self), .node_type = node_type, .max_addresses = max_addresses, .router_solicitations = router_solicitations, @@ -11640,11 +11861,14 @@ activate_stage3_ip_config_for_addr_family(NMDevice *self, int addr_family, const goto out_devip; if (IS_IPv4) { + if (_prop_get_ipv4_link_local(self) == NM_SETTING_IP4_LL_ENABLED) + _dev_ipll4_start(self); + if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) _dev_ipdhcpx_start(self, AF_INET); - else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) - _dev_ipll4_start(self); - else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) + else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { + /* pass */ + } else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) _dev_ipshared4_start(self); else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) priv->ip_data_x[IS_IPv4].is_disabled = TRUE; @@ -12344,7 +12568,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); @@ -12360,6 +12585,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); } @@ -12479,12 +12707,15 @@ can_reapply_change(NMDevice *self, NM_SETTING_CONNECTION_STABLE_ID, NM_SETTING_CONNECTION_AUTOCONNECT, NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES, + NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, NM_SETTING_CONNECTION_ZONE, NM_SETTING_CONNECTION_METERED, NM_SETTING_CONNECTION_LLDP, NM_SETTING_CONNECTION_MDNS, NM_SETTING_CONNECTION_LLMNR, - NM_SETTING_CONNECTION_DNS_OVER_TLS); + NM_SETTING_CONNECTION_DNS_OVER_TLS, + NM_SETTING_CONNECTION_MPTCP_FLAGS, + NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY); } if (NM_IN_STRSET(setting_name, @@ -12700,7 +12931,8 @@ check_and_reapply_connection(NMDevice *self, NM_SETTING_CONNECTION_LLDP, NM_SETTING_CONNECTION_MDNS, NM_SETTING_CONNECTION_LLMNR, - NM_SETTING_CONNECTION_DNS_OVER_TLS)) { + NM_SETTING_CONNECTION_DNS_OVER_TLS, + NM_SETTING_CONNECTION_MPTCP_FLAGS)) { priv->ip_data_4.do_reapply = TRUE; priv->ip_data_6.do_reapply = TRUE; } @@ -13361,29 +13593,71 @@ _dispatcher_cleanup(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + nm_clear_g_source_inst(&priv->delay_activation_source); + if (!priv->dispatcher.call_id) return FALSE; nm_dispatcher_call_cancel(g_steal_pointer(&priv->dispatcher.call_id)); priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; + return TRUE; } static void -_dispatcher_complete_proceed_state(NMDispatcherCallId *call_id, gpointer user_data) +_queue_dispatcher_post_state(NMDevice *self) { - NMDevice *self = NM_DEVICE(user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - g_return_if_fail(call_id == priv->dispatcher.call_id); - - priv->dispatcher.call_id = NULL; nm_device_queue_state(self, priv->dispatcher.post_state, priv->dispatcher.post_state_reason); priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; } +static gboolean +_wait_activation_delay_timeout(gpointer user_data) +{ + NMDevice *self = user_data; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + nm_clear_g_source_inst(&priv->delay_activation_source); + + _LOGD(LOGD_DEVICE, "finished waiting on activation delay"); + _queue_dispatcher_post_state(self); + + return G_SOURCE_REMOVE; +} + +static void +_dispatcher_complete_proceed_state(NMDispatcherCallId *call_id, gpointer user_data) +{ + NMDevice *self = NM_DEVICE(user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection *conn; + NMSettingConnection *s_conn; + gint32 delay_timeout; + + g_return_if_fail(call_id == priv->dispatcher.call_id); + nm_assert(!priv->delay_activation_source); + + priv->dispatcher.call_id = NULL; + conn = nm_device_get_applied_connection(self); + if (conn) { + s_conn = nm_connection_get_setting_connection(conn); + if (s_conn) { + delay_timeout = nm_setting_connection_get_wait_activation_delay(s_conn); + if (delay_timeout > 0) { + priv->delay_activation_source = + nm_g_timeout_add_source(delay_timeout, _wait_activation_delay_timeout, self); + return; + } + } + } + + _queue_dispatcher_post_state(self); +} + /*****************************************************************************/ static void @@ -13437,14 +13711,14 @@ spawn_ping(NMDevice *self) gs_free char *str_timeout = NULL; gs_free char *tmp_str = NULL; const char *args[] = {priv->gw_ping.binary, - "-I", - nm_device_get_ip_iface(self), - "-c", - "1", - "-w", - NULL, - priv->gw_ping.address, - NULL}; + "-I", + nm_device_get_ip_iface(self), + "-c", + "1", + "-w", + NULL, + priv->gw_ping.address, + NULL}; gs_free_error GError *error = NULL; gboolean ret; @@ -13665,10 +13939,38 @@ _get_carrier_wait_ms(NMDevice *self) CARRIER_WAIT_TIME_MS); } +/* + * Devices that support carrier detect must be IFF_UP to report carrier + * changes; so after setting the device IFF_UP we must suppress startup + * complete (via a pending action) until either the carrier turns on, or + * a timeout is reached. + */ +static void +carrier_detect_wait(NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gint64 now_ms, until_ms; + + if (!nm_device_has_capability(self, NM_DEVICE_CAP_CARRIER_DETECT)) + return; + + /* we start a grace period of 5 seconds during which we will schedule + * a pending action whenever we have no carrier. + * + * If during that time carrier goes away, we declare the interface + * as not ready. */ + nm_clear_g_source(&priv->carrier_wait_id); + if (!priv->carrier) + nm_device_add_pending_action(self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); + + now_ms = nm_utils_get_monotonic_timestamp_msec(); + until_ms = NM_MAX(now_ms + _get_carrier_wait_ms(self), priv->carrier_wait_until_ms); + priv->carrier_wait_id = g_timeout_add(until_ms - now_ms, carrier_wait_timeout, self); +} + gboolean nm_device_bring_up(NMDevice *self, gboolean block, gboolean *no_firmware) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); gboolean device_is_up = FALSE; NMDeviceCapabilities capabilities; int ifindex; @@ -13724,27 +14026,7 @@ nm_device_bring_up(NMDevice *self, gboolean block, gboolean *no_firmware) capabilities |= NM_DEVICE_GET_CLASS(self)->get_generic_capabilities(self); _add_capabilities(self, capabilities); - /* Devices that support carrier detect must be IFF_UP to report carrier - * changes; so after setting the device IFF_UP we must suppress startup - * complete (via a pending action) until either the carrier turns on, or - * a timeout is reached. - */ - if (nm_device_has_capability(self, NM_DEVICE_CAP_CARRIER_DETECT)) { - gint64 now_ms, until_ms; - - /* we start a grace period of 5 seconds during which we will schedule - * a pending action whenever we have no carrier. - * - * If during that time carrier goes away, we declare the interface - * as not ready. */ - nm_clear_g_source(&priv->carrier_wait_id); - if (!priv->carrier) - nm_device_add_pending_action(self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); - - now_ms = nm_utils_get_monotonic_timestamp_msec(); - until_ms = NM_MAX(now_ms + _get_carrier_wait_ms(self), priv->carrier_wait_until_ms); - priv->carrier_wait_id = g_timeout_add(until_ms - now_ms, carrier_wait_timeout, self); - } + carrier_detect_wait(self); /* Can only get HW address of some devices when they are up */ nm_device_update_hw_address(self); @@ -14997,6 +15279,9 @@ _cancel_activation(NMDevice *self) _dispatcher_cleanup(self); ip_check_gw_ping_cleanup(self); + _dev_ip_state_cleanup(self, AF_INET, FALSE); + _dev_ip_state_cleanup(self, AF_INET6, FALSE); + /* Break the activation chain */ activation_source_clear(self); } @@ -15500,6 +15785,13 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, if (!nm_device_bring_up(self, TRUE, &no_firmware) && no_firmware) _LOGW(LOGD_PLATFORM, "firmware may be missing."); nm_device_set_firmware_missing(self, no_firmware ? TRUE : FALSE); + } else { + /* We didn't bring the device up and we have little idea + * when was it brought up. Play it safe and assume it could + * have been brought up very recently and it might one of + * those who take time to detect carrier. + */ + carrier_detect_wait(self); } /* Ensure the device gets deactivated in response to stuff like @@ -16804,7 +17096,7 @@ get_address_for_hostname_dns_lookup(NMDevice *self, int addr_family) * opposed to an address that is configured? */ head_entry = nm_platform_lookup( nm_device_get_platform(self), - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex)); + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex)); if (head_entry) { c_list_for_each_entry (iter, &head_entry->lst_entries_head, lst_entries) { diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h index d59aecb2..382c8660 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 ea77dd18..048afb02 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 6ba52f40..5510e39f 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-ovs-factory.c b/src/core/devices/ovs/nm-ovs-factory.c index 5aaa5c01..ff2c7858 100644 --- a/src/core/devices/ovs/nm-ovs-factory.c +++ b/src/core/devices/ovs/nm-ovs-factory.c @@ -178,7 +178,8 @@ ovsdb_device_removed(NMOvsdb *ovsdb, device_state = nm_device_get_state(device); if (device_type == NM_DEVICE_TYPE_OVS_INTERFACE && nm_device_get_act_request(device) - && device_state < NM_DEVICE_STATE_DEACTIVATING) { + && (device_state > NM_DEVICE_STATE_DISCONNECTED + && device_state < NM_DEVICE_STATE_DEACTIVATING)) { nm_device_state_changed(device, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_REMOVED); diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index 44e16cb7..e7c96852 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); @@ -1584,7 +1587,7 @@ ovsdb_got_update(NMOvsdb *self, json_t *msg) json_t *items; json_t *external_ids; json_error_t json_error = { - 0, + 0, }; void *iter; const char *name; @@ -1985,7 +1988,7 @@ ovsdb_got_msg(NMOvsdb *self, json_t *msg) { NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); json_error_t json_error = { - 0, + 0, }; json_t *json_id = NULL; json_int_t id = (json_int_t) -1; @@ -2127,7 +2130,7 @@ ovsdb_read_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) gssize size; json_t *msg; json_error_t json_error = { - 0, + 0, }; size = g_input_stream_read_finish(stream, res, &error); diff --git a/src/core/devices/team/nm-device-team.c b/src/core/devices/team/nm-device-team.c index b67c7100..e6d34266 100644 --- a/src/core/devices/team/nm-device-team.c +++ b/src/core/devices/team/nm-device-team.c @@ -65,6 +65,50 @@ static gboolean teamd_start(NMDeviceTeam *self); /*****************************************************************************/ +static struct teamdctl * +_tdc_connect_new(NMDeviceTeam *self, const char *iface, GError **error) +{ + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + struct teamdctl *tdc; + const char *cli_type; + int r; + + tdc = teamdctl_alloc(); + if (!tdc) { + nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "failure to allocate teamdctl structure"); + g_return_val_if_reached(NULL); + } + + if (priv->teamd_dbus_watch) + cli_type = "dbus"; + else if (priv->usock_monitor) + cli_type = "usock"; + else + cli_type = NULL; + +again: + r = teamdctl_connect(tdc, iface, NULL, cli_type); + if (r != 0) { + _LOGD(LOGD_TEAM, + "failure to connect to teamdctl%s%s, err=%d", + NM_PRINT_FMT_QUOTED2(cli_type, " with cli_type=", cli_type, ""), + r); + if (cli_type) { + /* How odd. Let's retry with any CLI type. */ + cli_type = NULL; + goto again; + } + teamdctl_free(tdc); + nm_utils_error_set(error, + NM_UTILS_ERROR_UNKNOWN, + "failure to connect to teamd (err=%d)", + r); + return NULL; + } + + return tdc; +} + static NMDeviceCapabilities get_generic_capabilities(NMDevice *device) { @@ -96,21 +140,16 @@ complete_connection(NMDevice *device, static gboolean ensure_teamd_connection(NMDevice *device) { - NMDeviceTeam *self = NM_DEVICE_TEAM(device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - int err; + NMDeviceTeam *self = NM_DEVICE_TEAM(device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + gs_free_error GError *error = NULL; if (priv->tdc) return TRUE; - priv->tdc = teamdctl_alloc(); - g_assert(priv->tdc); - err = teamdctl_connect(priv->tdc, nm_device_get_iface(device), NULL, NULL); - if (err != 0) { - _LOGE(LOGD_TEAM, "failed to connect to teamd (err=%d)", err); - teamdctl_free(priv->tdc); - priv->tdc = NULL; - } + priv->tdc = _tdc_connect_new(self, nm_device_get_iface(device), &error); + if (!priv->tdc) + _LOGE(LOGD_TEAM, "failed to connect to teamd: %s", error->message); return !!priv->tdc; } @@ -183,42 +222,31 @@ update_connection(NMDevice *device, NMConnection *connection) /*****************************************************************************/ static gboolean -master_update_slave_connection(NMDevice *self, +master_update_slave_connection(NMDevice *device, NMDevice *slave, NMConnection *connection, GError **error) { - NMSettingTeamPort *s_port; - char *port_config = NULL; - int err = 0; - struct teamdctl *tdc; - const char *team_port_config = NULL; - const char *iface = nm_device_get_iface(self); - const char *iface_slave = nm_device_get_iface(slave); - - tdc = teamdctl_alloc(); + NMDeviceTeam *self = NM_DEVICE_TEAM(device); + NMSettingTeamPort *s_port; + char *port_config = NULL; + gs_free_error GError *connect_error = NULL; + int err = 0; + struct teamdctl *tdc; + const char *team_port_config = NULL; + const char *iface = nm_device_get_iface(device); + const char *iface_slave = nm_device_get_iface(slave); + + tdc = _tdc_connect_new(self, iface, &connect_error); if (!tdc) { g_set_error(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "update slave connection for slave '%s' failed to connect to teamd for master " - "%s (out of memory?)", - iface_slave, - iface); - g_return_val_if_reached(FALSE); - } - - err = teamdctl_connect(tdc, iface, NULL, NULL); - if (err) { - teamdctl_free(tdc); - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "update slave connection for slave '%s' failed to connect to teamd for master " - "%s (err=%d)", + "%s (%s)", iface_slave, iface, - err); + connect_error->message); return FALSE; } @@ -790,19 +818,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 +845,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 +866,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 +875,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 +899,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 +1098,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/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c index 04608d14..39c68d77 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -3180,21 +3180,21 @@ ensure_hotspot_frequency(NMDeviceWifi *self, NMSettingWireless *s_wifi, NMWifiAP gsize ssid_len; const guint8 *ssid_data; const guint8 random_seed[16] = {0x9a, - 0xdc, - 0x86, - 0x9a, - 0xa8, - 0xa2, - 0x07, - 0x97, - 0xbe, - 0x6d, - 0xe6, - 0x99, - 0x9f, - 0xa8, - 0x09, - 0x2b}; + 0xdc, + 0x86, + 0x9a, + 0xa8, + 0xa2, + 0x07, + 0x97, + 0xbe, + 0x6d, + 0xe6, + 0x99, + 0x9f, + 0xa8, + 0x09, + 0x2b}; /* Calculate a stable "random" number based on the SSID. */ ssid = nm_setting_wireless_get_ssid(s_wifi); diff --git a/src/core/devices/wifi/tests/test-devices-wifi.c b/src/core/devices/wifi/tests/test-devices-wifi.c index 69d365e3..a52696ea 100644 --- a/src/core/devices/wifi/tests/test-devices-wifi.c +++ b/src/core/devices/wifi/tests/test-devices-wifi.c @@ -412,8 +412,8 @@ test_ap_wpa_psk_connection_base(const char *key_mgmt, const char *ssid = "blahblah"; const char *bssid = "01:02:03:04:05:06"; const KeyData exp_wifi[] = {{NM_SETTING_WIRELESS_SSID, ssid, 0}, - {NM_SETTING_WIRELESS_MODE, "infrastructure", 0}, - {NULL}}; + {NM_SETTING_WIRELESS_MODE, "infrastructure", 0}, + {NULL}}; const KeyData both_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, key_mgmt, 0}, {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, auth_alg, 0}, {NM_SETTING_WIRELESS_SECURITY_PSK, "asdfasdfasdfasdfasdfafs", 0}, @@ -541,8 +541,8 @@ test_ap_wpa_eap_connection_base(const char *key_mgmt, const char *bssid = "01:02:03:04:05:06"; const KeyData src_empty[] = {{NULL}}; const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, key_mgmt, 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, auth_alg, 0}, - {NULL}}; + {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, auth_alg, 0}, + {NULL}}; gboolean success; GError *error = NULL; @@ -778,12 +778,12 @@ test_priv_ap_leap_connection_1(gconstpointer add_wifi) const char *bssid = "01:02:03:04:05:06"; const char *leap_username = "Bill Smith"; const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, - {NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0}, - {NULL}}; + {NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0}, + {NULL}}; const KeyData exp_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", 0}, - {NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0}, - {NULL}}; + {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", 0}, + {NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0}, + {NULL}}; gboolean success; GError *error = NULL; @@ -862,15 +862,15 @@ test_priv_ap_dynamic_wep_1(void) const char *ssid = "blahblah"; const char *bssid = "01:02:03:04:05:06"; const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, - {NULL}}; + {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, + {NULL}}; const KeyData both_8021x[] = {{NM_SETTING_802_1X_EAP, "peap", 0}, {NM_SETTING_802_1X_IDENTITY, "Bill Smith", 0}, {NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2", 0}, {NULL}}; const KeyData exp_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, - {NULL}}; + {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, + {NULL}}; gboolean success; GError *error = NULL; @@ -917,8 +917,8 @@ test_priv_ap_dynamic_wep_2(void) {NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2", 0}, {NULL}}; const KeyData exp_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, - {NULL}}; + {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, + {NULL}}; gboolean success; GError *error = NULL; @@ -1130,8 +1130,8 @@ test_wpa_ap_leap_connection_1(gconstpointer data) const char *bssid = "01:02:03:04:05:06"; const char *leap_username = "Bill Smith"; const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, - {NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0}, - {NULL}}; + {NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0}, + {NULL}}; gboolean success; GError *error = NULL; diff --git a/src/core/devices/wwan/nm-modem-ofono.c b/src/core/devices/wwan/nm-modem-ofono.c index 0db30046..c003880e 100644 --- a/src/core/devices/wwan/nm-modem-ofono.c +++ b/src/core/devices/wwan/nm-modem-ofono.c @@ -805,7 +805,7 @@ handle_settings(GVariant *v_dict, gpointer user_data) _LOGW("invalid 'Netmask': %s", s ?: ""); goto out; } - address.plen = nm_utils_ip4_netmask_to_prefix(address_network); + address.plen = _nm_utils_ip4_netmask_to_prefix(address_network); _LOGI("Address: %s", nm_platform_ip4_address_to_string(&address, sbuf, sizeof(sbuf))); nm_l3_config_data_add_address_4(priv->l3cd_4, &address); diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index 00a2d207..77cfeecf 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -32,6 +32,38 @@ /*****************************************************************************/ +/* This is how long we do ACD for each entry and reject new offers for + * the same address. Note that the maximum ACD timeout is limited to 30 seconds + * (NM_ACD_TIMEOUT_MAX_MSEC). + **/ +#define ACD_REGLIST_GRACE_PERIOD_MSEC 300000u + +G_STATIC_ASSERT(ACD_REGLIST_GRACE_PERIOD_MSEC > (NM_ACD_TIMEOUT_MAX_MSEC + 1000)); + +#define ACD_REGLIST_MAX_ENTRIES 30 + +/* To do ACD for an address (new lease), we will register a NML3ConfigData + * with l3cfg. After ACD completes, we still continue having NML3Cfg + * watch that address, for ACD_REGLIST_GRACE_PERIOD_MSEC. The reasons are: + * + * - the caller is supposed to actually configure the address right after + * ACD passed. We would not want to drop the ACD state before the caller + * got a chance to do that. + * - when ACD fails, we decline the address and expect the DHCP client + * to present a new lease. We may want to outright reject the address, + * if ACD is bad. Thus, we want to keep running ACD for the address a bit + * longer, so that future requests for the same address can be rejected. + * + * This data structure is used for tracking the registered ACD address. + */ +typedef struct { + const NML3ConfigData *l3cd; + gint64 expiry_msec; + in_addr_t addr; +} AcdRegListData; + +/*****************************************************************************/ + enum { SIGNAL_NOTIFY, LAST_SIGNAL, @@ -42,14 +74,47 @@ static guint signals[LAST_SIGNAL] = {0}; NM_GOBJECT_PROPERTIES_DEFINE(NMDhcpClient, PROP_CONFIG, ); typedef struct _NMDhcpClientPrivate { - NMDhcpClientConfig config; - const NML3ConfigData *l3cd; - GSource *no_lease_timeout_source; - GSource *watch_source; - GBytes *effective_client_id; + NMDhcpClientConfig config; + + /* This is the "next" data. That is, the one what was received last via + * _nm_dhcp_client_notify(), but which is currently pending on ACD. */ + const NML3ConfigData *l3cd_next; + + /* This is the currently exposed data. It passed ACD (or no ACD was performed), + * and is set from l3cd_next. */ + const NML3ConfigData *l3cd_curr; + + GSource *no_lease_timeout_source; + GSource *watch_source; + GBytes *effective_client_id; union { struct { + struct { + NML3CfgCommitTypeHandle *l3cfg_commit_handle; + GSource *done_source; + + /* When we do ACD for a l3cd lease, we will keep running ACD for + * the grace period ACD_REGLIST_GRACE_PERIOD_MSEC, even if we already + * determined the state. There are two reasons for that: + * + * - after ACD completes we notify the lease to the user, who is supposed + * to configure the address in NML3Cfg. If we were already removing the + * ACD state from NML3Cfg, ACD might need to start over. Instead, when + * the caller tries to configure the address, ACD state is already good. + * + * - if we decline on ACD offer, we may want to keep running and + * select other offers. Offers for which we just failed ACD (within + * ACD_REGLIST_GRACE_PERIOD_MSEC) are rejected. See _nm_dhcp_client_accept_offer(). + * For that, we keep monitoring the ACD state for up to ACD_REGLIST_MAX_ENTRIES + * addresses, to not restart and select the same lease twice in a row. + */ + GArray *reglist; + GSource *reglist_timeout_source; + + in_addr_t addr; + NMOptionBool state; + } acd; struct { GDBusMethodInvocation *invocation; } bound; @@ -77,16 +142,22 @@ G_DEFINE_ABSTRACT_TYPE(NMDhcpClient, nm_dhcp_client, G_TYPE_OBJECT) /*****************************************************************************/ +#define L3CD_ACD_TAG(priv) (&(priv)->v4.acd.addr) + static gboolean _dhcp_client_accept(NMDhcpClient *self, const NML3ConfigData *l3cd, GError **error); -_nm_unused static gboolean _dhcp_client_decline(NMDhcpClient *self, - const NML3ConfigData *l3cd, - const char *error_message, - GError **error); +static gboolean _dhcp_client_decline(NMDhcpClient *self, + const NML3ConfigData *l3cd, + const char *error_message, + GError **error); static void l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcpClient *self); +static void _acd_reglist_timeout_reschedule(NMDhcpClient *self, gint64 now_msec); + +static void _acd_reglist_data_remove(NMDhcpClient *self, guint idx, gboolean do_log); + /*****************************************************************************/ /* we use pid=-1 for invalid PIDs. Ensure that pid_t can hold negative values. */ @@ -157,6 +228,16 @@ nm_dhcp_client_get_effective_client_id(NMDhcpClient *self) return priv->effective_client_id; } +NML3ConfigData * +nm_dhcp_client_create_l3cd(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return nm_l3_config_data_new(nm_l3cfg_get_multi_idx(priv->config.l3cfg), + nm_l3cfg_get_ifindex(priv->config.l3cfg), + NM_IP_CONFIG_SOURCE_DHCP); +} + /*****************************************************************************/ void @@ -200,7 +281,8 @@ l3_cfg_notify_check_connected(NMDhcpClient *self) gboolean do_connect; do_connect = priv->l3cfg_notify.wait_dhcp_commit | priv->l3cfg_notify.wait_ll_address - | priv->l3cfg_notify.wait_ipv6_dad; + | priv->l3cfg_notify.wait_ipv6_dad + | (NM_IS_IPv4(priv->config.addr_family) && priv->v4.acd.l3cfg_commit_handle); if (!do_connect) { nm_clear_g_signal_handler(priv->config.l3cfg, &priv->l3cfg_notify.id); @@ -306,6 +388,333 @@ _no_lease_timeout_schedule(NMDhcpClient *self) /*****************************************************************************/ +static void +_acd_state_reset(NMDhcpClient *self, gboolean forget_addr, gboolean forget_reglist) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + if (!NM_IS_IPv4(priv->config.addr_family)) + return; + + if (priv->v4.acd.addr != INADDR_ANY) { + nm_l3cfg_commit_type_clear(priv->config.l3cfg, &priv->v4.acd.l3cfg_commit_handle); + l3_cfg_notify_check_connected(self); + nm_clear_g_source_inst(&priv->v4.acd.done_source); + if (forget_addr) { + priv->v4.acd.addr = INADDR_ANY; + priv->v4.acd.state = NM_OPTION_BOOL_DEFAULT; + } + } else + nm_assert(priv->v4.acd.state == NM_OPTION_BOOL_DEFAULT); + + if (forget_reglist) { + guint n; + + while ((n = nm_g_array_len(priv->v4.acd.reglist)) > 0) + _acd_reglist_data_remove(self, n - 1, TRUE); + } + + nm_assert(!priv->v4.acd.l3cfg_commit_handle); + nm_assert(!priv->v4.acd.done_source); + nm_assert(!forget_reglist + || !nm_l3cfg_remove_config_all(priv->config.l3cfg, L3CD_ACD_TAG(priv))); +} + +static gboolean +_acd_complete_on_idle_cb(gpointer user_data) +{ + NMDhcpClient *self = user_data; + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + nm_assert(NM_IS_IPv4(priv->config.addr_family)); + nm_assert(priv->v4.acd.addr != INADDR_ANY); + nm_assert(!priv->v4.acd.l3cfg_commit_handle); + nm_assert(priv->l3cd_next); + + _acd_state_reset(self, FALSE, FALSE); + + _nm_dhcp_client_notify(self, NM_DHCP_CLIENT_EVENT_TYPE_BOUND, priv->l3cd_next); + + return G_SOURCE_CONTINUE; +} + +#define _acd_reglist_data_get(priv, idx) \ + nm_g_array_index_p((priv)->v4.acd.reglist, AcdRegListData, (idx)) + +static guint +_acd_reglist_data_find(NMDhcpClientPrivate *priv, in_addr_t addr_needle) +{ + const guint n = nm_g_array_len(priv->v4.acd.reglist); + guint i; + + nm_assert(addr_needle != INADDR_ANY); + + for (i = 0; i < n; i++) { + AcdRegListData *reglist_data = _acd_reglist_data_get(priv, i); + + if (reglist_data->addr == addr_needle) + return i; + } + return G_MAXUINT; +} + +static void +_acd_reglist_data_remove(NMDhcpClient *self, guint idx, gboolean do_log) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + AcdRegListData *reglist_data; + + nm_assert(idx < nm_g_array_len(priv->v4.acd.reglist)); + + reglist_data = _acd_reglist_data_get(priv, idx); + + if (do_log) { + char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + + _LOGD("acd: drop check for address %s (l3cd " NM_HASH_OBFUSCATE_PTR_FMT ")", + _nm_utils_inet4_ntop(reglist_data->addr, sbuf_addr), + NM_HASH_OBFUSCATE_PTR(reglist_data->l3cd)); + } + + if (!nm_l3cfg_remove_config(priv->config.l3cfg, L3CD_ACD_TAG(priv), reglist_data->l3cd)) + nm_assert_not_reached(); + + nm_clear_l3cd(®list_data->l3cd); + + nm_l3cfg_commit_on_idle_schedule(priv->config.l3cfg, NM_L3_CFG_COMMIT_TYPE_UPDATE); + + g_array_remove_index(priv->v4.acd.reglist, idx); + + if (priv->v4.acd.reglist->len == 0) { + nm_clear_pointer(&priv->v4.acd.reglist, g_array_unref); + nm_clear_g_source_inst(&priv->v4.acd.reglist_timeout_source); + } +} + +static gboolean +_acd_reglist_timeout_cb(gpointer user_data) +{ + NMDhcpClient *self = user_data; + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + gint64 now_msec; + + nm_clear_g_source_inst(&priv->v4.acd.reglist_timeout_source); + + now_msec = nm_utils_get_monotonic_timestamp_msec(); + + while (nm_g_array_len(priv->v4.acd.reglist) > 0) { + AcdRegListData *reglist_data = _acd_reglist_data_get(priv, 0); + + if (reglist_data->expiry_msec > now_msec) + break; + + _acd_reglist_data_remove(self, 0, TRUE); + } + + _acd_reglist_timeout_reschedule(self, now_msec); + + return G_SOURCE_CONTINUE; +} + +static void +_acd_reglist_timeout_reschedule(NMDhcpClient *self, gint64 now_msec) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + AcdRegListData *reglist_data; + + if (nm_g_array_len(priv->v4.acd.reglist) == 0) { + nm_assert(!priv->v4.acd.reglist_timeout_source); + return; + } + + if (priv->v4.acd.reglist_timeout_source) { + /* already pending. As we only add new elements with a *later* + * expiry, we don't need to ever cancel a pending timer. Worst + * case, the timer fires, and there is nothing to do and we + * reschedule. */ + return; + } + + now_msec = nm_utils_get_monotonic_timestamp_msec(); + + reglist_data = _acd_reglist_data_get(priv, 0); + + nm_assert(reglist_data->expiry_msec > now_msec); + + priv->v4.acd.reglist_timeout_source = + nm_g_timeout_add_source(reglist_data->expiry_msec - now_msec, + _acd_reglist_timeout_cb, + self); +} + +static void +_acd_check_lease(NMDhcpClient *self, NMOptionBool *out_acd_state) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + in_addr_t addr; + gboolean addr_changed = FALSE; + guint idx; + gint64 now_msec; + + if (!NM_IS_IPv4(priv->config.addr_family)) + goto handle_no_acd; + + if (!priv->l3cd_next) + goto handle_no_acd; + + /* an IPv4 lease is always expected to have exactly one address. */ + nm_assert(nm_l3_config_data_get_num_addresses(priv->l3cd_next, AF_INET) == 1); + + if (priv->config.v4.acd_timeout_msec == 0) + goto handle_no_acd; + + addr = NMP_OBJECT_CAST_IP4_ADDRESS( + nm_l3_config_data_get_first_obj(priv->l3cd_next, NMP_OBJECT_TYPE_IP4_ADDRESS, NULL)) + ->address; + nm_assert(addr != INADDR_ANY); + + nm_clear_g_source_inst(&priv->v4.acd.done_source); + + if (priv->v4.acd.state != NM_OPTION_BOOL_DEFAULT && priv->v4.acd.addr == addr) { + /* the ACD state is already determined. Return right away. */ + nm_assert(!priv->v4.acd.l3cfg_commit_handle); + *out_acd_state = !!priv->v4.acd.state; + return; + } + + if (priv->v4.acd.addr != addr) { + addr_changed = TRUE; + priv->v4.acd.addr = addr; + } + + _LOGD("acd: %s check for address %s (timeout %u msec, l3cd " NM_HASH_OBFUSCATE_PTR_FMT ")", + addr_changed ? "add" : "update", + _nm_utils_inet4_ntop(addr, sbuf_addr), + priv->config.v4.acd_timeout_msec, + NM_HASH_OBFUSCATE_PTR(priv->l3cd_next)); + + priv->v4.acd.state = NM_OPTION_BOOL_DEFAULT; + + if (nm_l3cfg_add_config(priv->config.l3cfg, + L3CD_ACD_TAG(priv), + FALSE, + priv->l3cd_next, + NM_L3CFG_CONFIG_PRIORITY_IPV4LL, + 0, + 0, + NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4, + NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6, + 0, + 0, + NM_DNS_PRIORITY_DEFAULT_NORMAL, + NM_DNS_PRIORITY_DEFAULT_NORMAL, + NM_L3_ACD_DEFEND_TYPE_ONCE, + NM_MIN(priv->config.v4.acd_timeout_msec, NM_ACD_TIMEOUT_MAX_MSEC), + NM_L3CFG_CONFIG_FLAGS_ONLY_FOR_ACD, + NM_L3_CONFIG_MERGE_FLAGS_NONE)) + addr_changed = TRUE; + + if (!priv->v4.acd.reglist) + priv->v4.acd.reglist = g_array_new(FALSE, FALSE, sizeof(AcdRegListData)); + + idx = _acd_reglist_data_find(priv, addr); + + now_msec = nm_utils_get_monotonic_timestamp_msec(); + + g_array_append_val(priv->v4.acd.reglist, + ((AcdRegListData){ + .l3cd = nm_l3_config_data_ref(priv->l3cd_next), + .addr = addr, + .expiry_msec = now_msec + ACD_REGLIST_GRACE_PERIOD_MSEC, + })); + + if (idx != G_MAXUINT) { + /* we already tracked this "addr". We don't need to track it twice, + * forget about this one. This also has the effect, that we will + * always append the new entry to the list (so the list + * stays sorted by the increasing timestamp). */ + _acd_reglist_data_remove(self, idx, FALSE); + } + + if (priv->v4.acd.reglist->len > ACD_REGLIST_MAX_ENTRIES) { + /* rate limit how many addresses we track for ACD. */ + _acd_reglist_data_remove(self, 0, TRUE); + } + + _acd_reglist_timeout_reschedule(self, now_msec); + + if (!priv->v4.acd.l3cfg_commit_handle) { + priv->v4.acd.l3cfg_commit_handle = + nm_l3cfg_commit_type_register(priv->config.l3cfg, + NM_L3_CFG_COMMIT_TYPE_UPDATE, + NULL, + "dhcp4-acd"); + l3_cfg_notify_check_connected(self); + } + + if (addr_changed) + nm_l3cfg_commit_on_idle_schedule(priv->config.l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO); + + /* ACD is started/pending... */ + nm_assert(priv->v4.acd.addr != INADDR_ANY); + nm_assert(priv->v4.acd.state == NM_OPTION_BOOL_DEFAULT); + nm_assert(priv->v4.acd.l3cfg_commit_handle); + nm_assert(priv->l3cfg_notify.id); + *out_acd_state = NM_OPTION_BOOL_DEFAULT; + return; + +handle_no_acd: + /* Indicate that ACD is good (or disabled) by returning TRUE. */ + _acd_state_reset(self, TRUE, FALSE); + *out_acd_state = NM_OPTION_BOOL_TRUE; + return; +} + +/*****************************************************************************/ + +gboolean +_nm_dhcp_client_accept_offer(NMDhcpClient *self, gconstpointer p_yiaddr) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + NMIPAddr yiaddr; + const NML3AcdAddrInfo *acd_info; + + if (!NM_IS_IPv4(priv->config.addr_family)) + return nm_assert_unreachable_val(FALSE); + + if (priv->config.v4.acd_timeout_msec == 0) { + /* ACD is disabled. Note that we might track the address for other + * reasons and have information about the ACD state below. But + * with ACD disabled, we always ignore that information. */ + return TRUE; + } + + nm_ip_addr_set(priv->config.addr_family, &yiaddr, p_yiaddr); + + /* Note that once we do ACD for a certain address, even after completing + * it, we keep the l3cd registered in NML3Cfg for ACD_REGLIST_GRACE_PERIOD_MSEC + * The idea is, that we don't yet turn off ACD for a grace period, so that + * we can avoid selecting the same lease again. + * + * Note that we even check whether we have an ACD state if priv->v4.acd.reglist + * is empty. Maybe for odd reasons, we track ACD for the address already. */ + + acd_info = nm_l3cfg_get_acd_addr_info(priv->config.l3cfg, yiaddr.addr4); + + if (!acd_info) + return TRUE; + + if (!NM_IN_SET(acd_info->state, NM_L3_ACD_ADDR_STATE_USED, NM_L3_ACD_ADDR_STATE_CONFLICT)) + return TRUE; + + _LOGD("offered lease rejected: address %s failed ACD check", + _nm_utils_inet4_ntop(yiaddr.addr4, sbuf_addr)); + + return FALSE; +} + void _nm_dhcp_client_notify(NMDhcpClient *self, NMDhcpClientEventType client_event_type, @@ -313,6 +722,8 @@ _nm_dhcp_client_notify(NMDhcpClient *self, { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); GHashTable *options; + gboolean l3cd_changed; + NMOptionBool acd_state; const int IS_IPv4 = NM_IS_IPv4(priv->config.addr_family); nm_auto_unref_l3cd const NML3ConfigData *l3cd_merged = NULL; char sbuf1[NM_HASH_OBFUSCATE_PTR_STR_BUF_SIZE]; @@ -343,8 +754,7 @@ _nm_dhcp_client_notify(NMDhcpClient *self, nm_dhcp_client_event_type_to_string(client_event_type), NM_PRINT_FMT_QUOTED2(l3cd, ", l3cd=", NM_HASH_OBFUSCATE_PTR_STR(l3cd, sbuf1), "")); - if (l3cd) - nm_l3_config_data_seal(l3cd); + nm_l3_config_data_seal(l3cd); if (client_event_type >= NM_DHCP_CLIENT_EVENT_TYPE_TIMEOUT) watch_cleanup(self); @@ -353,33 +763,40 @@ _nm_dhcp_client_notify(NMDhcpClient *self, /* nm_dhcp_utils_merge_new_dhcp6_lease() relies on "life_starts" option * for merging, which is only set by dhclient. Internal client never sets that, * but it supports multiple IP addresses per lease. */ - if (nm_dhcp_utils_merge_new_dhcp6_lease(priv->l3cd, l3cd, &l3cd_merged)) { + if (nm_dhcp_utils_merge_new_dhcp6_lease(priv->l3cd_next, l3cd, &l3cd_merged)) { + _LOGD("lease merged with existing one"); l3cd = nm_l3_config_data_seal(l3cd_merged); } } - if (priv->l3cd == l3cd) - return; - if (l3cd) { nm_clear_g_source_inst(&priv->no_lease_timeout_source); - } else { - if (priv->l3cd) - _no_lease_timeout_schedule(self); - } + } else + _no_lease_timeout_schedule(self); - /* FIXME(l3cfg:dhcp): the API of NMDhcpClient is changing to expose a simpler API. - * The internals like the state should not be exposed (or possibly dropped in large - * parts). */ + l3cd_changed = nm_l3_config_data_reset(&priv->l3cd_next, l3cd); - nm_l3_config_data_reset(&priv->l3cd, l3cd); + _acd_check_lease(self, &acd_state); - options = l3cd ? nm_dhcp_lease_get_options( - nm_l3_config_data_get_dhcp_lease(l3cd, priv->config.addr_family)) - : NULL; + options = priv->l3cd_next ? nm_dhcp_lease_get_options( + nm_l3_config_data_get_dhcp_lease(priv->l3cd_next, priv->config.addr_family)) + : NULL; + + if (_LOGI_ENABLED()) { + const char *req_str = + IS_IPv4 ? nm_dhcp_option_request_string(AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS) + : nm_dhcp_option_request_string(AF_INET6, NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS); + const char *addr = nm_g_hash_table_lookup(options, req_str); + + _LOGI("state changed %s%s%s%s", + priv->l3cd_next ? "new lease" : "no lease", + NM_PRINT_FMT_QUOTED2(addr, ", address=", addr, ""), + acd_state == NM_OPTION_BOOL_DEFAULT ? ", acd pending" + : (acd_state ? "" : ", acd conflict")); + } if (_LOGD_ENABLED()) { - if (options) { + if (l3cd_changed && options) { gs_free const char **keys = NULL; guint nkeys; guint i; @@ -390,58 +807,41 @@ _nm_dhcp_client_notify(NMDhcpClient *self, 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); - } } } - if (_LOGI_ENABLED()) { - const char *req_str = - IS_IPv4 ? nm_dhcp_option_request_string(AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS) - : nm_dhcp_option_request_string(AF_INET6, NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS); - const char *addr = nm_g_hash_table_lookup(options, req_str); + if (acd_state == NM_OPTION_BOOL_DEFAULT) { + /* ACD is in progress... */ + return; + } - _LOGI("state changed %s%s%s%s", - priv->l3cd ? "new lease" : "no lease", - NM_PRINT_FMT_QUOTED(addr, ", address=", addr, "", "")); + if (!acd_state) { + gs_free_error GError *error = NULL; + + /* We only decline. We don't actually emit to the caller that + * something is wrong (like NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD). + * If we would, NMDevice might decide to tear down the device, when + * we actually should continue trying to get a better lease. There + * is already "ipv4.dhcp-timeout" which will handle the failure if + * we don't get a good lease. */ + if (!_dhcp_client_decline(self, priv->l3cd_next, "acd failed", &error)) + _LOGD("decline failed: %s", error->message); + return; } - /* FIXME(l3cfg:dhcp:acd): NMDhcpClient must also do ACD. It needs acd_timeout_msec - * as a configuration parameter (in NMDhcpClientConfig). When ACD is enabled, - * when a new lease gets announced, it must first use NML3Cfg to run ACD on the - * interface (the previous lease -- if any -- will still be used at that point). - * If ACD fails, we call _dhcp_client_decline() and try to get a different - * lease. - * If ACD passes, we need to notify the new lease, and the user (NMDevice) may - * then configure the address. We need to watch the configured addresses (in NML3Cfg), - * and if the address appears there, we need to accept the lease. That is complicated - * but necessary, because we can only accept the lease after we configured the - * address. - * - * As a whole, ACD is transparent for the user (NMDevice). It's entirely managed - * by NMDhcpClient. Note that we do ACD through NML3Cfg, which centralizes IP handling - * for one interface, so for example if the same address happens to be configured - * as a static address (bypassing ACD), then NML3Cfg is aware of that and signals - * immediate success. */ - - if (client_event_type == NM_DHCP_CLIENT_EVENT_TYPE_BOUND && priv->l3cd - && nm_l3_config_data_get_num_addresses(priv->l3cd, priv->config.addr_family) > 0) { + nm_l3_config_data_reset(&priv->l3cd_curr, priv->l3cd_next); + + if (client_event_type == NM_DHCP_CLIENT_EVENT_TYPE_BOUND && priv->l3cd_curr + && nm_l3_config_data_get_num_addresses(priv->l3cd_curr, priv->config.addr_family) > 0) priv->l3cfg_notify.wait_dhcp_commit = TRUE; - } else { + else priv->l3cfg_notify.wait_dhcp_commit = FALSE; - } - if (!priv->l3cfg_notify.wait_dhcp_commit && priv->l3cd) { + if (!priv->l3cfg_notify.wait_dhcp_commit && priv->l3cd_curr) { gs_free_error GError *error = NULL; _LOGD("accept lease right away"); - if (!_dhcp_client_accept(self, priv->l3cd, &error)) { + if (!_dhcp_client_accept(self, priv->l3cd_curr, &error)) { _LOGD("accept failed: %s", error->message); /* Unclear why this happened, or what to do about it. Just proceed. */ } @@ -454,7 +854,7 @@ _nm_dhcp_client_notify(NMDhcpClient *self, .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, .lease_update = { - .l3cd = priv->l3cd, + .l3cd = priv->l3cd_curr, .accepted = !priv->l3cfg_notify.wait_dhcp_commit, }, }; @@ -529,7 +929,7 @@ _dhcp_client_accept(NMDhcpClient *self, const NML3ConfigData *l3cd, GError **err klass = NM_DHCP_CLIENT_GET_CLASS(self); - g_return_val_if_fail(NM_DHCP_CLIENT_GET_PRIVATE(self)->l3cd, FALSE); + g_return_val_if_fail(NM_DHCP_CLIENT_GET_PRIVATE(self)->l3cd_curr, FALSE); return klass->accept(self, l3cd, error); } @@ -569,7 +969,7 @@ _dhcp_client_decline(NMDhcpClient *self, klass = NM_DHCP_CLIENT_GET_CLASS(self); - g_return_val_if_fail(NM_DHCP_CLIENT_GET_PRIVATE(self)->l3cd, FALSE); + g_return_val_if_fail(NM_DHCP_CLIENT_GET_PRIVATE(self)->l3cd_next, FALSE); return klass->decline(self, l3cd, error_message, error); } @@ -626,7 +1026,9 @@ ipv6_lladdr_find(NMDhcpClient *self) nm_assert(!NM_IS_IPv4(priv->config.addr_family)); l3cfg = priv->config.l3cfg; - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, nm_l3cfg_get_ifindex(l3cfg)); + nmp_lookup_init_object_by_ifindex(&lookup, + NMP_OBJECT_TYPE_IP6_ADDRESS, + nm_l3cfg_get_ifindex(l3cfg)); nm_platform_iter_obj_for_each (&iter, nm_l3cfg_get_platform(l3cfg), &lookup, &obj) { const NMPlatformIP6Address *pladdr = NMP_OBJECT_CAST_IP6_ADDRESS(obj); @@ -651,7 +1053,7 @@ ipv6_tentative_addr_find(NMDhcpClient *self) /* For each address in the lease, check whether it's tentative * in platform. */ - nm_l3_config_data_iter_ip6_address_for_each (&iter, priv->l3cd, &addr) { + nm_l3_config_data_iter_ip6_address_for_each (&iter, priv->l3cd_curr, &addr) { const NMPlatformIP6Address *pladdr; NMPObject needle; @@ -676,6 +1078,7 @@ static void l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcpClient *self) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; nm_assert(l3cfg == priv->config.l3cfg); @@ -717,7 +1120,7 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp self, &((NMDhcpClientNotifyData){.notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, .lease_update = { - .l3cd = priv->l3cd, + .l3cd = priv->l3cd_curr, .accepted = TRUE, }})); } @@ -736,7 +1139,7 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp * lease and notifying NMDevice. */ nm_l3_config_data_iter_ip_address_for_each (&ipconf_iter, - priv->l3cd, + priv->l3cd_curr, priv->config.addr_family, &lease_address) break; @@ -778,9 +1181,11 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp _LOGD("accept lease"); - if (!_dhcp_client_accept(self, priv->l3cd, &error)) { + if (!_dhcp_client_accept(self, priv->l3cd_curr, &error)) { gs_free char *reason = g_strdup_printf("error accepting lease: %s", error->message); + _LOGD("accept failed: %s", error->message); + _emit_notify(self, &((NMDhcpClientNotifyData){ .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, @@ -794,12 +1199,54 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp self, &((NMDhcpClientNotifyData){.notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, .lease_update = { - .l3cd = priv->l3cd, + .l3cd = priv->l3cd_curr, .accepted = TRUE, }})); } } -wait_dhcp_commit_done:; +wait_dhcp_commit_done: + + if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT + && priv->v4.acd.l3cfg_commit_handle) { + nm_assert(priv->v4.acd.addr != INADDR_ANY); + nm_assert(priv->v4.acd.state == NM_OPTION_BOOL_DEFAULT); + nm_assert(!priv->v4.acd.done_source); + + if (priv->v4.acd.addr == notify_data->acd_event.info.addr + && nm_l3_acd_addr_info_find_track_info(¬ify_data->acd_event.info, + L3CD_ACD_TAG(priv), + NULL, + NULL)) { + NMOptionBool acd_state; + + switch (notify_data->acd_event.info.state) { + default: + nm_assert_not_reached(); + /* fall-through */ + case NM_L3_ACD_ADDR_STATE_INIT: + case NM_L3_ACD_ADDR_STATE_PROBING: + acd_state = NM_OPTION_BOOL_DEFAULT; + break; + case NM_L3_ACD_ADDR_STATE_USED: + case NM_L3_ACD_ADDR_STATE_CONFLICT: + case NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED: + acd_state = NM_OPTION_BOOL_FALSE; + break; + case NM_L3_ACD_ADDR_STATE_READY: + case NM_L3_ACD_ADDR_STATE_DEFENDING: + acd_state = NM_OPTION_BOOL_TRUE; + break; + } + if (acd_state != NM_OPTION_BOOL_DEFAULT) { + _LOGD("acd: acd %s for %s", + acd_state ? "ready" : "conflict", + _nm_utils_inet4_ntop(priv->v4.acd.addr, sbuf_addr)); + nm_l3cfg_commit_type_clear(priv->config.l3cfg, &priv->v4.acd.l3cfg_commit_handle); + priv->v4.acd.state = acd_state; + priv->v4.acd.done_source = nm_g_idle_add_source(_acd_complete_on_idle_cb, self); + } + } + } } gboolean @@ -928,6 +1375,8 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release) "dhcp stopping"); } + _acd_state_reset(self, TRUE, TRUE); + priv->l3cfg_notify.wait_dhcp_commit = FALSE; priv->l3cfg_notify.wait_ll_address = FALSE; priv->l3cfg_notify.wait_ipv6_dad = FALSE; @@ -942,6 +1391,9 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release) _LOGI("canceled DHCP transaction"); nm_assert(priv->pid == -1); + nm_clear_l3cd(&priv->l3cd_next); + nm_clear_l3cd(&priv->l3cd_curr); + _nm_dhcp_client_notify(self, NM_DHCP_CLIENT_EVENT_TYPE_TERMINATED, NULL); } @@ -951,37 +1403,31 @@ static char * bytearray_variant_to_string(NMDhcpClient *self, GVariant *value, const char *key) { const guint8 *array; + char *str; gsize length; - GString *str; - int i; - unsigned char c; - char *converted = NULL; + gsize i; - g_return_val_if_fail(value != NULL, NULL); + nm_assert(value); array = g_variant_get_fixed_array(value, &length, 1); - /* Since the DHCP options come through environment variables, they should - * already be UTF-8 safe, but just make sure. + /* Since the DHCP options come originally came as environment variables, they + * have not guaranteed encoding. Let's only accept ASCII here. */ - str = g_string_sized_new(length); + str = g_malloc(length + 1); for (i = 0; i < length; i++) { - c = array[i]; + guint8 c = array[i]; - /* Convert NULLs to spaces and non-ASCII characters to ? */ if (c == '\0') - c = ' '; + str[i] = ' '; else if (c > 127) - c = '?'; - str = g_string_append_c(str, c); + str[i] = '?'; + else + str[i] = (char) c; } - str = g_string_append_c(str, '\0'); + str[i] = '\0'; - converted = str->str; - if (!g_utf8_validate(converted, -1, NULL)) - _LOGW("option '%s' couldn't be converted to UTF-8", key); - g_string_free(str, FALSE); - return converted; + return str; } static int @@ -1004,11 +1450,13 @@ label_is_unknown_xyz(const char *label) static void maybe_add_option(NMDhcpClient *self, GHashTable *hash, const char *key, GVariant *value) { - char *str_value = NULL; + char *str_value; + int priv_opt_num; - g_return_if_fail(g_variant_is_of_type(value, G_VARIANT_TYPE_BYTESTRING)); + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BYTESTRING)) + return; - if (g_str_has_prefix(key, OLD_TAG)) + if (NM_STR_HAS_PREFIX(key, OLD_TAG)) return; /* Filter out stuff that's not actually new DHCP options */ @@ -1021,34 +1469,33 @@ maybe_add_option(NMDhcpClient *self, GHashTable *hash, const char *key, GVariant return; str_value = bytearray_variant_to_string(self, value, key); - if (str_value) { - int priv_opt_num; + if (!str_value) + return; - g_hash_table_insert(hash, g_strdup(key), str_value); + g_hash_table_insert(hash, g_strdup(key), str_value); - /* dhclient has no special labels for private dhcp options: it uses "unknown_xyz" + /* dhclient has no special labels for private dhcp options: it uses "unknown_xyz" * labels for that. We need to identify those to alias them to our "private_xyz" * format unused in the internal dchp plugins. */ - if ((priv_opt_num = label_is_unknown_xyz(key)) > 0) { - gs_free guint8 *check_val = NULL; - char *hex_str = NULL; - gsize len; + if ((priv_opt_num = label_is_unknown_xyz(key)) > 0) { + gs_free guint8 *check_val = NULL; + char *hex_str = NULL; + gsize len; - /* dhclient passes values from dhcp private options in its own "string" format: + /* dhclient passes values from dhcp private options in its own "string" format: * if the raw values are printable as ascii strings, it will pass the string * representation; if the values are not printable as an ascii string, it will * pass a string displaying the hex values (hex string). Try to enforce passing * always an hex string, converting string representation if needed. */ - check_val = nm_utils_hexstr2bin_alloc(str_value, FALSE, TRUE, ":", 0, &len); - hex_str = nm_utils_bin2hexstr_full(check_val ?: (guint8 *) str_value, - check_val ? len : strlen(str_value), - ':', - FALSE, - NULL); - g_hash_table_insert(hash, g_strdup_printf("private_%d", priv_opt_num), hex_str); - } + check_val = nm_utils_hexstr2bin_alloc(str_value, FALSE, TRUE, ":", 0, &len); + hex_str = nm_utils_bin2hexstr_full(check_val ?: (guint8 *) str_value, + check_val ? len : strlen(str_value), + ':', + FALSE, + NULL); + g_hash_table_insert(hash, g_strdup_printf("private_%d", priv_opt_num), hex_str); } } @@ -1079,8 +1526,9 @@ nm_dhcp_client_handle_event(gpointer unused, nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; NMDhcpClientEventType client_event_type; NMPlatformIP6Address prefix = { - 0, + 0, }; + int IS_IPv4; g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); g_return_val_if_fail(iface != NULL, FALSE); @@ -1091,6 +1539,8 @@ nm_dhcp_client_handle_event(gpointer unused, priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + g_return_val_if_fail(!priv->is_stopped, FALSE); + if (!nm_streq0(priv->config.iface, iface)) return FALSE; if (priv->pid != pid) @@ -1175,10 +1625,12 @@ nm_dhcp_client_handle_event(gpointer unused, client_event_type = NM_DHCP_CLIENT_EVENT_TYPE_FAIL; } - if (priv->v4.bound.invocation) + IS_IPv4 = NM_IS_IPv4(priv->config.addr_family); + + if (IS_IPv4 && priv->v4.bound.invocation) g_dbus_method_invocation_return_value(g_steal_pointer(&priv->v4.bound.invocation), NULL); - if (NM_IS_IPv4(priv->config.addr_family) + if (IS_IPv4 && NM_IN_SET(client_event_type, NM_DHCP_CLIENT_EVENT_TYPE_BOUND, NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED)) @@ -1202,23 +1654,23 @@ nm_dhcp_client_server_id_is_rejected(NMDhcpClient *self, gconstpointer addr) /* IPv6 not implemented yet */ nm_assert(priv->config.addr_family == AF_INET); - if (!priv->config.reject_servers || !priv->config.reject_servers[0]) - return FALSE; - - for (i = 0; priv->config.reject_servers[i]; i++) { - in_addr_t r_addr; - in_addr_t mask; - int r_prefix; - - if (!nm_utils_parse_inaddr_prefix_bin(AF_INET, - priv->config.reject_servers[i], - NULL, - &r_addr, - &r_prefix)) - nm_assert_not_reached(); - mask = _nm_utils_ip4_prefix_to_netmask(r_prefix < 0 ? 32 : r_prefix); - if ((addr4 & mask) == (r_addr & mask)) - return TRUE; + if (priv->config.reject_servers) { + for (i = 0; priv->config.reject_servers[i]; i++) { + in_addr_t r_addr; + in_addr_t mask; + int r_prefix; + + if (!nm_utils_parse_inaddr_prefix_bin(AF_INET, + priv->config.reject_servers[i], + NULL, + &r_addr, + &r_prefix)) + nm_assert_not_reached(); + + mask = _nm_utils_ip4_prefix_to_netmask(r_prefix < 0 ? 32 : r_prefix); + if ((addr4 & mask) == (r_addr & mask)) + return TRUE; + } } return FALSE; @@ -1251,7 +1703,7 @@ config_init(NMDhcpClientConfig *config, const NMDhcpClientConfig *src) config->hostname = g_strdup(config->hostname); config->mud_url = g_strdup(config->mud_url); - config->reject_servers = (const char *const *) nm_strv_dup(config->reject_servers, -1, TRUE); + config->reject_servers = nm_strv_dup_packed(config->reject_servers, -1); if (NM_IS_IPv4(config->addr_family)) config->v4.last_address = g_strdup(config->v4.last_address); @@ -1284,7 +1736,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), @@ -1310,8 +1762,7 @@ config_clear(NMDhcpClientConfig *config) nm_clear_g_free((gpointer *) &config->anycast_address); nm_clear_g_free((gpointer *) &config->hostname); nm_clear_g_free((gpointer *) &config->mud_url); - - nm_clear_pointer((gpointer *) &config->reject_servers, g_strfreev); + nm_clear_g_free((gpointer *) &config->reject_servers); if (config->addr_family == AF_INET) { nm_clear_g_free((gpointer *) &config->v4.last_address); @@ -1338,6 +1789,13 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps { .invocation = NULL, }, + .acd = + { + .addr = INADDR_ANY, + .state = NM_OPTION_BOOL_DEFAULT, + .l3cfg_commit_handle = NULL, + .done_source = NULL, + }, }; } else { priv->v6 = (typeof(priv->v6)){ @@ -1383,6 +1841,11 @@ dispose(GObject *object) nm_clear_pointer(&priv->effective_client_id, g_bytes_unref); + nm_assert(!priv->watch_source); + nm_assert(!priv->l3cd_next); + nm_assert(!priv->l3cd_curr); + nm_assert(priv->l3cfg_notify.id == 0); + G_OBJECT_CLASS(nm_dhcp_client_parent_class)->dispose(object); } diff --git a/src/core/dhcp/nm-dhcp-client.h b/src/core/dhcp/nm-dhcp-client.h index e4b99929..51c6bc04 100644 --- a/src/core/dhcp/nm-dhcp-client.h +++ b/src/core/dhcp/nm-dhcp-client.h @@ -150,6 +150,10 @@ typedef struct { /* The address from the previous lease */ const char *last_address; + /* Whether to do ACD for the DHCPv4 address. With timeout zero, ACD + * is disabled. */ + guint acd_timeout_msec; + /* Set BOOTP broadcast flag in request packets, so that servers * will always broadcast replies. */ bool request_broadcast : 1; @@ -261,6 +265,8 @@ void _nm_dhcp_client_notify(NMDhcpClient *self, NMDhcpClientEventType client_event_type, const NML3ConfigData *l3cd); +gboolean _nm_dhcp_client_accept_offer(NMDhcpClient *self, gconstpointer p_yiaddr); + gboolean nm_dhcp_client_handle_event(gpointer unused, const char *iface, int pid, @@ -282,6 +288,8 @@ int nm_dhcp_client_get_ifindex(NMDhcpClient *self); void nm_dhcp_client_set_effective_client_id(NMDhcpClient *self, GBytes *client_id); GBytes *nm_dhcp_client_get_effective_client_id(NMDhcpClient *self); +NML3ConfigData *nm_dhcp_client_create_l3cd(NMDhcpClient *self); + /***************************************************************************** * Client data *****************************************************************************/ diff --git a/src/core/dhcp/nm-dhcp-helper.c b/src/core/dhcp/nm-dhcp-helper.c index aab658a2..5a17f4e8 100644 --- a/src/core/dhcp/nm-dhcp-helper.c +++ b/src/core/dhcp/nm-dhcp-helper.c @@ -103,14 +103,17 @@ next:; int main(int argc, char *argv[]) { - gs_unref_object GDBusConnection *connection = NULL; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *parameters = NULL; - gs_unref_variant GVariant *result = NULL; - gboolean success = FALSE; + gs_unref_object GDBusConnection *connection = NULL; + gs_free_error GError *error = NULL; + gs_free_error GError *error_flush = NULL; + gs_unref_variant GVariant *parameters = NULL; + gs_unref_variant GVariant *result = NULL; + gs_free char *s_err = NULL; + gboolean success; guint try_count; gint64 time_start; gint64 time_end; + gint64 remaining_time; /* Connecting to the unix socket can fail with EAGAIN if there are too * many pending connections and the server can't accept them in time @@ -121,6 +124,8 @@ main(int argc, char *argv[]) time_end = time_start + (5000 * 1000L); try_count = 0; + _LOGi("nm-dhcp-helper: event called"); + do_connect: try_count++; connection = @@ -131,16 +136,16 @@ do_connect: &error); if (!connection) { if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { - gint64 time_remaining = time_end - g_get_monotonic_time(); - gint64 interval; + remaining_time = time_end - g_get_monotonic_time(); + if (remaining_time > 0) { + gint64 interval; - if (time_remaining > 0) { _LOGi("failure to connect: %s (retry %u, waited %lld ms)", error->message, try_count, - (long long) (time_end - time_remaining - time_start) / 1000); + (long long) (time_end - remaining_time - time_start) / 1000); interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31))), 5000, 100000); - g_usleep(NM_MIN(interval, time_remaining)); + g_usleep(NM_MIN(interval, remaining_time)); g_clear_error(&error); goto do_connect; } @@ -148,6 +153,7 @@ do_connect: g_dbus_error_strip_remote_error(error); _LOGE("could not connect to NetworkManager D-Bus socket: %s", error->message); + success = FALSE; goto out; } @@ -169,57 +175,74 @@ do_notify: NULL, &error); - if (!result) { - gs_free char *s_err = NULL; + if (result) { + success = TRUE; + goto out; + } - s_err = g_dbus_error_get_remote_error(error); - if (NM_IN_STRSET(s_err, "org.freedesktop.DBus.Error.UnknownMethod")) { - gint64 remaining_time = time_end - g_get_monotonic_time(); - gint64 interval; + s_err = g_dbus_error_get_remote_error(error); - /* I am not sure that a race can actually happen, as we register the object - * on the server side during GDBusServer:new-connection signal. - * - * However, there was also a race for subscribing to an event, so let's just - * do some retry. */ - if (remaining_time > 0) { - _LOGi("failure to call notify: %s (retry %u)", error->message, try_count); - interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31))), 5000, 25000); - g_usleep(NM_MIN(interval, remaining_time)); - g_clear_error(&error); - goto do_notify; - } - } + if (NM_IN_STRSET(s_err, "org.freedesktop.NetworkManager.Device.Failed")) { + _LOGi("notify failed with reason: %s", error->message); + success = FALSE; + goto out; + } + + if (!NM_IN_STRSET(s_err, "org.freedesktop.DBus.Error.UnknownMethod")) { + /* Some unexpected error. We treat that as a failure. In particular, + * the daemon will fail the request if ACD fails. This causes nm-dhcp-helper + * to fail, which in turn causes dhclient to send a DECLINE. */ _LOGW("failure to call notify: %s (try signal via Event)", error->message); + success = FALSE; + goto out; + } + + /* I am not sure that a race can actually happen, as we register the object + * on the server side during GDBusServer:new-connection signal. + * + * However, there was also a race for subscribing to an event, so let's just + * do some retry. */ + remaining_time = time_end - g_get_monotonic_time(); + if (remaining_time > 0) { + gint64 interval; + + _LOGi("failure to call notify: %s (retry %u)", error->message, try_count); + interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31))), 5000, 25000); + g_usleep(NM_MIN(interval, remaining_time)); g_clear_error(&error); + goto do_notify; + } - /* for backward compatibility, try to emit the signal. There is no stable - * API between the dhcp-helper and NetworkManager. However, while upgrading - * the NetworkManager package, a newer helper might want to notify an - * older server, which still uses the "Event". */ - if (!g_dbus_connection_emit_signal(connection, - NULL, - "/", - NM_DHCP_CLIENT_DBUS_IFACE, - "Event", - parameters, - &error)) { - g_dbus_error_strip_remote_error(error); - _LOGE("could not send DHCP Event signal: %s", error->message); - goto out; - } + /* for backward compatibility, try to emit the signal. There is no stable + * API between the dhcp-helper and NetworkManager. However, while upgrading + * the NetworkManager package, a newer helper might want to notify an + * older server, which still uses the "Event". */ + + _LOGW("failure to call notify: %s (try signal via Event)", error->message); + g_clear_error(&error); + + if (g_dbus_connection_emit_signal(connection, + NULL, + "/", + NM_DHCP_CLIENT_DBUS_IFACE, + "Event", + parameters, + &error)) { /* We were able to send the asynchronous Event. Consider that a success. */ success = TRUE; - } else - success = TRUE; - - if (!g_dbus_connection_flush_sync(connection, NULL, &error)) { - g_dbus_error_strip_remote_error(error); - _LOGE("could not flush D-Bus connection: %s", error->message); - success = FALSE; goto out; } + g_dbus_error_strip_remote_error(error); + _LOGE("could not send DHCP Event signal: %s", error->message); + success = FALSE; + out: + if (!g_dbus_connection_flush_sync(connection, NULL, &error_flush)) { + _LOGE("could not flush D-Bus connection: %s", error_flush->message); + /* if we considered this a success so far, don't fail because of this. */ + } + + _LOGi("success: %s", success ? "YES" : "NO"); return success ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/core/dhcp/nm-dhcp-manager.c b/src/core/dhcp/nm-dhcp-manager.c index 9fea1666..cfff23f8 100644 --- a/src/core/dhcp/nm-dhcp-manager.c +++ b/src/core/dhcp/nm-dhcp-manager.c @@ -42,6 +42,30 @@ G_DEFINE_TYPE(NMDhcpManager, nm_dhcp_manager, G_TYPE_OBJECT) /*****************************************************************************/ +#undef _NMLOG_ENABLED +#define _NMLOG_ENABLED(level, addr_family) nm_logging_enabled((level), _LOGD_DHCP(addr_family)) + +#define _NMLOG(level, addr_family, ...) \ + G_STMT_START \ + { \ + const int _addr_family = (addr_family); \ + const NMLogLevel _log_level = (level); \ + const NMLogDomain _log_domain = LOGD_DHCP_af(_addr_family); \ + \ + if (nm_logging_enabled(_log_level, _log_domain)) { \ + _nm_log(_log_level, \ + _log_domain, \ + 0, \ + NULL, \ + NULL, \ + "dhcp%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + nm_utils_addr_family_to_str(_addr_family) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ + G_STMT_END + +/*****************************************************************************/ + /* default to installed helper, but can be modified for testing */ const char *nm_dhcp_helper_path = LIBEXECDIR "/nm-dhcp-helper"; @@ -167,11 +191,10 @@ nm_dhcp_manager_start_client(NMDhcpManager *self, NMDhcpClientConfig *config, GE gtype = _client_factory_get_gtype(priv->client_factory, config->addr_family); - nm_log_trace(LOGD_DHCP, - "dhcp%c: creating IPv%c DHCP client of type %s", - nm_utils_addr_family_to_char(config->addr_family), - nm_utils_addr_family_to_char(config->addr_family), - g_type_name(gtype)); + _LOGT(config->addr_family, + "creating IPv%c DHCP client of type %s", + nm_utils_addr_family_to_char(config->addr_family), + g_type_name(gtype)); client = g_object_new(gtype, NM_DHCP_CLIENT_CONFIG, config, NULL); @@ -244,11 +267,11 @@ nm_dhcp_manager_init(NMDhcpManager *self) if (!f) continue; - nm_log_dbg(LOGD_DHCP, - "dhcp-init: enabled DHCP client '%s'%s%s", - f->name, - _client_factory_available(f) ? "" : " (not available)", - f->undocumented ? " (undocumented internal plugin)" : ""); + _LOGD(AF_UNSPEC, + "init: enabled DHCP client '%s'%s%s", + f->name, + _client_factory_available(f) ? "" : " (not available)", + f->undocumented ? " (undocumented internal plugin)" : ""); } /* Client-specific setup */ @@ -261,20 +284,20 @@ nm_dhcp_manager_init(NMDhcpManager *self) if (client) { client_factory = _client_factory_available(_client_factory_find_by_name(client)); if (!client_factory) - nm_log_warn(LOGD_DHCP, "dhcp-init: DHCP client '%s' not available", client); + _LOGW(AF_UNSPEC, "init: DHCP client '%s' not available", client); } if (!client_factory) { client_factory = _client_factory_find_by_name("" NM_CONFIG_DEFAULT_MAIN_DHCP); if (!client_factory) - nm_log_err(LOGD_DHCP, - "dhcp-init: default DHCP client '%s' is not installed", - NM_CONFIG_DEFAULT_MAIN_DHCP); + _LOGE(AF_UNSPEC, + "init: default DHCP client '%s' is not installed", + NM_CONFIG_DEFAULT_MAIN_DHCP); else { client_factory = _client_factory_available(client_factory); if (!client_factory) - nm_log_info(LOGD_DHCP, - "dhcp-init: default DHCP client '%s' is not available", - NM_CONFIG_DEFAULT_MAIN_DHCP); + _LOGI(AF_UNSPEC, + "init: default DHCP client '%s' is not available", + NM_CONFIG_DEFAULT_MAIN_DHCP); } } if (!client_factory) { @@ -287,7 +310,7 @@ nm_dhcp_manager_init(NMDhcpManager *self) g_return_if_fail(client_factory); - nm_log_info(LOGD_DHCP, "dhcp-init: Using DHCP client '%s'", client_factory->name); + _LOGI(AF_UNSPEC, "init: Using DHCP client '%s'", client_factory->name); /* NOTE: currently the DHCP plugin is chosen once at start. It's not * possible to reload that configuration. If that ever becomes possible, diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c index 2e41cf15..05b7b52e 100644 --- a/src/core/dhcp/nm-dhcp-nettools.c +++ b/src/core/dhcp/nm-dhcp-nettools.c @@ -13,22 +13,24 @@ #include #include +#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" /*****************************************************************************/ @@ -56,6 +58,8 @@ typedef struct { const NML3ConfigData *lease_l3cd; } granted; + GSource *pop_all_events_on_idle_source; + GSource *event_source; char *lease_file; } NMDhcpNettoolsPrivate; @@ -76,6 +80,10 @@ G_DEFINE_TYPE(NMDhcpNettools, nm_dhcp_nettools, NM_TYPE_DHCP_CLIENT) /*****************************************************************************/ +static void dhcp4_event_pop_all_events_on_idle(NMDhcpNettools *self); + +/*****************************************************************************/ + static void set_error_nettools(GError **error, int r, const char *message) { @@ -156,8 +164,10 @@ lease_option_consume_route(const uint8_t **datap, /*****************************************************************************/ static gboolean -lease_parse_address(NDhcp4ClientLease *lease, +lease_parse_address(NMDhcpNettools *self /* for logging context only */, + NDhcp4ClientLease *lease, NML3ConfigData *l3cd, + const char *iface, GHashTable *options, in_addr_t *out_address, GError **error) @@ -228,15 +238,33 @@ lease_parse_address(NDhcp4ClientLease *lease, } r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_SUBNET_MASK, &l_data, &l_data_len); - if (r != 0 || !nm_dhcp_lease_data_parse_in_addr(l_data, l_data_len, &a_netmask)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_UNKNOWN, - "could not get netmask from lease"); - return FALSE; + if (r == N_DHCP4_E_UNSET) { + char str1[NM_UTILS_INET_ADDRSTRLEN]; + char str2[NM_UTILS_INET_ADDRSTRLEN]; + + /* Some DHCP servers may not set the subnet-mask (issue#1037). + * Do the same as the dhclient plugin and use a default. */ + a_plen = _nm_utils_ip4_get_default_prefix(a_address.s_addr); + a_netmask = _nm_utils_ip4_prefix_to_netmask(a_plen); + _LOGT("missing subnet mask (option 1). Guess %s based on IP address %s", + _nm_utils_inet4_ntop(a_netmask, str1), + _nm_utils_inet4_ntop(a_address.s_addr, str2)); + } else { + if (r != 0 + || !nm_dhcp_lease_data_parse_in_addr(l_data, + l_data_len, + &a_netmask, + iface, + NM_DHCP_OPTION_DHCP4_SUBNET_MASK)) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_UNKNOWN, + "could not get netmask from lease"); + return FALSE; + } + a_plen = _nm_utils_ip4_netmask_to_prefix(a_netmask); + a_netmask = _nm_utils_ip4_prefix_to_netmask(a_plen); } - a_plen = nm_utils_ip4_netmask_to_prefix(a_netmask); - nm_dhcp_option_add_option_in_addr(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS, @@ -282,6 +310,7 @@ lease_parse_address(NDhcp4ClientLease *lease, static void lease_parse_address_list(NDhcp4ClientLease *lease, NML3ConfigData *l3cd, + const char *iface, NMDhcpOptionDhcp4Options option, GHashTable *options, NMStrBuf *sbuf) @@ -294,8 +323,14 @@ lease_parse_address_list(NDhcp4ClientLease *lease, if (r != 0) return; - if (l_data_len == 0 || l_data_len % 4 != 0) + if (l_data_len == 0 || l_data_len % 4 != 0) { + nm_dhcp_lease_log_invalid_option(iface, + AF_INET, + option, + "wrong option length %lu", + (unsigned long) l_data_len); return; + } nm_str_buf_reset(sbuf); @@ -308,9 +343,14 @@ lease_parse_address_list(NDhcp4ClientLease *lease, switch (option) { case NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER: - if (addr == 0 || nm_ip4_addr_is_localhost(addr)) { + if (addr == 0 || nm_utils_ip4_address_is_loopback(addr)) { /* Skip localhost addresses, like also networkd does. * See https://github.com/systemd/systemd/issues/4524. */ + nm_dhcp_lease_log_invalid_option(iface, + AF_INET, + option, + "address %s is ignored", + _nm_utils_inet4_ntop(addr, addr_str)); continue; } nm_l3_config_data_add_nameserver(l3cd, AF_INET, &addr); @@ -502,7 +542,10 @@ lease_parse_routes(NDhcp4ClientLease *lease, } static void -lease_parse_search_domains(NDhcp4ClientLease *lease, NML3ConfigData *l3cd, GHashTable *options) +lease_parse_search_domains(NDhcp4ClientLease *lease, + NML3ConfigData *l3cd, + const char *iface, + GHashTable *options) { gs_strfreev char **domains = NULL; const guint8 *l_data; @@ -514,7 +557,11 @@ lease_parse_search_domains(NDhcp4ClientLease *lease, NML3ConfigData *l3cd, GHash if (r != 0) return; - domains = nm_dhcp_lease_data_parse_search_list(l_data, l_data_len); + domains = nm_dhcp_lease_data_parse_search_list(l_data, + l_data_len, + iface, + AF_INET, + NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST); if (!domains || !domains[0]) return; @@ -556,12 +603,9 @@ lease_parse_private_options(NDhcp4ClientLease *lease, GHashTable *options) } static NML3ConfigData * -lease_to_ip4_config(NMDedupMultiIndex *multi_idx, - const char *iface, - int ifindex, - NDhcp4ClientLease *lease, - GError **error) +lease_to_ip4_config(NMDhcpNettools *self, NDhcp4ClientLease *lease, GError **error) { + const char *iface; nm_auto_str_buf NMStrBuf sbuf = NM_STR_BUF_INIT(0, FALSE); nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; gs_unref_hashtable GHashTable *options = NULL; @@ -574,13 +618,15 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, struct in_addr v_inaddr_s; int r; - g_return_val_if_fail(lease != NULL, NULL); + nm_assert(lease); + + iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); - l3cd = nm_l3_config_data_new(multi_idx, ifindex, NM_IP_CONFIG_SOURCE_DHCP); + l3cd = nm_dhcp_client_create_l3cd(NM_DHCP_CLIENT(self)); options = nm_dhcp_option_create_options_dict(); - if (!lease_parse_address(lease, l3cd, options, &lease_address, error)) + if (!lease_parse_address(self, lease, l3cd, iface, options, &lease_address, error)) return NULL; r = n_dhcp4_client_lease_get_server_identifier(lease, &v_inaddr_s); @@ -592,7 +638,12 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, } r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_BROADCAST, &l_data, &l_data_len); - if (r == 0 && nm_dhcp_lease_data_parse_in_addr(l_data, l_data_len, &v_inaddr)) { + if (r == 0 + && nm_dhcp_lease_data_parse_in_addr(l_data, + l_data_len, + &v_inaddr, + iface, + NM_DHCP_OPTION_DHCP4_BROADCAST)) { nm_dhcp_option_add_option_in_addr(options, AF_INET, NM_DHCP_OPTION_DHCP4_BROADCAST, @@ -601,10 +652,21 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, lease_parse_routes(lease, l3cd, lease_address, options, &sbuf); - lease_parse_address_list(lease, l3cd, NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER, options, &sbuf); + lease_parse_address_list(lease, + l3cd, + iface, + NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER, + options, + &sbuf); r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_DOMAIN_NAME, &l_data, &l_data_len); - if (r == 0 && nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) { + if (r == 0 + && nm_dhcp_lease_data_parse_cstr(l_data, + l_data_len, + &l_data_len, + iface, + AF_INET, + NM_DHCP_OPTION_DHCP4_DOMAIN_NAME)) { gs_free const char **domains = NULL; nm_str_buf_reset(&sbuf); @@ -620,7 +682,10 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, for (i = 0; domains[i]; i++) { gs_free char *s = NULL; - s = nm_dhcp_lease_data_parse_domain_validate(domains[i]); + s = nm_dhcp_lease_data_parse_domain_validate(domains[i], + iface, + AF_INET, + NM_DHCP_OPTION_DHCP4_DOMAIN_NAME); if (!s) continue; @@ -638,10 +703,16 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, } } - lease_parse_search_domains(lease, l3cd, options); + lease_parse_search_domains(lease, l3cd, iface, options); r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, &l_data, &l_data_len); - if (r == 0 && nm_dhcp_lease_data_parse_mtu(l_data, l_data_len, &v_u16)) { + if (r == 0 + && nm_dhcp_lease_data_parse_mtu(l_data, + l_data_len, + &v_u16, + iface, + AF_INET, + NM_DHCP_OPTION_DHCP4_INTERFACE_MTU)) { nm_dhcp_option_add_option_u64(options, AF_INET, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, v_u16); nm_l3_config_data_set_mtu(l3cd, v_u16); } @@ -654,15 +725,26 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, if (r == 0) { gs_free char *s = NULL; - if (nm_dhcp_lease_data_parse_domain(l_data, l_data_len, &s)) { + if (nm_dhcp_lease_data_parse_domain(l_data, + l_data_len, + &s, + iface, + AF_INET, + NM_DHCP_OPTION_DHCP4_HOST_NAME)) { nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_HOST_NAME, s); } } - lease_parse_address_list(lease, l3cd, NM_DHCP_OPTION_DHCP4_NTP_SERVER, options, &sbuf); + lease_parse_address_list(lease, l3cd, iface, NM_DHCP_OPTION_DHCP4_NTP_SERVER, options, &sbuf); r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_ROOT_PATH, &l_data, &l_data_len); - if (r == 0 && nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) { + if (r == 0 + && nm_dhcp_lease_data_parse_cstr(l_data, + l_data_len, + &l_data_len, + iface, + AF_INET, + NM_DHCP_OPTION_DHCP4_ROOT_PATH)) { /* https://tools.ietf.org/html/rfc2132#section-3.19 * * The path is formatted as a character string consisting of @@ -684,7 +766,13 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY, &l_data, &l_data_len); - if (r == 0 && nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) { + if (r == 0 + && nm_dhcp_lease_data_parse_cstr(l_data, + l_data_len, + &l_data_len, + iface, + AF_INET, + NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY)) { /* https://tools.ietf.org/html/draft-ietf-wrec-wpad-01#section-4.4.1 * * We reject NUL characters inside the string (except trailing NULs). @@ -704,7 +792,13 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, } r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_NIS_DOMAIN, &l_data, &l_data_len); - if (r == 0 && nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) { + if (r == 0 + && nm_dhcp_lease_data_parse_cstr(l_data, + l_data_len, + &l_data_len, + iface, + AF_INET, + NM_DHCP_OPTION_DHCP4_NIS_DOMAIN)) { gs_free char *to_free = NULL; /* https://tools.ietf.org/html/rfc2132#section-8.1 */ @@ -730,7 +824,13 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, } r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_BOOTFILE_NAME, &l_data, &l_data_len); - if (r == 0 && nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) { + if (r == 0 + && nm_dhcp_lease_data_parse_cstr(l_data, + l_data_len, + &l_data_len, + iface, + AF_INET, + NM_DHCP_OPTION_DHCP4_BOOTFILE_NAME)) { gs_free char *to_free = NULL; v_str = nm_utils_buf_utf8safe_escape((char *) l_data, @@ -743,9 +843,14 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, v_str ?: ""); } - lease_parse_address_list(lease, l3cd, NM_DHCP_OPTION_DHCP4_NIS_SERVERS, options, &sbuf); + lease_parse_address_list(lease, l3cd, iface, NM_DHCP_OPTION_DHCP4_NIS_SERVERS, options, &sbuf); - lease_parse_address_list(lease, l3cd, NM_DHCP_OPTION_DHCP4_NETBIOS_NAMESERVER, options, &sbuf); + lease_parse_address_list(lease, + l3cd, + iface, + NM_DHCP_OPTION_DHCP4_NETBIOS_NAMESERVER, + options, + &sbuf); lease_parse_private_options(lease, options); @@ -785,9 +890,7 @@ lease_save(NMDhcpNettools *self, NDhcp4ClientLease *lease, const char *lease_fil static void bound4_handle(NMDhcpNettools *self, guint event, NDhcp4ClientLease *lease) { - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - NMDhcpClient *client = NM_DHCP_CLIENT(self); - const NMDhcpClientConfig *client_config; + NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; gs_free_error GError *error = NULL; @@ -796,17 +899,14 @@ bound4_handle(NMDhcpNettools *self, guint event, NDhcp4ClientLease *lease) _LOGT("lease available (%s)", (event == N_DHCP4_CLIENT_EVENT_GRANTED) ? "granted" : "extended"); - client_config = nm_dhcp_client_get_config(client); - l3cd = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(client), - client_config->iface, - nm_dhcp_client_get_ifindex(client), - lease, - &error); + l3cd = lease_to_ip4_config(self, lease, &error); if (!l3cd) { _LOGW("failure to parse lease: %s", error->message); - if (event == N_DHCP4_CLIENT_EVENT_GRANTED) + if (event == N_DHCP4_CLIENT_EVENT_GRANTED) { n_dhcp4_client_lease_decline(lease, "invalid lease"); + dhcp4_event_pop_all_events_on_idle(self); + } _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL); return; @@ -854,7 +954,7 @@ dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) case N_DHCP4_CLIENT_EVENT_OFFER: r = n_dhcp4_client_lease_get_server_identifier(event->offer.lease, &server_id); if (r) { - _LOGW("selecting lease failed: %d", r); + _LOGW("selecting lease failed: could not get DHCP server identifier (%d)", r); return; } @@ -870,11 +970,19 @@ dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) return; } + if (!_nm_dhcp_client_accept_offer(NM_DHCP_CLIENT(self), &yiaddr.s_addr)) { + /* We don't log about this, the parent class is expected to notify about the reasons. */ + return; + } + _LOGT("selecting offered lease from %s for %s", _nm_utils_inet4_ntop(server_id.s_addr, addr_str), _nm_utils_inet4_ntop(yiaddr.s_addr, addr_str2)); r = n_dhcp4_client_lease_select(event->offer.lease); + + dhcp4_event_pop_all_events_on_idle(self); + if (r) { _LOGW("selecting lease failed: %d", r); return; @@ -906,22 +1014,79 @@ dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) } } +static void +dhcp4_event_pop_all_events(NMDhcpNettools *self) +{ + NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); + NDhcp4ClientEvent *event; + + while (!n_dhcp4_client_pop_event(priv->client, &event) && event) + dhcp4_event_handle(self, event); + + nm_clear_g_source_inst(&priv->pop_all_events_on_idle_source); +} + +static gboolean +dhcp4_event_pop_all_events_on_idle_cb(gpointer user_data) +{ + NMDhcpNettools *self = user_data; + NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); + + nm_clear_g_source_inst(&priv->pop_all_events_on_idle_source); + dhcp4_event_pop_all_events(self); + return G_SOURCE_CONTINUE; +} + +static void +dhcp4_event_pop_all_events_on_idle(NMDhcpNettools *self) +{ + NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); + + /* For the most part, NDhcp4Client gets driven from internal, that is + * by having events ready on the socket or the timerfd. For those + * events, we will poll on the (epoll) FD, then let it be processed + * by n_dhcp4_client_dispatch(), and pop the queued events. + * + * But certain commands (n_dhcp4_client_lease_select(), n_dhcp4_client_lease_accept(), + * n_dhcp4_client_lease_decline()) are initiated by the user. And they tend + * to log events. Logging is done by queuing a message, but that won't be processed, + * unless we pop the event. + * + * To ensure that those logging events get popped, schedule an idle handler to do that. + * + * Yes, this means, that the messages only get logged later, when the idle handler + * runs. The alternative seems even more problematic, because we don't know + * the current call-state, and it seems dangerous to pop unexpected events. + * E.g. we call n_dhcp4_client_lease_select() from inside the event-handler, + * it seems wrong to call dhcp4_event_pop_all_events() in that context again. + * + * See-also: https://github.com/nettools/n-dhcp4/issues/34 + */ + + if (!priv->pop_all_events_on_idle_source) { + priv->pop_all_events_on_idle_source = + nm_g_idle_add_source(dhcp4_event_pop_all_events_on_idle_cb, self); + } +} + static gboolean dhcp4_event_cb(int fd, GIOCondition condition, gpointer user_data) { NMDhcpNettools *self = user_data; NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - NDhcp4ClientEvent *event; int r; 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); @@ -929,8 +1094,7 @@ dhcp4_event_cb(int fd, GIOCondition condition, gpointer user_data) return G_SOURCE_REMOVE; } - while (!n_dhcp4_client_pop_event(priv->client, &event) && event) - dhcp4_event_handle(self, event); + dhcp4_event_pop_all_events(self); return G_SOURCE_CONTINUE; } @@ -1056,6 +1220,8 @@ _accept(NMDhcpClient *client, const NML3ConfigData *l3cd, GError **error) if (!r) lease_save(self, priv->granted.lease, priv->lease_file); + dhcp4_event_pop_all_events_on_idle(self); + nm_clear_pointer(&priv->granted.lease, n_dhcp4_client_lease_unref); nm_clear_l3cd(&priv->granted.lease_l3cd); @@ -1091,6 +1257,8 @@ decline(NMDhcpClient *client, const NML3ConfigData *l3cd, const char *error_mess r = n_dhcp4_client_lease_decline(lease, error_message); + dhcp4_event_pop_all_events_on_idle(self); + if (r) { set_error_nettools(error, r, "failed to decline lease"); return FALSE; @@ -1155,18 +1323,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) { @@ -1304,6 +1474,7 @@ dispose(GObject *object) nm_clear_g_free(&priv->lease_file); nm_clear_g_source_inst(&priv->event_source); + nm_clear_g_source_inst(&priv->pop_all_events_on_idle_source); nm_clear_pointer(&priv->granted.lease, n_dhcp4_client_lease_unref); nm_clear_l3cd(&priv->granted.lease_l3cd); nm_clear_pointer(&priv->probe, n_dhcp4_client_probe_free); diff --git a/src/core/dhcp/nm-dhcp-systemd.c b/src/core/dhcp/nm-dhcp-systemd.c index f2dd1823..49e21d97 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,683 +68,7 @@ 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_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_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_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL); - return; - } - - dhcp_lease_save(lease, priv->lease_file); - - _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), - extended ? NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED - : NM_DHCP_CLIENT_EVENT_TYPE_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_notify(NM_DHCP_CLIENT(user_data), NM_DHCP_CLIENT_EVENT_TYPE_EXPIRE, NULL); - break; - case SD_DHCP_CLIENT_EVENT_STOP: - _nm_dhcp_client_notify(NM_DHCP_CLIENT(user_data), NM_DHCP_CLIENT_EVENT_TYPE_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, - sd_dhcp6_lease *lease, - gboolean info_only, - gint32 ts, - GError **error) +lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GError **error) { nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; gs_unref_hashtable GHashTable *options = NULL; @@ -762,11 +84,11 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx, nm_assert(lease); - l3cd = nm_l3_config_data_new(multi_idx, ifindex, NM_IP_CONFIG_SOURCE_DHCP); + l3cd = nm_dhcp_client_create_l3cd(NM_DHCP_CLIENT(self)); options = nm_dhcp_option_create_options_dict(); - if (!info_only) { + if (!nm_dhcp_client_get_config(NM_DHCP_CLIENT(self))->v6.info_only) { gboolean has_any_addresses = FALSE; uint32_t lft_pref; uint32_t lft_valid; @@ -864,17 +186,13 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx, static void bound6_handle(NMDhcpSystemd *self) { - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - const gint32 ts = nm_utils_get_monotonic_timestamp_sec(); - const char *iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); - const NMDhcpClientConfig *client_config; + NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); + const gint32 ts = nm_utils_get_monotonic_timestamp_sec(); nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; gs_free_error GError *error = NULL; NMPlatformIP6Address prefix = {0}; sd_dhcp6_lease *lease = NULL; - client_config = nm_dhcp_client_get_config(NM_DHCP_CLIENT(self)); - if (sd_dhcp6_client_get_lease(priv->client6, &lease) < 0 || !lease) { _LOGW(" no lease!"); _nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL); @@ -883,13 +201,7 @@ bound6_handle(NMDhcpSystemd *self) _LOGD("lease available"); - l3cd = lease_to_ip6_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), - iface, - nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), - lease, - client_config->v6.info_only, - ts, - &error); + l3cd = lease_to_ip6_config(self, lease, ts, &error); if (!l3cd) { _LOGW("%s", error->message); @@ -953,7 +265,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); @@ -1080,18 +391,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); } @@ -1109,12 +415,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); @@ -1132,14 +432,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 88fe83f3..1bffb3c4 100644 --- a/src/core/dhcp/nm-dhcp-utils.c +++ b/src/core/dhcp/nm-dhcp-utils.c @@ -14,6 +14,7 @@ #include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "nm-dhcp-utils.h" +#include "nm-dhcp-options.h" #include "nm-l3-config-data.h" #include "nm-utils.h" #include "nm-config.h" @@ -295,7 +296,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 +306,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 +341,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 +353,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 +375,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); } } @@ -414,18 +416,21 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, str = g_hash_table_lookup(options, "ip_address"); if (!str || !nm_utils_parse_inaddr_bin(AF_INET, str, NULL, &addr)) return NULL; + if (addr == INADDR_ANY) + return NULL; _LOG2I(LOGD_DHCP4, iface, " address %s", str); str = g_hash_table_lookup(options, "subnet_mask"); if (str && (inet_pton(AF_INET, str, &tmp_addr) > 0)) { - plen = nm_utils_ip4_netmask_to_prefix(tmp_addr); + plen = _nm_utils_ip4_netmask_to_prefix(tmp_addr); _LOG2I(LOGD_DHCP4, iface, " plen %d (%s)", plen, str); } else { /* Get default netmask for the IP according to appropriate class. */ plen = _nm_utils_ip4_get_default_prefix(addr); _LOG2I(LOGD_DHCP4, iface, " plen %d (default)", plen); } + nm_platform_ip4_address_set_addr(&address, addr, plen); /* Routes: if the server returns classless static routes, we MUST ignore @@ -588,7 +593,7 @@ nm_dhcp_utils_ip6_prefix_from_options(GHashTable *options) { gs_strfreev char **split_addr = NULL; NMPlatformIP6Address address = { - 0, + 0, }; struct in6_addr tmp_addr; char *str = NULL; @@ -822,26 +827,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, @@ -902,28 +887,75 @@ nm_dhcp_utils_merge_new_dhcp6_lease(const NML3ConfigData *l3cd_old, /*****************************************************************************/ +void +nm_dhcp_lease_log_invalid_option(const char *iface, + int addr_family, + guint option, + const char *fmt, + ...) +{ + const char *option_name; + gs_free char *msg = NULL; + va_list ap; + + option_name = nm_dhcp_option_request_string(addr_family, option); + + va_start(ap, fmt); + msg = g_strdup_vprintf(fmt, ap); + va_end(ap); + + _LOG2I(NM_IS_IPv4(addr_family) ? LOGD_DHCP4 : LOGD_DHCP6, + iface, + "error parsing DHCP option %d (%s)%s%s", + option, + option_name, + msg ? ": " : "", + msg ?: ""); +} + gboolean -nm_dhcp_lease_data_parse_u16(const guint8 *data, gsize n_data, uint16_t *out_val) +nm_dhcp_lease_data_parse_u16(const guint8 *data, + gsize n_data, + uint16_t *out_val, + const char *iface, + int addr_family, + guint option) { - if (n_data != 2) + if (n_data != 2) { + nm_dhcp_lease_log_invalid_option(iface, + addr_family, + option, + "invalid option length %lu", + (unsigned long) n_data); return FALSE; + } *out_val = unaligned_read_be16(data); return TRUE; } gboolean -nm_dhcp_lease_data_parse_mtu(const guint8 *data, gsize n_data, uint16_t *out_val) +nm_dhcp_lease_data_parse_mtu(const guint8 *data, + gsize n_data, + uint16_t *out_val, + const char *iface, + int addr_family, + guint option) { uint16_t mtu; - if (!nm_dhcp_lease_data_parse_u16(data, n_data, &mtu)) + if (!nm_dhcp_lease_data_parse_u16(data, n_data, &mtu, iface, addr_family, option)) return FALSE; if (mtu < 68) { /* https://tools.ietf.org/html/rfc2132#section-5.1: * * The minimum legal value for the MTU is 68. */ + nm_dhcp_lease_log_invalid_option(iface, + addr_family, + option, + "value %u is smaller than 68", + mtu); return FALSE; } @@ -932,7 +964,12 @@ nm_dhcp_lease_data_parse_mtu(const guint8 *data, gsize n_data, uint16_t *out_val } gboolean -nm_dhcp_lease_data_parse_cstr(const guint8 *data, gsize n_data, gsize *out_new_len) +nm_dhcp_lease_data_parse_cstr(const guint8 *data, + gsize n_data, + gsize *out_new_len, + const char *iface, + int addr_family, + guint option) { /* WARNING: this function only validates that the string does not contain * NUL characters (and ignores trailing NULs). It does not check character @@ -947,6 +984,10 @@ nm_dhcp_lease_data_parse_cstr(const guint8 *data, gsize n_data, gsize *out_new_l * * https://tools.ietf.org/html/rfc2132#section-2 * https://github.com/systemd/systemd/issues/1337 */ + nm_dhcp_lease_log_invalid_option(iface, + addr_family, + option, + "string contains embedded NUL"); return FALSE; } } @@ -956,32 +997,47 @@ nm_dhcp_lease_data_parse_cstr(const guint8 *data, gsize n_data, gsize *out_new_l } char * -nm_dhcp_lease_data_parse_domain_validate(const char *str) +nm_dhcp_lease_data_parse_domain_validate(const char *str, + const char *iface, + int addr_family, + guint option) { gs_free char *s = NULL; s = nm_sd_dns_name_normalize(str); if (!s) - return NULL; + goto err; if (nm_str_is_empty(s) || (s[0] == '.' && s[1] == '\0')) { /* root domains are not allowed. */ - return NULL; + goto err; } if (nm_utils_is_localhost(s)) - return NULL; + goto err; if (!g_utf8_validate(s, -1, NULL)) { /* the result must be valid UTF-8. */ - return NULL; + goto err; } return g_steal_pointer(&s); +err: + nm_dhcp_lease_log_invalid_option(iface, + addr_family, + option, + "'%s' is not a valid DNS domain", + str); + return NULL; } gboolean -nm_dhcp_lease_data_parse_domain(const guint8 *data, gsize n_data, char **out_val) +nm_dhcp_lease_data_parse_domain(const guint8 *data, + gsize n_data, + char **out_val, + const char *iface, + int addr_family, + guint option) { gs_free char *str1_free = NULL; const char *str1; @@ -989,7 +1045,7 @@ nm_dhcp_lease_data_parse_domain(const guint8 *data, gsize n_data, char **out_val /* this is mostly the same as systemd's lease_parse_domain(). */ - if (!nm_dhcp_lease_data_parse_cstr(data, n_data, &n_data)) + if (!nm_dhcp_lease_data_parse_cstr(data, n_data, &n_data, iface, addr_family, option)) return FALSE; if (n_data == 0) { @@ -1001,12 +1057,13 @@ nm_dhcp_lease_data_parse_domain(const guint8 *data, gsize n_data, char **out_val * * Note that this is *after* we potentially stripped trailing NULs. */ + nm_dhcp_lease_log_invalid_option(iface, addr_family, option, "empty value"); return FALSE; } str1 = nm_strndup_a(300, (char *) data, n_data, &str1_free); - s = nm_dhcp_lease_data_parse_domain_validate(str1); + s = nm_dhcp_lease_data_parse_domain_validate(str1, iface, addr_family, option); if (!s) return FALSE; @@ -1015,7 +1072,11 @@ nm_dhcp_lease_data_parse_domain(const guint8 *data, gsize n_data, char **out_val } gboolean -nm_dhcp_lease_data_parse_in_addr(const guint8 *data, gsize n_data, in_addr_t *out_val) +nm_dhcp_lease_data_parse_in_addr(const guint8 *data, + gsize n_data, + in_addr_t *out_val, + const char *iface, + guint option) { /* - option 1, https://tools.ietf.org/html/rfc2132#section-3.3 * - option 28, https://tools.ietf.org/html/rfc2132#section-5.3 @@ -1025,8 +1086,14 @@ nm_dhcp_lease_data_parse_in_addr(const guint8 *data, gsize n_data, in_addr_t *ou * according to RFC 3396 section 7. Therefore, it's possible that a * option carrying a IPv4 address has a length > 4. */ - if (n_data < 4) + if (n_data < 4) { + nm_dhcp_lease_log_invalid_option(iface, + AF_INET, + option, + "invalid address length %lu", + (unsigned long) n_data); return FALSE; + } *out_val = unaligned_read_ne32(data); return TRUE; @@ -1069,7 +1136,8 @@ static char * lease_option_print_domain_name(const uint8_t *cache, size_t *n_cachep, const uint8_t **datap, - size_t *n_datap) + size_t *n_datap, + gboolean *invalid) { nm_auto_str_buf NMStrBuf sbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_40, FALSE); const uint8_t *domain; @@ -1080,6 +1148,8 @@ lease_option_print_domain_name(const uint8_t *cache, gboolean first = TRUE; uint8_t c; + NM_SET_OUT(invalid, FALSE); + /* * We are given two adjacent memory regions. The @cache contains alreday parsed * domain names, and the @datap contains the remaining data to parse. @@ -1096,8 +1166,10 @@ lease_option_print_domain_name(const uint8_t *cache, * Note, that each time a jump to an offset is performed, the size of the * cache shrinks, so this is guaranteed to terminate. */ - if (cache + n_cache != *datap) + if (cache + n_cache != *datap) { + NM_SET_OUT(invalid, TRUE); return NULL; + } for (;;) { if (!nm_dhcp_lease_data_consume(domainp, n_domainp, &c, sizeof(c))) @@ -1122,8 +1194,10 @@ lease_option_print_domain_name(const uint8_t *cache, else first = FALSE; - if (!lease_option_print_label(&sbuf, n_label, domainp, n_domainp)) + if (!lease_option_print_label(&sbuf, n_label, domainp, n_domainp)) { + NM_SET_OUT(invalid, TRUE); return NULL; + } break; } @@ -1136,13 +1210,17 @@ lease_option_print_domain_name(const uint8_t *cache, * two high bits are masked out. */ - if (!nm_dhcp_lease_data_consume(domainp, n_domainp, &c, sizeof(c))) + if (!nm_dhcp_lease_data_consume(domainp, n_domainp, &c, sizeof(c))) { + NM_SET_OUT(invalid, TRUE); return NULL; + } offset += c; - if (offset >= n_cache) + if (offset >= n_cache) { + NM_SET_OUT(invalid, TRUE); return NULL; + } domain = cache + offset; n_domain = n_cache - offset; @@ -1154,29 +1232,44 @@ lease_option_print_domain_name(const uint8_t *cache, break; } default: + NM_SET_OUT(invalid, TRUE); return NULL; } } } char ** -nm_dhcp_lease_data_parse_search_list(const guint8 *data, gsize n_data) +nm_dhcp_lease_data_parse_search_list(const guint8 *data, + gsize n_data, + const char *iface, + int addr_family, + guint option) { GPtrArray *array = NULL; const guint8 *cache = data; gsize n_cache = 0; + guint i = 0; for (;;) { gs_free char *s = NULL; - - s = lease_option_print_domain_name(cache, &n_cache, &data, &n_data); - if (!s) + gboolean invalid; + + s = lease_option_print_domain_name(cache, &n_cache, &data, &n_data, &invalid); + if (!s) { + if (iface && invalid) + nm_dhcp_lease_log_invalid_option(iface, + addr_family, + option, + "search domain #%u is invalid", + i); break; + } if (!array) array = g_ptr_array_new(); g_ptr_array_add(array, g_steal_pointer(&s)); + i++; } if (!array) diff --git a/src/core/dhcp/nm-dhcp-utils.h b/src/core/dhcp/nm-dhcp-utils.h index bef50c52..00199b02 100644 --- a/src/core/dhcp/nm-dhcp-utils.h +++ b/src/core/dhcp/nm-dhcp-utils.h @@ -59,13 +59,48 @@ nm_dhcp_lease_data_consume_in_addr(const uint8_t **datap, size_t *n_datap, in_ad return nm_dhcp_lease_data_consume(datap, n_datap, addrp, sizeof(struct in_addr)); } -char *nm_dhcp_lease_data_parse_domain_validate(const char *str); - -gboolean nm_dhcp_lease_data_parse_u16(const guint8 *data, gsize n_data, guint16 *out_val); -gboolean nm_dhcp_lease_data_parse_mtu(const guint8 *data, gsize n_data, guint16 *out_val); -gboolean nm_dhcp_lease_data_parse_cstr(const guint8 *data, gsize n_data, gsize *out_new_len); -gboolean nm_dhcp_lease_data_parse_domain(const guint8 *data, gsize n_data, char **out_val); -gboolean nm_dhcp_lease_data_parse_in_addr(const guint8 *data, gsize n_data, in_addr_t *out_val); -char **nm_dhcp_lease_data_parse_search_list(const guint8 *data, gsize n_data); +void nm_dhcp_lease_log_invalid_option(const char *iface, + int addr_family, + guint option, + const char *fmt, + ...) G_GNUC_PRINTF(4, 5); +char *nm_dhcp_lease_data_parse_domain_validate(const char *str, + const char *iface, + int addr_family, + guint option); +gboolean nm_dhcp_lease_data_parse_u16(const guint8 *data, + gsize n_data, + guint16 *out_val, + const char *iface, + int addr_family, + guint option); +gboolean nm_dhcp_lease_data_parse_mtu(const guint8 *data, + gsize n_data, + guint16 *out_val, + const char *iface, + int addr_family, + guint option); +gboolean nm_dhcp_lease_data_parse_cstr(const guint8 *data, + gsize n_data, + gsize *out_new_len, + const char *iface, + int addr_family, + guint option); +gboolean nm_dhcp_lease_data_parse_domain(const guint8 *data, + gsize n_data, + char **out_val, + const char *iface, + int addr_family, + guint option); +gboolean nm_dhcp_lease_data_parse_in_addr(const guint8 *data, + gsize n_data, + in_addr_t *out_val, + const char *iface, + guint option); +char **nm_dhcp_lease_data_parse_search_list(const guint8 *data, + gsize n_data, + const char *iface, + int addr_family, + guint option); #endif /* __NETWORKMANAGER_DHCP_UTILS_H__ */ diff --git a/src/core/dhcp/tests/test-dhcp-utils.c b/src/core/dhcp/tests/test-dhcp-utils.c index f021b642..7597f516 100644 --- a/src/core/dhcp/tests/test-dhcp-utils.c +++ b/src/core/dhcp/tests/test-dhcp-utils.c @@ -196,16 +196,16 @@ test_parse_search_list(void) char **domains; data = (guint8[]){0x05, 'l', 'o', 'c', 'a', 'l', 0x00}; - domains = nm_dhcp_lease_data_parse_search_list(data, 7); + domains = nm_dhcp_lease_data_parse_search_list(data, 7, NULL, 0, 0); g_assert(domains); g_assert_cmpint(g_strv_length(domains), ==, 1); g_assert_cmpstr(domains[0], ==, "local"); g_strfreev(domains); data = (guint8[]){0x04, 't', 'e', 's', 't', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', - 'e', 0x03, 'c', 'o', 'm', 0x00, 0xc0, 0x05, 0x03, 'a', 'b', 'c', - 0xc0, 0x0d, 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x00}; - domains = nm_dhcp_lease_data_parse_search_list(data, 34); + 'e', 0x03, 'c', 'o', 'm', 0x00, 0xc0, 0x05, 0x03, 'a', 'b', 'c', + 0xc0, 0x0d, 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x00}; + domains = nm_dhcp_lease_data_parse_search_list(data, 34, NULL, 0, 0); g_assert(domains); g_assert_cmpint(g_strv_length(domains), ==, 4); g_assert_cmpstr(domains[0], ==, "test.example.com"); @@ -220,7 +220,7 @@ test_parse_search_list(void) 'a', 'd', }; - domains = nm_dhcp_lease_data_parse_search_list(data, 4); + domains = nm_dhcp_lease_data_parse_search_list(data, 4, NULL, 0, 0); g_assert(!domains); data = (guint8[]){ @@ -235,7 +235,7 @@ test_parse_search_list(void) 'a', 'd', }; - domains = nm_dhcp_lease_data_parse_search_list(data, 10); + domains = nm_dhcp_lease_data_parse_search_list(data, 10, NULL, 0, 0); g_assert(domains); g_assert_cmpint(g_strv_length(domains), ==, 1); g_assert_cmpstr(domains[0], ==, "okay"); @@ -285,7 +285,7 @@ test_classless_static_routes_1(void) const char *expected_route2_dest = "10.0.0.0"; const char *expected_route2_gw = "10.17.66.41"; static const Option data[] = { - /* dhclient custom format */ + /* dhclient custom format */ {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 8 10 10 17 66 41"}, {NULL, NULL}}; @@ -310,7 +310,7 @@ test_classless_static_routes_2(void) const char *expected_route2_dest = "10.0.0.0"; const char *expected_route2_gw = "10.17.66.41"; static const Option data[] = { - /* dhcpcd format */ + /* dhcpcd format */ {"classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41"}, {NULL, NULL}}; @@ -336,9 +336,9 @@ test_fedora_dhclient_classless_static_routes(void) const char *expected_route2_gw = "10.34.255.6"; const char *expected_gateway = "192.168.0.113"; static const Option data[] = { - /* Fedora dhclient format */ + /* Fedora dhclient format */ {"classless_static_routes", - "0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6"}, + "0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6"}, {NULL, NULL}}; options = fill_table(generic_options, NULL); @@ -362,7 +362,7 @@ test_dhclient_invalid_classless_routes_1(void) const char *expected_route1_dest = "192.168.10.0"; const char *expected_route1_gw = "192.168.1.1"; static const Option data[] = { - /* dhclient format */ + /* dhclient format */ {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 45 10 17 66 41"}, {NULL, NULL}}; @@ -389,7 +389,7 @@ test_dhcpcd_invalid_classless_routes_1(void) const char *expected_route2_dest = "100.99.88.56"; const char *expected_route2_gw = "10.1.1.1"; static const Option data[] = { - /* dhcpcd format */ + /* dhcpcd format */ {"classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.adfadf/44 10.17.66.41"}, {NULL, NULL}}; @@ -419,8 +419,8 @@ test_dhclient_invalid_classless_routes_2(void) const char *expected_route2_dest = "100.99.88.56"; const char *expected_route2_gw = "10.1.1.1"; static const Option data[] = { - {"rfc3442_classless_static_routes", "45 10 17 66 41 24 192 168 10 192 168 1 1"}, - {NULL, NULL}}; + {"rfc3442_classless_static_routes", "45 10 17 66 41 24 192 168 10 192 168 1 1"}, + {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); @@ -448,8 +448,8 @@ test_dhcpcd_invalid_classless_routes_2(void) const char *expected_route2_dest = "100.99.88.56"; const char *expected_route2_gw = "10.1.1.1"; static const Option data[] = { - {"classless_static_routes", "10.0.adfadf/44 10.17.66.41 192.168.10.0/24 192.168.1.1"}, - {NULL, NULL}}; + {"classless_static_routes", "10.0.adfadf/44 10.17.66.41 192.168.10.0/24 192.168.1.1"}, + {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); @@ -477,8 +477,8 @@ test_dhclient_invalid_classless_routes_3(void) const char *expected_route1_dest = "192.168.10.0"; const char *expected_route1_gw = "192.168.1.1"; static const Option data[] = { - {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 32 128 10 17 66 41"}, - {NULL, NULL}}; + {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 32 128 10 17 66 41"}, + {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); @@ -501,8 +501,8 @@ test_dhcpcd_invalid_classless_routes_3(void) const char *expected_route1_dest = "192.168.10.0"; const char *expected_route1_gw = "192.168.1.1"; static Option data[] = { - {"classless_static_routes", "192.168.10.0/24 192.168.1.1 128/32 10.17.66.41"}, - {NULL, NULL}}; + {"classless_static_routes", "192.168.10.0/24 192.168.1.1 128/32 10.17.66.41"}, + {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); @@ -526,8 +526,8 @@ test_dhclient_gw_in_classless_routes(void) const char *expected_route1_gw = "192.168.1.1"; const char *expected_gateway = "192.2.3.4"; static Option data[] = { - {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 0 192 2 3 4"}, - {NULL, NULL}}; + {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 0 192 2 3 4"}, + {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); @@ -550,8 +550,8 @@ test_dhcpcd_gw_in_classless_routes(void) const char *expected_route1_gw = "192.168.1.1"; const char *expected_gateway = "192.2.3.4"; static Option data[] = { - {"classless_static_routes", "192.168.10.0/24 192.168.1.1 0.0.0.0/0 192.2.3.4"}, - {NULL, NULL}}; + {"classless_static_routes", "192.168.10.0/24 192.168.1.1 0.0.0.0/0 192.2.3.4"}, + {NULL, NULL}}; options = fill_table(generic_options, NULL); options = fill_table(data, options); diff --git a/src/core/dns/nm-dns-dnsmasq.c b/src/core/dns/nm-dns-dnsmasq.c index 43426882..7d0f0490 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 566f3d66..1e54452a 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 c30d4b3a..210f9f6c 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 847d7839..41a0dbc1 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 f9c424ab..24d6083b 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 c4993884..e0b94647 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 { @@ -77,15 +78,18 @@ typedef struct { GDBusConnection *dbus_connection; GHashTable *dirty_interfaces; GCancellable *cancellable; - GSource *try_start_timeout_source; + GCancellable *service_start_cancellable; CList request_queue_lst_head; 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->service_start_cancellable) { + /* 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 +_update_pending_maybe_changed(NMDnsSystemdResolved *self) +{ + 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_free(RequestItem *request_item) +_request_item_unref(RequestItem *request_item) { - c_list_unlink_stale(&request_item->request_queue_lst); + 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)); + } } } @@ -413,33 +522,45 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic) return has_config; } -static gboolean -_ensure_resolved_running_timeout(gpointer user_data) +static void +start_resolved_cb(GObject *source, GAsyncResult *result, gpointer user_data) { - NMDnsSystemdResolved *self = user_data; - NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + gs_unref_variant GVariant *res = NULL; + gs_free_error GError *error = NULL; + NMDnsSystemdResolved *self; + NMDnsSystemdResolvedPrivate *priv; NMDnsSystemdResolvedResolveHandle *handle; - nm_clear_g_source_inst(&priv->try_start_timeout_source); + res = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error); + if (nm_utils_error_is_cancelled(error)) + return; + + self = user_data; + priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + nm_clear_g_cancellable(&priv->service_start_cancellable); - _LOGT("timeout waiting to D-Bus activate systemd-resolved. Systemd-resolved won't be " - "used until it appears on the bus"); + if (!res) { + g_dbus_error_strip_remote_error(error); + _LOGD("error activating systemd-resolved: %s", error->message); again: - c_list_for_each_entry (handle, &priv->handle_lst_head, handle_lst) { - gs_free_error GError *error = NULL; + c_list_for_each_entry (handle, &priv->handle_lst_head, handle_lst) { + gs_free_error GError *local = NULL; - if (handle->is_failing_on_idle) - continue; + if (handle->is_failing_on_idle) + continue; - nm_utils_error_set_literal(&error, - NM_UTILS_ERROR_NOT_READY, - "timeout waiting for systemd-resolved to start"); - _resolve_complete_error(handle, error); - goto again; - } + nm_utils_error_set(&local, + NM_UTILS_ERROR_NOT_READY, + "error activating systemd-resolved: %s", + error->message); + _resolve_complete_error(handle, local); + goto again; + } + } else + _LOGD("systemd-resolved successfully started"); - return G_SOURCE_CONTINUE; + _update_pending_maybe_changed(self); } static NMTernary @@ -447,6 +568,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; @@ -459,16 +583,15 @@ ensure_resolved_running(NMDnsSystemdResolved *self) _LOGT("try D-Bus activating systemd-resolved..."); priv->try_start_blocked = TRUE; - - priv->try_start_timeout_source = - nm_g_timeout_add_source(4000, _ensure_resolved_running_timeout, self); - + nm_clear_g_cancellable(&priv->service_start_cancellable); + priv->service_start_cancellable = g_cancellable_new(); nm_dbus_connection_call_start_service_by_name(priv->dbus_connection, SYSTEMD_RESOLVED_DBUS_SERVICE, - -1, - NULL, - NULL, - NULL); + 4000, + priv->service_start_cancellable, + start_resolved_cb, + self); + _update_pending_maybe_changed(self); return NM_TERNARY_DEFAULT; } @@ -523,6 +646,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 +663,7 @@ send_updates(NMDnsSystemdResolved *self) -1, priv->cancellable, call_done, - request_item); + _request_item_ref(request_item)); } start_resolve: @@ -554,43 +683,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 +742,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; } @@ -636,8 +791,7 @@ name_owner_changed(NMDnsSystemdResolved *self, const char *owner) else _LOGT("D-Bus name for systemd-resolved has owner %s", owner); - nm_clear_g_source_inst(&priv->try_start_timeout_source); - + nm_clear_g_cancellable(&priv->service_start_cancellable); nm_strdup_reset(&priv->dbus_owner, owner); if (owner) { @@ -649,6 +803,7 @@ name_owner_changed(NMDnsSystemdResolved *self, const char *owner) } send_updates(self); + _update_pending_maybe_changed(self); } static void @@ -956,6 +1111,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_cancellable(&priv->service_start_cancellable); +} + +/*****************************************************************************/ + static void nm_dns_systemd_resolved_init(NMDnsSystemdResolved *self) { @@ -974,6 +1171,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 +1197,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); - - nm_clear_g_cancellable(&priv->cancellable); + NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(object); + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); - 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 +1216,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 8a75cf08..00000000 --- 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 - */ - -#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 feb33099..00000000 --- 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/main.c b/src/core/main.c index 1a9c3a65..2eb230d9 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -293,6 +293,7 @@ main(int argc, char *argv[]) GError *error_invalid_logging_config = NULL; const char *const *warnings; int errsv; + gboolean has_logging = FALSE; _nm_utils_is_manager_process = TRUE; @@ -354,10 +355,14 @@ main(int argc, char *argv[]) g_free(path); } - if (!nm_logging_setup(global_opt.opt_log_level, - global_opt.opt_log_domains, - &bad_domains, - &error)) { + if (nm_config_kernel_command_line_nm_debug()) { + /* we honor kernel command line. If "nm.debug" is set, we always enable trace logging. */ + nm_logging_setup("TRACE", "ALL", NULL, NULL); + has_logging = TRUE; + } else if (!nm_logging_setup(global_opt.opt_log_level, + global_opt.opt_log_domains, + &bad_domains, + &error)) { fprintf(stderr, _("%s. Please use --help to see a list of valid options.\n"), error->message); @@ -379,7 +384,7 @@ main(int argc, char *argv[]) /* Initialize logging from config file *only* if not explicitly * specified by commandline. */ - if (global_opt.opt_log_level == NULL && global_opt.opt_log_domains == NULL) { + if (!has_logging && !global_opt.opt_log_level && !global_opt.opt_log_domains) { if (!nm_logging_setup(nm_config_get_log_level(config), nm_config_get_log_domains(config), &bad_domains, @@ -417,9 +422,10 @@ main(int argc, char *argv[]) } nm_log_info(LOGD_CORE, - "NetworkManager (version " NM_DIST_VERSION ") is starting... (%s%s)", - nm_config_get_first_start(config) ? "for the first time" : "after a restart", - NM_MORE_ASSERTS != 0 ? ", asserts:" G_STRINGIFY(NM_MORE_ASSERTS) : ""); + "NetworkManager (version " NM_DIST_VERSION ") is starting... (%s%sboot:%s)", + nm_config_get_first_start(config) ? "" : "after a restart, ", + NM_MORE_ASSERTS != 0 ? "asserts:" G_STRINGIFY(NM_MORE_ASSERTS) ", " : "", + nm_utils_boot_id_str()); nm_log_info(LOGD_CORE, "Read config: %s", diff --git a/src/core/meson.build b/src/core/meson.build index 2148d23b..f3359ad0 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-data.c b/src/core/nm-config-data.c index ddb7787f..0f512e38 100644 --- a/src/core/nm-config-data.c +++ b/src/core/nm-config-data.c @@ -839,6 +839,13 @@ nm_config_data_log(const NMConfigData *self, _LOG(stream, prefix, "# no-auto-default specs \"%s\"", msg); } + if (nm_config_kernel_command_line_nm_debug()) { + _LOG(stream, + prefix, + "# /proc/cmdline contains \"" NM_CONFIG_KERNEL_CMDLINE_NM_DEBUG + "\". Debug log enabled"); + } + #undef _LOG } @@ -1681,7 +1688,7 @@ nm_config_data_get_connection_default_int64(const NMConfigData *self, const char *value; value = nm_config_data_get_connection_default(self, property, device); - return _nm_utils_ascii_str_to_int64(value, 10, min, max, fallback); + return _nm_utils_ascii_str_to_int64(value, 0, min, max, fallback); } static const char * diff --git a/src/core/nm-config.c b/src/core/nm-config.c index ea1c2ab3..3d23d4f6 100644 --- a/src/core/nm-config.c +++ b/src/core/nm-config.c @@ -11,7 +11,9 @@ #include #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" @@ -573,93 +575,93 @@ nm_config_cmd_line_options_add_to_entries(NMConfigCmdLineOptions *cli, GOptionCo { GOptionGroup *group; GOptionEntry config_options[] = { - {"config", - 0, - 0, - G_OPTION_ARG_FILENAME, - &cli->config_main_file, - N_("Config file location"), - DEFAULT_CONFIG_MAIN_FILE}, - {"config-dir", - 0, - 0, - G_OPTION_ARG_FILENAME, - &cli->config_dir, - N_("Config directory location"), - DEFAULT_CONFIG_DIR}, - {"system-config-dir", - 0, - 0, - G_OPTION_ARG_FILENAME, - &cli->system_config_dir, - N_("System config directory location"), - DEFAULT_SYSTEM_CONFIG_DIR}, - {"intern-config", - 0, - 0, - G_OPTION_ARG_FILENAME, - &cli->intern_config_file, - N_("Internal config file location"), - DEFAULT_INTERN_CONFIG_FILE}, - {"state-file", - 0, - 0, - G_OPTION_ARG_FILENAME, - &cli->state_file, - N_("State file location"), - DEFAULT_STATE_FILE}, - {"no-auto-default", - 0, - G_OPTION_FLAG_HIDDEN, - G_OPTION_ARG_FILENAME, - &cli->no_auto_default_file, - N_("State file for no-auto-default devices"), - DEFAULT_NO_AUTO_DEFAULT_FILE}, - {"plugins", - 0, - 0, - G_OPTION_ARG_STRING, - &cli->plugins, - N_("List of plugins separated by ','"), - NM_CONFIG_DEFAULT_MAIN_PLUGINS}, - {"configure-and-quit", - 0, - G_OPTION_FLAG_OPTIONAL_ARG, - G_OPTION_ARG_CALLBACK, - parse_configure_and_quit, - N_("Quit after initial configuration"), - NULL}, - {"debug", - 'd', - 0, - G_OPTION_ARG_NONE, - &cli->is_debug, - N_("Don't become a daemon, and log to stderr"), - NULL}, - - /* These three are hidden for now, and should eventually just go away. */ - {"connectivity-uri", - 0, - G_OPTION_FLAG_HIDDEN, - G_OPTION_ARG_STRING, - &cli->connectivity_uri, - N_("An http(s) address for checking internet connectivity"), - "http://example.com"}, - {"connectivity-interval", - 0, - G_OPTION_FLAG_HIDDEN, - G_OPTION_ARG_INT, - &cli->connectivity_interval, - N_("The interval between connectivity checks (in seconds)"), - G_STRINGIFY(NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL)}, - {"connectivity-response", - 0, - G_OPTION_FLAG_HIDDEN, - G_OPTION_ARG_STRING, - &cli->connectivity_response, - N_("The expected start of the response"), - NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE}, - {0}, + {"config", + 0, + 0, + G_OPTION_ARG_FILENAME, + &cli->config_main_file, + N_("Config file location"), + DEFAULT_CONFIG_MAIN_FILE}, + {"config-dir", + 0, + 0, + G_OPTION_ARG_FILENAME, + &cli->config_dir, + N_("Config directory location"), + DEFAULT_CONFIG_DIR}, + {"system-config-dir", + 0, + 0, + G_OPTION_ARG_FILENAME, + &cli->system_config_dir, + N_("System config directory location"), + DEFAULT_SYSTEM_CONFIG_DIR}, + {"intern-config", + 0, + 0, + G_OPTION_ARG_FILENAME, + &cli->intern_config_file, + N_("Internal config file location"), + DEFAULT_INTERN_CONFIG_FILE}, + {"state-file", + 0, + 0, + G_OPTION_ARG_FILENAME, + &cli->state_file, + N_("State file location"), + DEFAULT_STATE_FILE}, + {"no-auto-default", + 0, + G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_FILENAME, + &cli->no_auto_default_file, + N_("State file for no-auto-default devices"), + DEFAULT_NO_AUTO_DEFAULT_FILE}, + {"plugins", + 0, + 0, + G_OPTION_ARG_STRING, + &cli->plugins, + N_("List of plugins separated by ','"), + NM_CONFIG_DEFAULT_MAIN_PLUGINS}, + {"configure-and-quit", + 0, + G_OPTION_FLAG_OPTIONAL_ARG, + G_OPTION_ARG_CALLBACK, + parse_configure_and_quit, + N_("Quit after initial configuration"), + NULL}, + {"debug", + 'd', + 0, + G_OPTION_ARG_NONE, + &cli->is_debug, + N_("Don't become a daemon, and log to stderr"), + NULL}, + + /* These three are hidden for now, and should eventually just go away. */ + {"connectivity-uri", + 0, + G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_STRING, + &cli->connectivity_uri, + N_("An http(s) address for checking internet connectivity"), + "http://example.com"}, + {"connectivity-interval", + 0, + G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_INT, + &cli->connectivity_interval, + N_("The interval between connectivity checks (in seconds)"), + G_STRINGIFY(NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL)}, + {"connectivity-response", + 0, + G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_STRING, + &cli->connectivity_response, + N_("The expected start of the response"), + NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE}, + {0}, }; g_return_if_fail(opt_ctx); @@ -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); @@ -2978,6 +3014,15 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps /*****************************************************************************/ +gboolean +nm_config_kernel_command_line_nm_debug(void) +{ + return (nm_strv_find_first(nm_utils_proc_cmdline_split(), -1, NM_CONFIG_KERNEL_CMDLINE_NM_DEBUG) + >= 0); +} + +/*****************************************************************************/ + static gboolean init_sync(GInitable *initable, GCancellable *cancellable, GError **error) { diff --git a/src/core/nm-config.h b/src/core/nm-config.h index 2c23ff20..0dd159f4 100644 --- a/src/core/nm-config.h +++ b/src/core/nm-config.h @@ -18,6 +18,8 @@ #define NM_IS_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_CONFIG)) #define NM_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_CONFIG, NMConfigClass)) +#define NM_CONFIG_KERNEL_CMDLINE_NM_DEBUG "nm.debug" + /* Properties */ #define NM_CONFIG_CMD_LINE_OPTIONS "cmd-line-options" #define NM_CONFIG_ATOMIC_SECTION_PREFIXES "atomic-section-prefixes" @@ -183,9 +185,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); @@ -198,4 +199,8 @@ void nm_config_clear_warnings(NMConfig *config); /*****************************************************************************/ +gboolean nm_config_kernel_command_line_nm_debug(void); + +/*****************************************************************************/ + #endif /* __NETWORKMANAGER_CONFIG_H__ */ diff --git a/src/core/nm-connectivity.c b/src/core/nm-connectivity.c index eea8adb2..25ac3c7f 100644 --- a/src/core/nm-connectivity.c +++ b/src/core/nm-connectivity.c @@ -816,8 +816,7 @@ system_resolver_resolve_cb(GObject *source_object, GAsyncResult *res, gpointer u addr_family = AF_INET6; break; default: - addr_family = AF_UNSPEC; - break; + goto next; } if (cb_data->addr_family != AF_UNSPEC && cb_data->addr_family != addr_family) continue; @@ -832,6 +831,7 @@ system_resolver_resolve_cb(GObject *source_object, GAsyncResult *res, gpointer u nm_str_buf_append(&strbuf_hosts, nm_utils_inet_ntop(addr_family, g_inet_address_to_bytes(a), str_addr)); +next:; } g_list_free_full(list, g_object_unref); diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index 60c286ee..480e9b28 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" @@ -3094,7 +3093,10 @@ again: if (G_UNLIKELY(!proc_cmdline)) { gs_free char *str = NULL; - g_file_get_contents("/proc/cmdline", &str, NULL, NULL); + /* /run/NetworkManager/proc-cmdline can be used to overrule /proc/cmdline. */ + if (!g_file_get_contents(NMRUNDIR "/proc-cmdline", &str, NULL, NULL)) + g_file_get_contents("/proc/cmdline", &str, NULL, NULL); + str = nm_str_realloc(str); proc_cmdline = str ?: ""; @@ -5117,7 +5119,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'); @@ -5131,7 +5133,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, @@ -5226,7 +5228,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 @@ -5242,7 +5244,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; } @@ -5252,11 +5254,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 b32c9b70..394a3a49 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 cae0e11a..cdca4ef1 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-dispatcher.c b/src/core/nm-dispatcher.c index b6ff25ca..d3529ee4 100644 --- a/src/core/nm-dispatcher.c +++ b/src/core/nm-dispatcher.c @@ -56,6 +56,7 @@ struct NMDispatcherCallId { gpointer user_data; const char *log_ifname; const char *log_con_uuid; + gint64 start_at_msec; NMDispatcherAction action; guint idle_id; guint32 request_id; @@ -82,6 +83,7 @@ static struct { static NMDispatcherCallId * dispatcher_call_id_new(guint32 request_id, + gint64 start_at_msec, NMDispatcherAction action, NMDispatcherFunc callback, gpointer user_data, @@ -98,11 +100,12 @@ dispatcher_call_id_new(guint32 request_id, call_id = g_malloc(sizeof(NMDispatcherCallId) + l_log_ifname + l_log_con_uuid); - call_id->action = action; - call_id->request_id = request_id; - call_id->callback = callback; - call_id->user_data = user_data; - call_id->idle_id = 0; + call_id->action = action; + call_id->start_at_msec = start_at_msec; + call_id->request_id = request_id; + call_id->callback = callback; + call_id->user_data = user_data; + call_id->idle_id = 0; extra_strings = &call_id->extra_strings[0]; @@ -366,6 +369,8 @@ dispatch_result_to_string(DispatchResult result) static void dispatcher_results_process(guint32 request_id, + gint64 start_at_msec, + gint64 now_msec, const char *log_ifname, const char *log_con_uuid, GVariant *v_results) @@ -373,13 +378,22 @@ dispatcher_results_process(guint32 request_id, nm_auto_free_variant_iter GVariantIter *results = NULL; const char *script, *err; guint32 result; + gsize n_children; g_variant_get(v_results, "(a(sus))", &results); - if (g_variant_iter_n_children(results) == 0) { - _LOG2D(request_id, log_ifname, log_con_uuid, "succeeded but no scripts invoked"); + n_children = g_variant_iter_n_children(results); + + _LOG2D(request_id, + log_ifname, + log_con_uuid, + "succeeded (after %ld.%03d sec, %zu scripts invoked)", + (long int) ((now_msec - start_at_msec) / 1000), + (int) ((now_msec - start_at_msec) % 1000), + n_children); + + if (n_children == 0) return; - } while (g_variant_iter_next(results, "(&su&s)", &script, &result, &err)) { if (result == DISPATCH_RESULT_SUCCESS) { @@ -402,19 +416,30 @@ dispatcher_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) gs_unref_variant GVariant *ret = NULL; gs_free_error GError *error = NULL; NMDispatcherCallId *call_id = user_data; + gint64 now_msec; nm_assert((gpointer) source == gl.dbus_connection); + now_msec = nm_utils_get_monotonic_timestamp_msec(); + ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error); if (!ret) { + NMLogLevel log_level = LOGL_DEBUG; + if (_nm_dbus_error_has_name(error, "org.freedesktop.systemd1.LoadFailed")) { g_dbus_error_strip_remote_error(error); - _LOG3W(call_id, "failed to call dispatcher scripts: %s", error->message); - } else { - _LOG3D(call_id, "failed to call dispatcher scripts: %s", error->message); + log_level = LOGL_WARN; } + _NMLOG3(log_level, + call_id, + "failed to call dispatcher scripts (after %ld.%03d sec): %s", + (long int) ((now_msec - call_id->start_at_msec) / 1000), + (int) ((now_msec - call_id->start_at_msec) % 1000), + error->message); } else { dispatcher_results_process(call_id->request_id, + call_id->start_at_msec, + now_msec, call_id->log_ifname, call_id->log_con_uuid, ret); @@ -481,6 +506,8 @@ _dispatcher_call(NMDispatcherAction action, const char *connectivity_state_string = "UNKNOWN"; const char *log_ifname; const char *log_con_uuid; + gint64 start_at_msec; + gint64 now_msec; g_return_val_if_fail(!blocking || (!callback && !user_data), FALSE); @@ -596,6 +623,8 @@ _dispatcher_call(NMDispatcherAction action, &vpn_ip6_props, nm_logging_enabled(LOGL_DEBUG, LOGD_DISPATCH)); + start_at_msec = nm_utils_get_monotonic_timestamp_msec(); + /* Send the action to the dispatcher */ if (blocking) { gs_unref_variant GVariant *ret = NULL; @@ -612,17 +641,36 @@ _dispatcher_call(NMDispatcherAction action, CALL_TIMEOUT, NULL, &error); + + now_msec = nm_utils_get_monotonic_timestamp_msec(); + if (!ret) { g_dbus_error_strip_remote_error(error); - _LOG2W(request_id, log_ifname, log_con_uuid, "failed: %s", error->message); + _LOG2W(request_id, + log_ifname, + log_con_uuid, + "failed (after %ld.%03d sec): %s", + (long int) ((now_msec - start_at_msec) / 1000), + (int) ((now_msec - start_at_msec) % 1000), + error->message); return FALSE; } - dispatcher_results_process(request_id, log_ifname, log_con_uuid, ret); + dispatcher_results_process(request_id, + start_at_msec, + now_msec, + log_ifname, + log_con_uuid, + ret); return TRUE; } - call_id = - dispatcher_call_id_new(request_id, action, callback, user_data, log_ifname, log_con_uuid); + call_id = dispatcher_call_id_new(request_id, + start_at_msec, + action, + callback, + user_data, + log_ifname, + log_con_uuid); g_dbus_connection_call(gl.dbus_connection, NM_DISPATCHER_DBUS_SERVICE, diff --git a/src/core/nm-firewall-utils.c b/src/core/nm-firewall-utils.c index 8fa8059e..1311f503 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-hostname-manager.c b/src/core/nm-hostname-manager.c index 64c2531e..ba0c6c9d 100644 --- a/src/core/nm-hostname-manager.c +++ b/src/core/nm-hostname-manager.c @@ -239,7 +239,7 @@ _set_hostname_read_file(NMHostnameManager *self) #if defined(HOSTNAME_PERSIST_GENTOO) hostname = read_hostname_gentoo(HOSTNAME_FILE); #elif defined(HOSTNAME_PERSIST_SLACKWARE) - hostname = read_hostname_slackware(HOSTNAME_FILE); + hostname = read_hostname_slackware(HOSTNAME_FILE); #else if (g_file_get_contents(HOSTNAME_FILE, &hostname, NULL, NULL)) g_strchomp(hostname); @@ -321,39 +321,50 @@ nm_hostname_manager_get_transient_hostname(NMHostnameManager *self, char **hostn return TRUE; } -gboolean -nm_hostname_manager_write_hostname(NMHostnameManager *self, const char *hostname) +/*****************************************************************************/ + +static void +_write_hostname_dbus_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + gs_unref_object GTask *task = G_TASK(user_data); + gs_unref_variant GVariant *res = NULL; + GError *error = NULL; + + res = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), result, &error); + if (!res) { + g_task_return_error(task, error); + return; + } + g_task_return_boolean(task, TRUE); +} + +static void +_write_hostname_on_idle_cb(gpointer user_data, GCancellable *cancellable) { - NMHostnameManagerPrivate *priv; - char *hostname_eol; - gboolean ret; - gs_free_error GError *error = NULL; - const char *file = HOSTNAME_FILE; - gs_free char *link_path = NULL; - gs_unref_variant GVariant *var = NULL; - struct stat file_stat; + gs_unref_object GTask *task = G_TASK(user_data); + NMHostnameManager *self; + NMHostnameManagerPrivate *priv; + const char *hostname; + gs_free char *hostname_eol = NULL; + gboolean ret; + gs_free_error GError *error = NULL; + const char *file = HOSTNAME_FILE; + gs_free char *link_path = NULL; + struct stat file_stat; #if HAVE_SELINUX gboolean fcon_was_set = FALSE; char *fcon_prev = NULL; #endif - g_return_val_if_fail(NM_IS_HOSTNAME_MANAGER(self), FALSE); + if (g_task_return_error_if_cancelled(task)) + return; + self = g_task_get_source_object(task); priv = NM_HOSTNAME_MANAGER_GET_PRIVATE(self); - if (priv->hostnamed_proxy) { - var = g_dbus_proxy_call_sync(priv->hostnamed_proxy, - "SetStaticHostname", - g_variant_new("(sb)", hostname, FALSE), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - &error); - if (error) - _LOGW("could not set hostname: %s", error->message); - - return !error; - } + nm_assert(!priv->hostnamed_proxy); + + hostname = g_task_get_task_data(task); /* If the hostname file is a symbolic link, follow it to find where the * real file is located, otherwise g_file_set_contents will attempt to @@ -363,13 +374,15 @@ nm_hostname_manager_write_hostname(NMHostnameManager *self, const char *hostname && (link_path = nm_utils_read_link_absolute(file, NULL))) file = link_path; + if (hostname) { #if defined(HOSTNAME_PERSIST_GENTOO) - hostname_eol = g_strdup_printf("#Generated by NetworkManager\n" - "hostname=\"%s\"\n", - hostname); + hostname_eol = g_strdup_printf("#Generated by NetworkManager\n" + "hostname=\"%s\"\n", + hostname); #else - hostname_eol = g_strdup_printf("%s\n", hostname); + hostname_eol = g_strdup_printf("%s\n", hostname); #endif + } #if HAVE_SELINUX /* Get default context for hostname file and set it for fscreate */ @@ -396,7 +409,7 @@ nm_hostname_manager_write_hostname(NMHostnameManager *self, const char *hostname } #endif - ret = g_file_set_contents(file, hostname_eol, -1, &error); + ret = g_file_set_contents(file, hostname_eol ?: "", -1, &error); #if HAVE_SELINUX /* Restore previous context and cleanup */ @@ -406,14 +419,63 @@ nm_hostname_manager_write_hostname(NMHostnameManager *self, const char *hostname freecon(fcon_prev); #endif - g_free(hostname_eol); - if (!ret) { - _LOGW("could not save hostname to %s: %s", file, error->message); - return FALSE; + g_task_return_new_error(task, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "could not save hostname to %s: %s", + file, + error->message); + return; } - return TRUE; + g_task_return_boolean(task, TRUE); +} + +void +nm_hostname_manager_write_hostname(NMHostnameManager *self, + const char *hostname, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + NMHostnameManagerPrivate *priv; + GTask *task; + + g_return_if_fail(NM_IS_HOSTNAME_MANAGER(self)); + + priv = NM_HOSTNAME_MANAGER_GET_PRIVATE(self); + + task = + nm_g_task_new(self, cancellable, nm_hostname_manager_write_hostname, callback, user_data); + + g_task_set_task_data(task, g_strdup(hostname), g_free); + + if (priv->hostnamed_proxy) { + g_dbus_proxy_call(priv->hostnamed_proxy, + "SetStaticHostname", + g_variant_new("(sb)", hostname ?: "", FALSE), + G_DBUS_CALL_FLAGS_NONE, + 15000, + cancellable, + _write_hostname_dbus_cb, + task); + return; + } + + nm_utils_invoke_on_idle(cancellable, _write_hostname_on_idle_cb, task); +} + +gboolean +nm_hostname_manager_write_hostname_finish(NMHostnameManager *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail(NM_IS_HOSTNAME_MANAGER(self), FALSE); + g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_hostname_manager_write_hostname), + FALSE); + + return g_task_propagate_boolean(G_TASK(result), error); } /*****************************************************************************/ diff --git a/src/core/nm-hostname-manager.h b/src/core/nm-hostname-manager.h index b871d177..31596819 100644 --- a/src/core/nm-hostname-manager.h +++ b/src/core/nm-hostname-manager.h @@ -36,7 +36,15 @@ NMHostnameManager *nm_hostname_manager_get(void); const char *nm_hostname_manager_get_static_hostname(NMHostnameManager *self); -gboolean nm_hostname_manager_write_hostname(NMHostnameManager *self, const char *hostname); +void nm_hostname_manager_write_hostname(NMHostnameManager *self, + const char *hostname, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean nm_hostname_manager_write_hostname_finish(NMHostnameManager *self, + GAsyncResult *result, + GError **error); void nm_hostname_manager_set_transient_hostname(NMHostnameManager *self, const char *hostname, diff --git a/src/core/nm-l3-config-data.c b/src/core/nm-l3-config-data.c index 2a722756..bcd0b62a 100644 --- a/src/core/nm-l3-config-data.c +++ b/src/core/nm-l3-config-data.c @@ -149,6 +149,8 @@ struct _NML3ConfigData { NMSettingIP6ConfigPrivacy ip6_privacy : 4; + NMMptcpFlags mptcp_flags : 18; + bool is_sealed : 1; bool has_routes_with_type_local_4_set : 1; @@ -582,6 +584,16 @@ nm_l3_config_data_log(const NML3ConfigData *self, NULL))); } + if (self->mptcp_flags != NM_MPTCP_FLAGS_NONE) { + gs_free char *s = NULL; + + _L("mptcp-flags: %s", + (s = _nm_utils_enum_to_str_full(nm_mptcp_flags_get_type(), + self->mptcp_flags, + " ", + NULL))); + } + if (self->ip6_token.id != 0) { _L("ipv6-token: %s", nm_utils_inet6_interface_identifier_to_token(&self->ip6_token, sbuf_addr)); @@ -694,6 +706,7 @@ nm_l3_config_data_new(NMDedupMultiIndex *multi_idx, int ifindex, NMIPConfigSourc .never_default_4 = NM_OPTION_BOOL_DEFAULT, .source = source, .ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, + .mptcp_flags = NM_MPTCP_FLAGS_NONE, .ndisc_hop_limit_set = FALSE, .ndisc_reachable_time_msec_set = FALSE, .ndisc_retrans_timer_msec_set = FALSE, @@ -1875,6 +1888,30 @@ nm_l3_config_data_set_ip6_token(NML3ConfigData *self, NMUtilsIPv6IfaceId ipv6_to return TRUE; } +NMMptcpFlags +nm_l3_config_data_get_mptcp_flags(const NML3ConfigData *self) +{ + nm_assert(!self || _NM_IS_L3_CONFIG_DATA(self, TRUE)); + + if (!self) + return NM_MPTCP_FLAGS_NONE; + + return self->mptcp_flags; +} + +gboolean +nm_l3_config_data_set_mptcp_flags(NML3ConfigData *self, NMMptcpFlags mptcp_flags) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + nm_assert(!NM_FLAGS_ANY(mptcp_flags, ~_NM_MPTCP_FLAGS_ALL)); + + if (self->mptcp_flags == mptcp_flags) + return FALSE; + self->mptcp_flags = mptcp_flags; + nm_assert(self->mptcp_flags == mptcp_flags); + return TRUE; +} + NMProxyConfigMethod nm_l3_config_data_get_proxy_method(const NML3ConfigData *self) { @@ -2324,6 +2361,7 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a, NM_CMP_DIRECT_REF_STRING(a->proxy_pac_url, b->proxy_pac_url); NM_CMP_DIRECT_REF_STRING(a->proxy_pac_script, b->proxy_pac_script); NM_CMP_DIRECT_UNSAFE(a->ip6_privacy, b->ip6_privacy); + NM_CMP_DIRECT_UNSAFE(a->mptcp_flags, b->mptcp_flags); NM_CMP_DIRECT_UNSAFE(a->ndisc_hop_limit_set, b->ndisc_hop_limit_set); if (a->ndisc_hop_limit_set) @@ -2613,9 +2651,6 @@ nm_l3_config_data_add_dependent_device_routes(NML3ConfigData *self, const gboolean has_peer = !IN6_IS_ADDR_UNSPECIFIED(&addr_src->a6.peer_address); int routes_i; - if (addr_src->ax.plen == 0) - continue; - if (NM_FLAGS_HAS(addr_src->a6.n_ifa_flags, IFA_F_NOPREFIXROUTE)) continue; @@ -2999,10 +3034,10 @@ nm_l3_config_data_merge(NML3ConfigData *self, gpointer hook_user_data) { static const guint32 x_default_route_metric_x[2] = {NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6, - NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4}; + NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4}; static const guint32 x_default_route_penalty_x[2] = {0, 0}; static const int x_default_dns_priority_x[2] = {NM_DNS_PRIORITY_DEFAULT_NORMAL, - NM_DNS_PRIORITY_DEFAULT_NORMAL}; + NM_DNS_PRIORITY_DEFAULT_NORMAL}; guint32 default_route_table_coerced_x[2]; NMDedupMultiIter iter; const NMPObject *obj; @@ -3245,6 +3280,9 @@ nm_l3_config_data_merge(NML3ConfigData *self, if (self->ip6_privacy == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) self->ip6_privacy = src->ip6_privacy; + if (self->mptcp_flags == NM_MPTCP_FLAGS_NONE) + self->mptcp_flags = src->mptcp_flags; + if (!self->ndisc_hop_limit_set && src->ndisc_hop_limit_set) { self->ndisc_hop_limit_set = TRUE; self->ndisc_hop_limit_val = src->ndisc_hop_limit_val; diff --git a/src/core/nm-l3-config-data.h b/src/core/nm-l3-config-data.h index 20a32c62..ca42d4a1 100644 --- a/src/core/nm-l3-config-data.h +++ b/src/core/nm-l3-config-data.h @@ -487,6 +487,10 @@ NMUtilsIPv6IfaceId nm_l3_config_data_get_ip6_token(const NML3ConfigData *self); gboolean nm_l3_config_data_set_ip6_token(NML3ConfigData *self, NMUtilsIPv6IfaceId ipv6_token); +NMMptcpFlags nm_l3_config_data_get_mptcp_flags(const NML3ConfigData *self); + +gboolean nm_l3_config_data_set_mptcp_flags(NML3ConfigData *self, NMMptcpFlags mptcp_flags); + const in_addr_t *nm_l3_config_data_get_wins(const NML3ConfigData *self, guint *out_len); gboolean nm_l3_config_data_add_wins(NML3ConfigData *self, in_addr_t wins); diff --git a/src/core/nm-l3-ipv4ll.c b/src/core/nm-l3-ipv4ll.c index 2aedab56..3fc1e165 100644 --- a/src/core/nm-l3-ipv4ll.c +++ b/src/core/nm-l3-ipv4ll.c @@ -672,7 +672,9 @@ _ipv4ll_platform_find_addr(NML3IPv4LL *self, const NML3AcdAddrInfo **out_acd_inf const NML3AcdAddrInfo *acd_info; const NMPlatformIP4Address *addr; - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP4_ADDRESS, nm_l3_ipv4ll_get_ifindex(self)); + nmp_lookup_init_object_by_ifindex(&lookup, + NMP_OBJECT_TYPE_IP4_ADDRESS, + nm_l3_ipv4ll_get_ifindex(self)); nm_platform_iter_obj_for_each (&iter, nm_l3_ipv4ll_get_platform(self), &lookup, &obj) { addr = NMP_OBJECT_CAST_IP4_ADDRESS(obj); if (!_ip4_address_is_link_local(addr)) diff --git a/src/core/nm-l3-ipv6ll.c b/src/core/nm-l3-ipv6ll.c index 2b9a1a0e..2640c075 100644 --- a/src/core/nm-l3-ipv6ll.c +++ b/src/core/nm-l3-ipv6ll.c @@ -343,7 +343,9 @@ _pladdr_find_ll(NML3IPv6LL *self, gboolean *out_cur_addr_failed) if (!NM_IN_SET(self->state, NM_L3_IPV6LL_STATE_DAD_IN_PROGRESS, NM_L3_IPV6LL_STATE_READY)) cur_addr_check = FALSE; - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, nm_l3_ipv6ll_get_ifindex(self)); + nmp_lookup_init_object_by_ifindex(&lookup, + NMP_OBJECT_TYPE_IP6_ADDRESS, + nm_l3_ipv6ll_get_ifindex(self)); nm_platform_iter_obj_for_each (&iter, nm_l3_ipv6ll_get_platform(self), &lookup, &obj) { const NMPlatformIP6Address *pladdr = NMP_OBJECT_CAST_IP6_ADDRESS(obj); diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index af6099e9..b2fbb031 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -4,6 +4,8 @@ #include "nm-l3cfg.h" +#include "libnm-std-aux/nm-linux-compat.h" + #include #include #include @@ -12,7 +14,7 @@ #include "libnm-glib-aux/nm-time-utils.h" #include "libnm-platform/nm-platform.h" #include "libnm-platform/nmp-object.h" -#include "libnm-platform/nmp-route-manager.h" +#include "libnm-platform/nmp-global-tracker.h" #include "nm-netns.h" #include "n-acd/src/n-acd.h" #include "nm-l3-ipv4ll.h" @@ -37,7 +39,6 @@ G_STATIC_ASSERT(NM_ACD_TIMEOUT_RFC5227_MSEC == N_ACD_TIMEOUT_RFC5227); #define ACD_ENSURE_RATELIMIT_MSEC ((guint32) 4000u) #define ACD_WAIT_PROBING_EXTRA_TIME_MSEC ((guint32) (1000u + ACD_ENSURE_RATELIMIT_MSEC)) #define ACD_WAIT_PROBING_EXTRA_TIME2_MSEC ((guint32) 1000u) -#define ACD_MAX_TIMEOUT_MSEC ((guint32) 30000u) #define ACD_WAIT_TIME_PROBING_FULL_RESTART_MSEC ((guint32) 30000u) #define ACD_WAIT_TIME_CONFLICT_RESTART_MSEC ((guint32) 120000u) #define ACD_WAIT_TIME_ANNOUNCE_RESTART_MSEC ((guint32) 30000u) @@ -271,6 +272,15 @@ typedef struct _NML3CfgPrivate { NMIPConfig *ipconfig_x[2]; }; + /* Whether we earlier configured MPTCP endpoints for the interface. */ + union { + struct { + bool mptcp_set_6; + bool mptcp_set_4; + }; + bool mptcp_set_x[2]; + }; + /* This is for rate-limiting the creation of nacd instance. */ GSource *nacd_instance_ensure_retry; @@ -312,6 +322,9 @@ typedef struct _NML3CfgPrivate { bool changed_configs_configs : 1; bool changed_configs_acd_state : 1; + + bool rp_filter_handled : 1; + bool rp_filter_set : 1; } NML3CfgPrivate; struct _NML3CfgClass { @@ -322,6 +335,13 @@ G_DEFINE_TYPE(NML3Cfg, nm_l3cfg, G_TYPE_OBJECT) /*****************************************************************************/ +#define _NODEV_ROUTES_TAG(self, IS_IPv4) \ + ((gconstpointer) (&(((const char *) (self))[0 + (!(IS_IPv4))]))) + +#define _MPTCP_TAG(self, IS_IPv4) ((gconstpointer) (&(((const char *) (self))[2 + (!(IS_IPv4))]))) + +/*****************************************************************************/ + #define _NMLOG_DOMAIN LOGD_CORE #define _NMLOG_PREFIX_NAME "l3cfg" #define _NMLOG(level, ...) \ @@ -1880,10 +1900,10 @@ _l3_acd_data_add(NML3Cfg *self, acd_data = _l3_acd_data_find(self, addr); - if (acd_timeout_msec > ACD_MAX_TIMEOUT_MSEC) { + if (acd_timeout_msec > NM_ACD_TIMEOUT_MAX_MSEC) { /* we limit the maximum timeout. Otherwise we have to handle integer overflow * when adding timeouts. */ - acd_timeout_msec = ACD_MAX_TIMEOUT_MSEC; + acd_timeout_msec = NM_ACD_TIMEOUT_MAX_MSEC; } if (!acd_data) { @@ -3243,8 +3263,8 @@ nm_l3cfg_add_config(NML3Cfg *self, nm_assert(l3cd); nm_assert(nm_l3_config_data_get_ifindex(l3cd) == self->priv.ifindex); - if (acd_timeout_msec > ACD_MAX_TIMEOUT_MSEC) - acd_timeout_msec = ACD_MAX_TIMEOUT_MSEC; + if (acd_timeout_msec > NM_ACD_TIMEOUT_MAX_MSEC) + acd_timeout_msec = NM_ACD_TIMEOUT_MAX_MSEC; nm_assert(NM_IN_SET(acd_defend_type, NM_L3_ACD_DEFEND_TYPE_NEVER, @@ -3451,15 +3471,13 @@ nm_l3cfg_remove_config_all_dirty(NML3Cfg *self, gconstpointer tag) /*****************************************************************************/ -#define _NODEV_ROUTES_TAG(self, IS_IPv4) ((gconstpointer) (&(&(self)->priv.route_manager)[IS_IPv4])) - static gboolean _nodev_routes_untrack(NML3Cfg *self, int addr_family) { - return nmp_route_manager_untrack_all(self->priv.route_manager, - _NODEV_ROUTES_TAG(self, NM_IS_IPv4(addr_family)), - FALSE, - TRUE); + return nmp_global_tracker_untrack_all(self->priv.global_tracker, + _NODEV_ROUTES_TAG(self, NM_IS_IPv4(addr_family)), + FALSE, + TRUE); } static void @@ -3479,12 +3497,12 @@ _nodev_routes_sync(NML3Cfg *self, for (i = 0; i < routes_nodev->len; i++) { const NMPObject *obj = routes_nodev->pdata[i]; - if (nmp_route_manager_track(self->priv.route_manager, - obj_type, - NMP_OBJECT_CAST_IP_ROUTE(obj), - 1, - _NODEV_ROUTES_TAG(self, IS_IPv4), - NULL)) + if (nmp_global_tracker_track(self->priv.global_tracker, + obj_type, + NMP_OBJECT_CAST_IP_ROUTE(obj), + 1, + _NODEV_ROUTES_TAG(self, IS_IPv4), + NULL)) changed = TRUE; } @@ -3492,8 +3510,11 @@ out_clear: if (_nodev_routes_untrack(self, addr_family)) changed = TRUE; - if (changed || commit_type >= NM_L3_CFG_COMMIT_TYPE_REAPPLY) - nmp_route_manager_sync(self->priv.route_manager, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4), FALSE); + if (changed || commit_type >= NM_L3_CFG_COMMIT_TYPE_REAPPLY) { + nmp_global_tracker_sync(self->priv.global_tracker, + NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4), + FALSE); + } } /*****************************************************************************/ @@ -4182,6 +4203,259 @@ _l3_commit_ip6_token(NML3Cfg *self, NML3CfgCommitType commit_type) } } +/*****************************************************************************/ + +static void +_rp_filter_update(NML3Cfg *self, gboolean reapply) +{ + gboolean rp_filter_relax = FALSE; + const char *ifname; + int rf_val; + + /* The rp_filter sysctl is only an IPv4 thing. We only enable the rp-filter + * handling, if we did anything to MPTCP about IPv4 addresses. + * + * While we only have one "connection.mptcp-flags=enabled" property, whether + * we handle MPTCP is still tracked per AF. In particular, with "enabled-on-global-iface" + * flag, which honors the AF-specific default route. */ + if (self->priv.p->mptcp_set_4) + rp_filter_relax = TRUE; + + if (!rp_filter_relax) { + if (self->priv.p->rp_filter_handled) { + self->priv.p->rp_filter_handled = FALSE; + if (self->priv.p->rp_filter_set) { + self->priv.p->rp_filter_set = FALSE; + + ifname = nm_l3cfg_get_ifname(self, TRUE); + rf_val = nm_platform_sysctl_ip_conf_get_rp_filter_ipv4(self->priv.platform, + ifname, + FALSE, + NULL); + if (rf_val == 2) { + /* We only relaxed from 1 to 2. Only if that is still the case, reset. */ + nm_platform_sysctl_ip_conf_set(self->priv.platform, + AF_INET, + ifname, + "rp_filter", + "1"); + } + } + } + return; + } + + if (self->priv.p->rp_filter_handled && !reapply) { + /* We only set rp_filter once (except reapply). */ + return; + } + + /* No matter whether we actually reset the value below, we set the "handled" flag + * so that we only do this once (except during reapply). */ + self->priv.p->rp_filter_handled = TRUE; + + ifname = nm_l3cfg_get_ifname(self, TRUE); + + rf_val = + nm_platform_sysctl_ip_conf_get_rp_filter_ipv4(self->priv.platform, ifname, FALSE, NULL); + + if (rf_val != 1) { + /* We only relax from strict (1) to loose (2). No other transition. Nothing to do. */ + return; + } + + /* We actually loosen the flag. We need to remember to reset it. */ + self->priv.p->rp_filter_set = TRUE; + nm_platform_sysctl_ip_conf_set(self->priv.platform, AF_INET, ifname, "rp_filter", "2"); +} + +/*****************************************************************************/ + +static gboolean +_global_tracker_mptcp_untrack(NML3Cfg *self, int addr_family) +{ + return nmp_global_tracker_untrack_all(self->priv.global_tracker, + _MPTCP_TAG(self, NM_IS_IPv4(addr_family)), + FALSE, + TRUE); +} + +static gboolean +_l3_commit_mptcp_af(NML3Cfg *self, + NML3CfgCommitType commit_type, + int addr_family, + gboolean *out_reapply) +{ + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMMptcpFlags mptcp_flags; + gboolean reapply = FALSE; + gboolean changed = FALSE; + + nm_assert(NM_IS_L3CFG(self)); + nm_assert(NM_IN_SET(commit_type, + NM_L3_CFG_COMMIT_TYPE_NONE, + NM_L3_CFG_COMMIT_TYPE_REAPPLY, + NM_L3_CFG_COMMIT_TYPE_UPDATE)); + + if (commit_type >= NM_L3_CFG_COMMIT_TYPE_REAPPLY) + reapply = TRUE; + + if (commit_type != NM_L3_CFG_COMMIT_TYPE_NONE && self->priv.p->combined_l3cd_commited) + mptcp_flags = nm_l3_config_data_get_mptcp_flags(self->priv.p->combined_l3cd_commited); + else + mptcp_flags = NM_MPTCP_FLAGS_DISABLED; + + if (mptcp_flags == NM_MPTCP_FLAGS_NONE || NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_DISABLED)) + mptcp_flags = NM_MPTCP_FLAGS_DISABLED; + else if (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_ENABLED_ON_GLOBAL_IFACE)) { + /* Whether MPTCP is enabled/disabled, depends on whether we have a unicast default + * route (in the main routing table). */ + if (self->priv.p->combined_l3cd_commited + && nm_l3_config_data_get_best_default_route(self->priv.p->combined_l3cd_commited, + addr_family)) + mptcp_flags = NM_FLAGS_UNSET(mptcp_flags, NM_MPTCP_FLAGS_ENABLED_ON_GLOBAL_IFACE) + | NM_MPTCP_FLAGS_ENABLED; + else + mptcp_flags = NM_MPTCP_FLAGS_DISABLED; + } else + mptcp_flags |= NM_MPTCP_FLAGS_ENABLED; + + if (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_DISABLED)) { + if (!self->priv.p->mptcp_set_x[IS_IPv4] && !reapply) { + /* Nothing to configure, and we did not earlier configure MPTCP. Nothing to do. */ + NM_SET_OUT(out_reapply, FALSE); + return FALSE; + } + + self->priv.p->mptcp_set_x[IS_IPv4] = FALSE; + reapply = TRUE; + } else { + const NMPlatformIPXAddress *addr; + NMDedupMultiIter iter; + const guint32 FLAGS = + (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_SIGNAL) ? MPTCP_PM_ADDR_FLAG_SIGNAL : 0) + | (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_SUBFLOW) ? MPTCP_PM_ADDR_FLAG_SUBFLOW : 0) + | (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_BACKUP) ? MPTCP_PM_ADDR_FLAG_BACKUP : 0) + | (NM_FLAGS_HAS(mptcp_flags, NM_MPTCP_FLAGS_FULLMESH) ? MPTCP_PM_ADDR_FLAG_FULLMESH + : 0); + NMPlatformMptcpAddr a = { + .ifindex = self->priv.ifindex, + .id = 0, + .flags = FLAGS, + .addr_family = addr_family, + .port = 0, + }; + gboolean any_tracked = FALSE; + + self->priv.p->mptcp_set_x[IS_IPv4] = TRUE; + + if (self->priv.p->combined_l3cd_commited) { + gint32 addr_prio; + + addr_prio = 100; + + nm_l3_config_data_iter_ip_address_for_each (&iter, + self->priv.p->combined_l3cd_commited, + addr_family, + (const NMPlatformIPAddress **) &addr) { + /* We want to evaluate the with-{loopback,link_local}-{4,6} flags based on the actual + * ifa_scope that the address will have once we configure it. + * "addr" is an address we want to configure, we expect that it will + * later have the scope nm_platform_ip_address_get_scope() based on + * the address. */ + switch (nm_platform_ip_address_get_scope(addr_family, addr->ax.address_ptr)) { + case RT_SCOPE_HOST: + goto skip_addr; + case RT_SCOPE_LINK: + goto skip_addr; + default: + if (IS_IPv4) { + /* We take all addresses, including rfc1918 private addresses + * (nm_utils_ip_is_site_local()). */ + } else { + if (nm_utils_ip6_is_ula(&addr->a6.address)) { + /* Exclude unique local IPv6 addresses fc00::/7. */ + goto skip_addr; + } else { + /* We take all other addresses, including deprecated IN6_IS_ADDR_SITELOCAL() + * (fec0::/10). */ + } + } + break; + } + + a.addr = nm_ip_addr_init(addr_family, addr->ax.address_ptr); + + /* We track the address with different priorities, that depends + * on the order in which they are listed here. NMPGlobalTracker + * will sort all tracked addresses by priority. That means, if we + * have multiple interfaces then we will prefer the first address + * of those interfaces, then the second, etc. + * + * That is relevant, because the overall number of addresses we + * can configure in kernel is strongly limited (MPTCP_PM_ADDR_MAX). */ + if (addr_prio > 10) + addr_prio--; + + if (nmp_global_tracker_track(self->priv.global_tracker, + NMP_OBJECT_TYPE_MPTCP_ADDR, + &a, + addr_prio, + _MPTCP_TAG(self, IS_IPv4), + NULL)) + changed = TRUE; + + any_tracked = TRUE; + +skip_addr: + (void) 0; + } + } + + if (!any_tracked) { + /* We need to make it known that this ifindex is used. Track a dummy object. */ + if (nmp_global_tracker_track( + self->priv.global_tracker, + NMP_OBJECT_TYPE_MPTCP_ADDR, + nmp_global_tracker_mptcp_addr_init_for_ifindex(&a, self->priv.ifindex), + 1, + _MPTCP_TAG(self, IS_IPv4), + NULL)) + changed = TRUE; + } + } + + if (_global_tracker_mptcp_untrack(self, addr_family)) + changed = TRUE; + + NM_SET_OUT(out_reapply, reapply); + return changed || reapply; +} + +static void +_l3_commit_mptcp(NML3Cfg *self, NML3CfgCommitType commit_type) +{ + gboolean changed = FALSE; + gboolean reapply = FALSE; + gboolean i_reapply = FALSE; + + if (_l3_commit_mptcp_af(self, commit_type, AF_INET, &i_reapply)) + changed = TRUE; + reapply |= i_reapply; + if (_l3_commit_mptcp_af(self, commit_type, AF_INET6, &i_reapply)) + changed = TRUE; + reapply |= i_reapply; + + nm_assert(commit_type < NM_L3_CFG_COMMIT_TYPE_REAPPLY || reapply); + + if (changed) + nmp_global_tracker_sync_mptcp_addrs(self->priv.global_tracker, reapply); + else + nm_assert(!reapply); + + _rp_filter_update(self, reapply); +} + static gboolean _l3_commit_one(NML3Cfg *self, int addr_family, @@ -4380,6 +4654,8 @@ _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle) _l3_commit_one(self, AF_INET, commit_type, changed_combined_l3cd, l3cd_old); _l3_commit_one(self, AF_INET6, commit_type, changed_combined_l3cd, l3cd_old); + _l3_commit_mptcp(self, commit_type); + _l3_acd_data_process_changes(self); if (self->priv.p->l3_config_datas) { @@ -4626,7 +4902,9 @@ nm_l3cfg_has_commited_ip6_addresses_pending_dad(NML3Cfg *self) * Of course, all lookups are O(1) anyway, so in any case the operation is * O(n) (once "n" being the addresses in platform, and once in l3cd). */ - nmp_lookup_init_object(&plat_lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, self->priv.ifindex); + nmp_lookup_init_object_by_ifindex(&plat_lookup, + NMP_OBJECT_TYPE_IP6_ADDRESS, + self->priv.ifindex); nm_platform_iter_obj_for_each (&iter, self->priv.platform, &plat_lookup, &plat_obj) { const NMPlatformIP6Address *plat_addr = NMP_OBJECT_CAST_IP6_ADDRESS(plat_obj); @@ -4763,7 +5041,8 @@ constructed(GObject *object) self->priv.platform = g_object_ref(nm_netns_get_platform(self->priv.netns)); nm_assert(NM_IS_PLATFORM(self->priv.platform)); - self->priv.route_manager = nmp_route_manager_ref(nm_netns_get_route_manager(self->priv.netns)); + self->priv.global_tracker = + nmp_global_tracker_ref(nm_netns_get_global_tracker(self->priv.netns)); _LOGT("created (netns=" NM_HASH_OBFUSCATE_PTR_FMT ")", NM_HASH_OBFUSCATE_PTR(self->priv.netns)); @@ -4785,6 +5064,7 @@ static void finalize(GObject *object) { NML3Cfg *self = NM_L3CFG(object); + gboolean changed; nm_assert(!self->priv.p->ipconfig_4); nm_assert(!self->priv.p->ipconfig_6); @@ -4818,13 +5098,21 @@ finalize(GObject *object) nm_assert(c_list_is_empty(&self->priv.p->obj_state_zombie_lst_head)); if (_nodev_routes_untrack(self, AF_INET)) - nmp_route_manager_sync(self->priv.route_manager, NMP_OBJECT_TYPE_IP4_ROUTE, FALSE); + nmp_global_tracker_sync(self->priv.global_tracker, NMP_OBJECT_TYPE_IP4_ROUTE, FALSE); if (_nodev_routes_untrack(self, AF_INET6)) - nmp_route_manager_sync(self->priv.route_manager, NMP_OBJECT_TYPE_IP6_ROUTE, FALSE); + nmp_global_tracker_sync(self->priv.global_tracker, NMP_OBJECT_TYPE_IP6_ROUTE, FALSE); + + changed = FALSE; + if (_global_tracker_mptcp_untrack(self, AF_INET)) + changed = TRUE; + if (_global_tracker_mptcp_untrack(self, AF_INET6)) + changed = TRUE; + if (changed) + nmp_global_tracker_sync_mptcp_addrs(self->priv.global_tracker, FALSE); g_clear_object(&self->priv.netns); g_clear_object(&self->priv.platform); - nm_clear_pointer(&self->priv.route_manager, nmp_route_manager_unref); + nm_clear_pointer(&self->priv.global_tracker, nmp_global_tracker_unref); nm_clear_l3cd(&self->priv.p->combined_l3cd_merged); nm_clear_l3cd(&self->priv.p->combined_l3cd_commited); diff --git a/src/core/nm-l3cfg.h b/src/core/nm-l3cfg.h index 215d21e9..e0257623 100644 --- a/src/core/nm-l3cfg.h +++ b/src/core/nm-l3cfg.h @@ -10,6 +10,7 @@ #define NM_L3CFG_CONFIG_PRIORITY_IPV6LL 1 #define NM_L3CFG_CONFIG_PRIORITY_VPN 9 #define NM_ACD_TIMEOUT_RFC5227_MSEC 9000u +#define NM_ACD_TIMEOUT_MAX_MSEC 30000u #define NM_TYPE_L3CFG (nm_l3cfg_get_type()) #define NM_L3CFG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_L3CFG, NML3Cfg)) @@ -195,18 +196,18 @@ typedef struct { } NML3ConfigNotifyData; struct _NML3CfgPrivate; -struct _NMPRouteManager; +struct _NMPGlobalTracker; struct _NML3Cfg { GObject parent; struct { - struct _NML3CfgPrivate *p; - NMNetns *netns; - NMPlatform *platform; - struct _NMPRouteManager *route_manager; - const NMPObject *plobj; - const NMPObject *plobj_next; - int ifindex; + struct _NML3CfgPrivate *p; + NMNetns *netns; + NMPlatform *platform; + struct _NMPGlobalTracker *global_tracker; + const NMPObject *plobj; + const NMPObject *plobj_next; + int ifindex; } priv; }; diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index 52153697..3af24aa0 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 */ @@ -209,6 +213,10 @@ typedef struct { unsigned connectivity_check_enabled_last : 2; + /* List of GDBusMethodInvocation of in progress Sleep() and Enable() + * calls. They return only if all in-flight deactivations finished. */ + GSList *sleep_invocations; + guint delete_volatile_connection_idle_id; CList delete_volatile_connection_lst_head; } NMManagerPrivate; @@ -346,6 +354,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 +1612,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 +1631,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) { @@ -2221,6 +2250,18 @@ connection_updated_cb(NMSettings *settings, connection_changed(self, sett_conn); } +static void +connections_changed(NMManager *self) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self); + NMSettingsConnection *const *connections; + guint i; + + connections = nm_settings_get_connections_sorted_by_autoconnect_priority(priv->settings, NULL); + for (i = 0; connections[i]; i++) + connection_changed(self, connections[i]); +} + /*****************************************************************************/ static void @@ -6336,6 +6377,22 @@ done: g_clear_object(&subject); } +static void +sleep_devices_check_empty(NMManager *self) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self); + GDBusMethodInvocation *invocation; + + if (g_hash_table_size(priv->sleep_devices) > 0) + return; + + while (priv->sleep_invocations) { + invocation = priv->sleep_invocations->data; + g_dbus_method_invocation_return_value(invocation, NULL); + priv->sleep_invocations = g_slist_remove(priv->sleep_invocations, invocation); + } +} + static gboolean sleep_devices_add(NMManager *self, NMDevice *device, gboolean suspending) { @@ -6378,6 +6435,9 @@ sleep_devices_remove(NMManager *self, NMDevice *device) g_signal_handlers_disconnect_by_func(device, device_sleep_cb, self); g_hash_table_remove(priv->sleep_devices, device); g_object_unref(device); + + sleep_devices_check_empty(self); + return TRUE; } @@ -6389,9 +6449,6 @@ sleep_devices_clear(NMManager *self) NMSleepMonitorInhibitorHandle *handle; GHashTableIter iter; - if (!priv->sleep_devices) - return; - g_hash_table_iter_init(&iter, priv->sleep_devices); while (g_hash_table_iter_next(&iter, (gpointer *) &device, (gpointer *) &handle)) { g_signal_handlers_disconnect_by_func(device, device_sleep_cb, self); @@ -6400,6 +6457,8 @@ sleep_devices_clear(NMManager *self) g_object_unref(device); g_hash_table_iter_remove(&iter); } + + sleep_devices_check_empty(self); } static void @@ -6551,6 +6610,10 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed) FALSE, NM_DEVICE_STATE_REASON_NOW_MANAGED); } + + /* Give the connections a chance to recreate the virtual devices. + * We've torn them down on sleep. */ + connections_changed(self); } nm_manager_update_state(self); @@ -6628,7 +6691,10 @@ impl_manager_sleep(NMDBusObject *obj, TRUE, subject, NULL); - g_dbus_method_invocation_return_value(invocation, NULL); + + priv->sleep_invocations = g_slist_prepend(priv->sleep_invocations, invocation); + sleep_devices_check_empty(self); + return; } @@ -6668,10 +6734,11 @@ _internal_enable(NMManager *self, gboolean enable) static void enable_net_done_cb(NMAuthChain *chain, GDBusMethodInvocation *context, gpointer user_data) { - NMManager *self = NM_MANAGER(user_data); - NMAuthCallResult result; - gboolean enable; - NMAuthSubject *subject; + NMManager *self = NM_MANAGER(user_data); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self); + NMAuthCallResult result; + gboolean enable; + NMAuthSubject *subject; nm_assert(G_IS_DBUS_METHOD_INVOCATION(context)); @@ -6696,8 +6763,10 @@ enable_net_done_cb(NMAuthChain *chain, GDBusMethodInvocation *context, gpointer } _internal_enable(self, enable); - g_dbus_method_invocation_return_value(context, NULL); nm_audit_log_control_op(NM_AUDIT_OP_NET_CONTROL, enable ? "on" : "off", TRUE, subject, NULL); + + priv->sleep_invocations = g_slist_prepend(priv->sleep_invocations, context); + sleep_devices_check_empty(self); } static void @@ -7014,10 +7083,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 +7124,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 +7131,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); @@ -7119,9 +7174,8 @@ devices_inited_cb(gpointer user_data) gboolean nm_manager_start(NMManager *self, GError **error) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self); - NMSettingsConnection *const *connections; - guint i; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self); + guint i; nm_device_factory_manager_load_factories(_register_device_factory, self); @@ -7175,9 +7229,10 @@ nm_manager_start(NMManager *self, GError **error) NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, G_CALLBACK(connection_updated_cb), self); - connections = nm_settings_get_connections_sorted_by_autoconnect_priority(priv->settings, NULL); - for (i = 0; connections[i]; i++) - connection_changed(self, connections[i]); + + /* Make sure virtual devices for all connections are created so + * that they could be autoconnected. */ + connections_changed(self); nm_clear_g_source(&priv->devices_inited_id); priv->devices_inited_id = g_idle_add_full(G_PRIORITY_LOW + 10, devices_inited_cb, self, NULL); @@ -7790,6 +7845,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 +8327,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); @@ -8300,8 +8380,10 @@ dispose(GObject *object) g_clear_object(&priv->vpn_manager); - sleep_devices_clear(self); - nm_clear_pointer(&priv->sleep_devices, g_hash_table_unref); + if (priv->sleep_devices) { + sleep_devices_clear(self); + nm_clear_pointer(&priv->sleep_devices, g_hash_table_unref); + } if (priv->sleep_monitor) { g_signal_handlers_disconnect_by_func(priv->sleep_monitor, sleeping_cb, self); diff --git a/src/core/nm-manager.h b/src/core/nm-manager.h index f8563c3a..fcb00227 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/nm-netns.c b/src/core/nm-netns.c index f120e43d..5ee63152 100644 --- a/src/core/nm-netns.c +++ b/src/core/nm-netns.c @@ -15,21 +15,21 @@ #include "nm-l3cfg.h" #include "libnm-platform/nm-platform.h" #include "libnm-platform/nmp-netns.h" -#include "libnm-platform/nmp-route-manager.h" +#include "libnm-platform/nmp-global-tracker.h" /*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_PLATFORM, ); typedef struct { - NMNetns *_self_signal_user_data; - NMPlatform *platform; - NMPNetns *platform_netns; - NMPRouteManager *route_manager; - GHashTable *l3cfgs; - GHashTable *shared_ips; - CList l3cfg_signal_pending_lst_head; - GSource *signal_pending_idle_source; + NMNetns *_self_signal_user_data; + NMPlatform *platform; + NMPNetns *platform_netns; + NMPGlobalTracker *global_tracker; + GHashTable *l3cfgs; + GHashTable *shared_ips; + CList l3cfg_signal_pending_lst_head; + GSource *signal_pending_idle_source; } NMNetnsPrivate; struct _NMNetns { @@ -79,10 +79,10 @@ nm_netns_get_platform(NMNetns *self) return NM_NETNS_GET_PRIVATE(self)->platform; } -NMPRouteManager * -nm_netns_get_route_manager(NMNetns *self) +NMPGlobalTracker * +nm_netns_get_global_tracker(NMNetns *self) { - return NM_NETNS_GET_PRIVATE(self)->route_manager; + return NM_NETNS_GET_PRIVATE(self)->global_tracker; } NMDedupMultiIndex * @@ -397,14 +397,14 @@ constructed(GObject *object) priv->platform_netns = nm_platform_netns_get(priv->platform); - priv->route_manager = nmp_route_manager_new(priv->platform); + priv->global_tracker = nmp_global_tracker_new(priv->platform); /* Weakly track the default rules with a dummy user-tag. These * rules are always weekly tracked... */ - nmp_route_manager_track_rule_default(priv->route_manager, - AF_UNSPEC, - 0, - nm_netns_parent_class /* static dummy user-tag */); + nmp_global_tracker_track_rule_default(priv->global_tracker, + AF_UNSPEC, + 0, + nm_netns_parent_class /* static dummy user-tag */); /* Also weakly track all existing rules. These were added before NetworkManager * starts, so they are probably none of NetworkManager's business. @@ -414,12 +414,12 @@ constructed(GObject *object) * of NetworkManager, we just don't know. * * For that reason, whenever we will touch such rules later one, we make them - * fully owned and no longer weekly tracked. See %NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG. */ - nmp_route_manager_track_rule_from_platform(priv->route_manager, - NULL, - AF_UNSPEC, - 0, - NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); + * fully owned and no longer weekly tracked. See %NMP_GLOBAL_TRACKER_EXTERN_WEAKLY_TRACKED_USER_TAG. */ + nmp_global_tracker_track_rule_from_platform(priv->global_tracker, + NULL, + AF_UNSPEC, + 0, + NMP_GLOBAL_TRACKER_EXTERN_WEAKLY_TRACKED_USER_TAG); G_OBJECT_CLASS(nm_netns_parent_class)->constructed(object); @@ -469,7 +469,7 @@ dispose(GObject *object) g_clear_object(&priv->platform); nm_clear_pointer(&priv->l3cfgs, g_hash_table_unref); - nm_clear_pointer(&priv->route_manager, nmp_route_manager_unref); + nm_clear_pointer(&priv->global_tracker, nmp_global_tracker_unref); G_OBJECT_CLASS(nm_netns_parent_class)->dispose(object); } diff --git a/src/core/nm-netns.h b/src/core/nm-netns.h index deb1d1f0..17c1c637 100644 --- a/src/core/nm-netns.h +++ b/src/core/nm-netns.h @@ -29,7 +29,7 @@ NMNetns *nm_netns_new(struct _NMPlatform *platform); struct _NMPlatform *nm_netns_get_platform(NMNetns *self); NMPNetns *nm_netns_get_platform_netns(NMNetns *self); -struct _NMPRouteManager *nm_netns_get_route_manager(NMNetns *self); +struct _NMPGlobalTracker *nm_netns_get_global_tracker(NMNetns *self); struct _NMDedupMultiIndex *nm_netns_get_multi_idx(NMNetns *self); diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index 1a824fa4..16b0211f 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -826,7 +826,7 @@ update_system_hostname(NMPolicy *self, const char *msg) && (nm_utils_is_specific_hostname(temp_hostname) || nm_utils_is_specific_hostname(priv->last_hostname))) { external_hostname = TRUE; - _LOGI(LOGD_DNS, + _LOGD(LOGD_DNS, "set-hostname: current hostname was changed outside NetworkManager: '%s'", temp_hostname); priv->dhcp_hostname = FALSE; diff --git a/src/core/platform/nm-fake-platform.c b/src/core/platform/nm-fake-platform.c index 7d8986d7..a1ca5434 100644 --- a/src/core/platform/nm-fake-platform.c +++ b/src/core/platform/nm-fake-platform.c @@ -323,6 +323,15 @@ link_add(NMPlatform *platform, dev_lnk = nmp_object_new(NMP_OBJECT_TYPE_LNK_BRIDGE, props); break; } + case NM_LINK_TYPE_BOND: + { + const NMPlatformLnkBond *props = extra_data; + + nm_assert(props); + + dev_lnk = nmp_object_new(NMP_OBJECT_TYPE_LNK_BOND, props); + break; + } case NM_LINK_TYPE_VETH: veth_peer = extra_data; g_assert(veth_peer); diff --git a/src/core/platform/tests/monitor.c b/src/core/platform/tests/monitor.c index ff6fae65..8d0e0107 100644 --- a/src/core/platform/tests/monitor.c +++ b/src/core/platform/tests/monitor.c @@ -9,6 +9,7 @@ #include #include "libnm-platform/nm-linux-platform.h" +#include "libnm-platform/nmp-object.h" #include "nm-test-utils-core.h" @@ -25,14 +26,14 @@ read_argv(int *argc, char ***argv) { GOptionContext *context; GOptionEntry options[] = { - {"no-persist", - 'P', - G_OPTION_FLAG_REVERSE, - G_OPTION_ARG_NONE, - &global_opt.persist, - "Exit after processing netlink messages", - NULL}, - {0}, + {"no-persist", + 'P', + G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, + &global_opt.persist, + "Exit after processing netlink messages", + NULL}, + {0}, }; gs_free_error GError *error = NULL; @@ -50,6 +51,18 @@ read_argv(int *argc, char ***argv) return TRUE; } +/*****************************************************************************/ + +static void +mptcp_addr_dump(NMPlatform *platform) +{ + gs_unref_ptrarray GPtrArray *addrs = NULL; + + addrs = nm_platform_mptcp_addrs_dump(platform); +} + +/*****************************************************************************/ + int main(int argc, char **argv) { @@ -69,6 +82,8 @@ main(int argc, char **argv) nm_linux_platform_setup(); + mptcp_addr_dump(NM_PLATFORM_GET); + if (global_opt.persist) g_main_loop_run(loop); diff --git a/src/core/platform/tests/test-common.c b/src/core/platform/tests/test-common.c index d7fed220..34ec5cc2 100644 --- a/src/core/platform/tests/test-common.c +++ b/src/core/platform/tests/test-common.c @@ -70,7 +70,7 @@ _ipx_address_get_all(NMPlatform *self, int ifindex, NMPObjectType obj_type) g_assert(NM_IS_PLATFORM(self)); g_assert(ifindex > 0); g_assert(NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS)); - nmp_lookup_init_object(&lookup, obj_type, ifindex); + nmp_lookup_init_object_by_ifindex(&lookup, obj_type, ifindex); return nmp_cache_lookup_to_array(nm_platform_lookup(self, &lookup), obj_type, FALSE /*addresses are always visible. */); @@ -103,7 +103,7 @@ nmtstp_platform_ip_address_find(NMPlatform *self, int ifindex, int addr_family, nm_assert(addr); if (ifindex > 0) - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex); + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex); else nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)); @@ -187,7 +187,9 @@ _nmtstp_platform_ip_addresses_assert(const char *filename, plat_addrs = nm_platform_lookup_clone( self, - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex), + nmp_lookup_init_object_by_ifindex(&lookup, + NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), + ifindex), NULL, NULL); @@ -1936,10 +1938,10 @@ nmtstp_link_macvlan_add(NMPlatform *platform, if (external_command) { const char *dev; char *modes[] = { - [MACVLAN_MODE_BRIDGE] = "bridge", - [MACVLAN_MODE_VEPA] = "vepa", - [MACVLAN_MODE_PRIVATE] = "private", - [MACVLAN_MODE_PASSTHRU] = "passthru", + [MACVLAN_MODE_BRIDGE] = "bridge", + [MACVLAN_MODE_VEPA] = "vepa", + [MACVLAN_MODE_PRIVATE] = "private", + [MACVLAN_MODE_PASSTHRU] = "passthru", }; dev = nm_platform_link_get_name(platform, parent); diff --git a/src/core/platform/tests/test-common.h b/src/core/platform/tests/test-common.h index 77f2c50d..da30b0ed 100644 --- a/src/core/platform/tests/test-common.h +++ b/src/core/platform/tests/test-common.h @@ -518,6 +518,11 @@ void nmtstp_link_delete(NMPlatform *platform, /*****************************************************************************/ +#define nmtst_object_new_mptcp_addr(...) \ + nmp_object_new(NMP_OBJECT_TYPE_MPTCP_ADDR, &((const NMPlatformMptcpAddr){__VA_ARGS__})) + +/*****************************************************************************/ + extern int NMTSTP_ENV1_IFINDEX; extern int NMTSTP_ENV1_EX; diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c index 48b321d2..b72bcb65 100644 --- a/src/core/platform/tests/test-link.c +++ b/src/core/platform/tests/test-link.c @@ -111,13 +111,16 @@ software_add(NMLinkType link_type, const char *name) { gboolean bond0_exists = !!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "bond0"); int r; + const NMPlatformLnkBond nm_platform_lnk_bond_default = { + .mode = 3, + }; - r = nm_platform_link_bond_add(NM_PLATFORM_GET, name, NULL); + r = nm_platform_link_bond_add(NM_PLATFORM_GET, name, &nm_platform_lnk_bond_default, NULL); /* Check that bond0 is *not* automatically created. */ if (!bond0_exists) g_assert(!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "bond0")); - return r >= 0; + return NMTST_NM_ERR_SUCCESS(r); } case NM_LINK_TYPE_TEAM: return NMTST_NM_ERR_SUCCESS(nm_platform_link_team_add(NM_PLATFORM_GET, name, NULL)); @@ -853,7 +856,7 @@ static void _test_wireguard_change(NMPlatform *platform, int ifindex, int test_mode) { const KeyPair self_key = {"yOWEsaXFxX9/DOkQPzqB9RufZOpfSP4LZZCErP0N0Xo=", - "s6pVT2xPwktor9O5bVOSzcPqBu9uzQOUzPQHXLU2jmk="}; + "s6pVT2xPwktor9O5bVOSzcPqBu9uzQOUzPQHXLU2jmk="}; const KeyPair keys[100] = { {"+BDHMh11bkheGfvlQpqt8P/H7N1sPXtVi05XraZS0E8=", "QItu7PJadBVXFXGv55CMtVnbRHdrI6E2CGlu2N5oGx4=", diff --git a/src/core/platform/tests/test-nmp-object.c b/src/core/platform/tests/test-nmp-object.c index ddd5aa93..193e750f 100644 --- a/src/core/platform/tests/test-nmp-object.c +++ b/src/core/platform/tests/test-nmp-object.c @@ -551,7 +551,9 @@ test_cache_qdisc(void) g_assert(nmp_cache_lookup_obj(cache, obj1b) == obj1b); g_assert(nmp_cache_lookup_obj(cache, obj2) == obj2); - head_entry = nmp_cache_lookup(cache, nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_QDISC, 1)); + head_entry = + nmp_cache_lookup(cache, + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_QDISC, 1)); g_assert(head_entry->len == 2); nmp_cache_free(cache); diff --git a/src/core/platform/tests/test-platform-general.c b/src/core/platform/tests/test-platform-general.c index 908ad4dd..c18886c9 100644 --- a/src/core/platform/tests/test-platform-general.c +++ b/src/core/platform/tests/test-platform-general.c @@ -788,6 +788,64 @@ test_route_type_is_nodev(void) /*****************************************************************************/ +static void +test_nmp_genl_family_type_from_name(void) +{ + int n_run; + int i; + + for (i = 0; i < (int) _NMP_GENL_FAMILY_TYPE_NUM; i++) { + const char *name = nmp_genl_family_infos[i].name; + + g_assert(name); + if (i > 0) + g_assert_cmpint(strcmp(nmp_genl_family_infos[i - 1].name, name), <, 0); + } + + g_assert_cmpint(nmp_genl_family_type_from_name("ethtool"), ==, NMP_GENL_FAMILY_TYPE_ETHTOOL); + g_assert_cmpint(nmp_genl_family_type_from_name("mptcp_pm"), ==, NMP_GENL_FAMILY_TYPE_MPTCP_PM); + g_assert_cmpint(nmp_genl_family_type_from_name("nl80211"), ==, NMP_GENL_FAMILY_TYPE_NL80211); + g_assert_cmpint(nmp_genl_family_type_from_name("nl802154"), ==, NMP_GENL_FAMILY_TYPE_NL802154); + g_assert_cmpint(nmp_genl_family_type_from_name("wireguard"), + ==, + NMP_GENL_FAMILY_TYPE_WIREGUARD); + + g_assert_cmpint(nmp_genl_family_type_from_name(NULL), ==, _NMP_GENL_FAMILY_TYPE_NONE); + g_assert_cmpint(nmp_genl_family_type_from_name("a"), ==, _NMP_GENL_FAMILY_TYPE_NONE); + g_assert_cmpint(nmp_genl_family_type_from_name("wireguara"), ==, _NMP_GENL_FAMILY_TYPE_NONE); + g_assert_cmpint(nmp_genl_family_type_from_name("wireguarb"), ==, _NMP_GENL_FAMILY_TYPE_NONE); + g_assert_cmpint(nmp_genl_family_type_from_name(""), ==, _NMP_GENL_FAMILY_TYPE_NONE); + g_assert_cmpint(nmp_genl_family_type_from_name("z"), ==, _NMP_GENL_FAMILY_TYPE_NONE); + + for (n_run = 0; n_run < 20; n_run++) { + for (i = 0; i < (int) _NMP_GENL_FAMILY_TYPE_NUM; i++) { + const char *cname = nmp_genl_family_infos[i].name; + const int ch_idx = nmtst_get_rand_uint() % strlen(cname); + char name[200]; + char ch; + gsize l; + + l = g_strlcpy(name, cname, sizeof(name)); + g_assert_cmpint(l, <, sizeof(name)); + + if (n_run == 0) { + g_assert_cmpint(nmp_genl_family_type_from_name(cname), ==, i); + g_assert_cmpint(nmp_genl_family_type_from_name(name), ==, i); + } + + /* randomly change one character in the name. Such a name becomes invalid. + * There are no two valid names which only differ by one characters. */ + do { + ch = nmtst_get_rand_uint() % 256; + } while (cname[ch_idx] == ch); + name[ch_idx] = ch; + g_assert_cmpint(nmp_genl_family_type_from_name(name), ==, _NMP_GENL_FAMILY_TYPE_NONE); + } + } +} + +/*****************************************************************************/ + NMTST_DEFINE(); int @@ -808,6 +866,8 @@ main(int argc, char **argv) GINT_TO_POINTER(2), test_platform_ip_address_pretty_sort_cmp); g_test_add_func("/general/test_route_type_is_nodev", test_route_type_is_nodev); + g_test_add_func("/nm-platform/test_nmp_genl_family_type_from_name", + test_nmp_genl_family_type_from_name); return g_test_run(); } diff --git a/src/core/platform/tests/test-route.c b/src/core/platform/tests/test-route.c index 85838267..148ed792 100644 --- a/src/core/platform/tests/test-route.c +++ b/src/core/platform/tests/test-route.c @@ -10,7 +10,7 @@ #include "nm-core-utils.h" #include "libnm-platform/nm-platform-utils.h" -#include "libnm-platform/nmp-route-manager.h" +#include "libnm-platform/nmp-global-tracker.h" #include "test-common.h" @@ -35,8 +35,9 @@ _wait_for_ipv4_addr_device_route(NMPlatform *platform, nmp_cache_iter_for_each ( &iter, - nm_platform_lookup(platform, - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex)), + nm_platform_lookup( + platform, + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex)), &o) { const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE(o); @@ -646,6 +647,9 @@ test_ip4_route_options(gconstpointer test_data) .initrwnd = 50, .mtu = 1350, .lock_cwnd = TRUE, + .mss = 1300, + .quickack = TRUE, + .rto_min = 1000, }); break; case 2: @@ -1167,7 +1171,7 @@ _rule_check_kernel_support(NMPlatform *platform, int attribute) .addr_family = AF_INET, .priority = PROBE_PRORITY, .uid_range = - { + { .start = 0, .end = 0, }, @@ -1643,8 +1647,8 @@ again: if (TEST_SYNC) { gs_unref_hashtable GHashTable *unique_priorities = g_hash_table_new(NULL, NULL); - nm_auto_unref_route_manager NMPRouteManager *route_manager = - nmp_route_manager_new(platform); + nm_auto_unref_global_tracker NMPGlobalTracker *global_tracker = + nmp_global_tracker_new(platform); gs_unref_ptrarray GPtrArray *objs_sync = NULL; gconstpointer USER_TAG_1 = &platform; gconstpointer USER_TAG_2 = &unique_priorities; @@ -1666,29 +1670,29 @@ again: } for (i = 0; i < objs_sync->len; i++) { - nmp_route_manager_track_rule(route_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - 1, - USER_TAG_1, - NULL); + nmp_global_tracker_track_rule(global_tracker, + NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), + 1, + USER_TAG_1, + NULL); if (nmtst_get_rand_bool()) { /* this has no effect, because a negative priority (of same absolute value) * has lower priority than the positive priority above. */ - nmp_route_manager_track_rule(route_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - -1, - USER_TAG_2, - NULL); + nmp_global_tracker_track_rule(global_tracker, + NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), + -1, + USER_TAG_2, + NULL); } if (nmtst_get_rand_uint32() % objs_sync->len == 0) { - nmp_route_manager_sync(route_manager, NMP_OBJECT_TYPE_ROUTING_RULE, FALSE); + nmp_global_tracker_sync(global_tracker, NMP_OBJECT_TYPE_ROUTING_RULE, FALSE); g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC), ==, i + 1); } } - nmp_route_manager_sync(route_manager, NMP_OBJECT_TYPE_ROUTING_RULE, FALSE); + nmp_global_tracker_sync(global_tracker, NMP_OBJECT_TYPE_ROUTING_RULE, FALSE); g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC), ==, objs_sync->len); @@ -1696,37 +1700,37 @@ again: for (i = 0; i < objs_sync->len; i++) { switch (nmtst_get_rand_uint32() % 3) { case 0: - nmp_route_manager_untrack_rule(route_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - USER_TAG_1); - nmp_route_manager_untrack_rule(route_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - USER_TAG_1); + nmp_global_tracker_untrack_rule(global_tracker, + NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), + USER_TAG_1); + nmp_global_tracker_untrack_rule(global_tracker, + NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), + USER_TAG_1); break; case 1: - nmp_route_manager_track_rule(route_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - -1, - USER_TAG_1, - NULL); + nmp_global_tracker_track_rule(global_tracker, + NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), + -1, + USER_TAG_1, + NULL); break; case 2: - nmp_route_manager_track_rule(route_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - -2, - USER_TAG_2, - NULL); + nmp_global_tracker_track_rule(global_tracker, + NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), + -2, + USER_TAG_2, + NULL); break; } if (nmtst_get_rand_uint32() % objs_sync->len == 0) { - nmp_route_manager_sync(route_manager, NMP_OBJECT_TYPE_ROUTING_RULE, FALSE); + nmp_global_tracker_sync(global_tracker, NMP_OBJECT_TYPE_ROUTING_RULE, FALSE); g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC), ==, objs_sync->len - i - 1); } } - nmp_route_manager_sync(route_manager, NMP_OBJECT_TYPE_ROUTING_RULE, FALSE); + nmp_global_tracker_sync(global_tracker, NMP_OBJECT_TYPE_ROUTING_RULE, FALSE); } else { for (i = 0; i < objs->len;) { @@ -1957,6 +1961,200 @@ test_blackhole(gconstpointer test_data) /*****************************************************************************/ +static gboolean +_mptcp_has_permissions(void) +{ + static int has_permissions = -1; + int p; + + /* We create a new netns for testing, where we also have CAP_NET_ADMIN. + * However, that is not enough for configuring MPTCP endpoints. Probably + * you can only create them, by running the test as root. Detect the + * inability, to skip the test. + * + * See https://lore.kernel.org/mptcp/20220805115020.525181-1-thaller@redhat.com/T/#u */ + +again: + p = g_atomic_int_get(&has_permissions); + + if (p == -1) { + static gsize lock; + const NMPlatformMptcpAddr mptcp_addr = (NMPlatformMptcpAddr){ + .id = 1, + .addr_family = AF_INET, + .addr.addr4 = nmtst_inet4_from_string("1.2.3.4"), + }; + int r; + + if (!g_once_init_enter(&lock)) + goto again; + + if (nmtst_get_rand_one_case_in(3)) { + gs_unref_ptrarray GPtrArray *arr = NULL; + + arr = nm_platform_mptcp_addrs_dump(NM_PLATFORM_GET); + g_assert_cmpint(nm_g_ptr_array_len(arr), ==, 0); + } + + r = nm_platform_mptcp_addr_update(NM_PLATFORM_GET, TRUE, &mptcp_addr); + if (r == 0) + p = TRUE; + else if (r == -EPERM) + p = FALSE; + else + g_assert_cmpint(r, ==, 0); + + if (p) { + if (nmtst_get_rand_one_case_in(3)) { + gs_unref_ptrarray GPtrArray *arr = NULL; + + arr = nm_platform_mptcp_addrs_dump(NM_PLATFORM_GET); + g_assert_cmpint(nm_g_ptr_array_len(arr), ==, 1); + } + + r = nm_platform_mptcp_addr_update(NM_PLATFORM_GET, FALSE, &mptcp_addr); + g_assert_cmpint(r, ==, 0); + } + + if (nmtst_get_rand_one_case_in(3)) { + gs_unref_ptrarray GPtrArray *arr = NULL; + + arr = nm_platform_mptcp_addrs_dump(NM_PLATFORM_GET); + g_assert_cmpint(nm_g_ptr_array_len(arr), ==, 0); + } + + g_atomic_int_set(&has_permissions, p); + g_once_init_leave(&lock, 1); + } + + return p; +} + +static gboolean +_mptcp_skip_test(void) +{ + if (nm_platform_genl_get_family_id(NM_PLATFORM_GET, NMP_GENL_FAMILY_TYPE_MPTCP_PM) == 0) { + g_test_skip("mptcp not available"); + return TRUE; + } + + if (!_mptcp_has_permissions()) { + g_test_skip("No permissions to create MPTCP endpoints"); + return TRUE; + } + + return FALSE; +} + +static void +test_mptcp(gconstpointer test_data) +{ + const int TEST_IDX = GPOINTER_TO_INT(test_data); + gs_unref_object NMPlatform *platform = g_object_ref(NM_PLATFORM_GET); + nm_auto_unref_global_tracker NMPGlobalTracker *global_tracker = + nmp_global_tracker_new(platform); + gconstpointer const USER_TAG = &TEST_IDX; + const int IFINDEX = nm_platform_link_get_ifindex(platform, DEVICE_NAME); + guint i; + guint j; + int r; + gs_unref_ptrarray GPtrArray *arr_external = + g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); + gs_unref_ptrarray GPtrArray *arr_tracked = + g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); + const NMPObject *obj; + gboolean delete_extra; + + g_assert_cmpint(IFINDEX, >, 0); + + if (_mptcp_skip_test()) + return; + + j = nmtst_get_rand_uint32() % 5; + for (i = 0; i < j; i++) { + obj = nmtst_object_new_mptcp_addr(.id = i + 1, + .ifindex = IFINDEX, + .addr_family = AF_INET, + .addr.addr4 = htonl(0xC0A80001u + i)); + g_ptr_array_add(arr_external, (gpointer) obj); + r = nm_platform_mptcp_addr_update(platform, TRUE, NMP_OBJECT_CAST_MPTCP_ADDR(obj)); + g_assert_cmpint(r, ==, 0); + } + + j = nmtst_get_rand_uint32() % 10; + for (i = 0; i < j; i++) { + obj = nmtst_object_new_mptcp_addr(.ifindex = IFINDEX, + .addr_family = AF_INET, + .addr.addr4 = htonl(0xC0A80001u + i)); + g_ptr_array_add(arr_tracked, (gpointer) obj); + nmp_global_tracker_track(global_tracker, + NMP_OBJECT_TYPE_MPTCP_ADDR, + NMP_OBJECT_CAST_MPTCP_ADDR(obj), + 20 - i, + USER_TAG, + NULL); + } + for (i = 0; i < arr_tracked->len;) { + if (nmtst_get_rand_bool()) { + nmp_global_tracker_untrack(global_tracker, + NMP_OBJECT_TYPE_MPTCP_ADDR, + NMP_OBJECT_CAST_MPTCP_ADDR(arr_tracked->pdata[i]), + USER_TAG); + g_ptr_array_remove_index(arr_tracked, i); + } else + i++; + } + + if (arr_tracked->len == 0 || nmtst_get_rand_bool()) { + NMPlatformMptcpAddr a; + + /* Track a dummy object that marks the ifindex as managed. */ + nmp_global_tracker_track(global_tracker, + NMP_OBJECT_TYPE_MPTCP_ADDR, + nmp_global_tracker_mptcp_addr_init_for_ifindex(&a, IFINDEX), + 10, + USER_TAG, + NULL); + } + + nmp_global_tracker_sync_mptcp_addrs(global_tracker, FALSE); + + if (nmtst_get_rand_bool()) { + gboolean reapply; + + nmp_global_tracker_untrack_all(global_tracker, USER_TAG, TRUE, FALSE); + reapply = nmtst_get_rand_bool(); + nmp_global_tracker_sync_mptcp_addrs(global_tracker, reapply); + + delete_extra = !reapply; + } else + delete_extra = TRUE; + + if (delete_extra) { + gs_unref_ptrarray GPtrArray *arr = NULL; + + /* We need to delete all MPTCP address again, because the next test uses the + * same netns (this test setup doesn't create a netns per test). */ + arr = nm_platform_mptcp_addrs_dump(platform); + for (i = 0; i < nm_g_ptr_array_len(arr); i++) { + r = nm_platform_mptcp_addr_update(platform, + FALSE, + NMP_OBJECT_CAST_MPTCP_ADDR(arr->pdata[i])); + g_assert(NMTST_NM_ERR_SUCCESS(r)); + } + } + + { + gs_unref_ptrarray GPtrArray *arr = NULL; + + arr = nm_platform_mptcp_addrs_dump(platform); + g_assert(arr); + g_assert_cmpint(arr->len, ==, 0); + } +} + +/*****************************************************************************/ + NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP; void @@ -1971,6 +2169,7 @@ _nmtstp_setup_tests(void) #define add_test_func(testpath, test_func) nmtstp_env1_add_test_func(testpath, test_func, TRUE) #define add_test_func_data(testpath, test_func, arg) \ nmtstp_env1_add_test_func_data(testpath, test_func, arg, TRUE) + add_test_func("/route/ip4", test_ip4_route); add_test_func("/route/ip6", test_ip6_route); add_test_func("/route/ip4_metric0", test_ip4_route_metric0); @@ -1998,4 +2197,8 @@ _nmtstp_setup_tests(void) add_test_func_data("/route/blackhole/1", test_blackhole, GINT_TO_POINTER(1)); add_test_func_data("/route/blackhole/2", test_blackhole, GINT_TO_POINTER(2)); } + if (nmtstp_is_root_test()) { + add_test_func_data("/route/mptcp/1", test_mptcp, GINT_TO_POINTER(1)); + add_test_func_data("/route/mptcp/2", test_mptcp, GINT_TO_POINTER(2)); + } } diff --git a/src/core/platform/tests/test-tc.c b/src/core/platform/tests/test-tc.c index db23a932..6a2019c8 100644 --- a/src/core/platform/tests/test-tc.c +++ b/src/core/platform/tests/test-tc.c @@ -30,10 +30,11 @@ qdiscs_lookup(int ifindex) { NMPLookup lookup; - return nm_platform_lookup_clone(NM_PLATFORM_GET, - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_QDISC, ifindex), - NULL, - NULL); + return nm_platform_lookup_clone( + NM_PLATFORM_GET, + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_QDISC, ifindex), + NULL, + NULL); } static void diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c index 1ff66e25..b7d846c6 100644 --- a/src/core/settings/nm-settings.c +++ b/src/core/settings/nm-settings.c @@ -376,6 +376,8 @@ typedef struct { GHashTable *sce_idx; + GCancellable *shutdown_cancellable; + CList sce_dirty_lst_head; CList connections_lst_head; @@ -389,15 +391,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 +543,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 +569,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 +611,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 +641,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); } @@ -3464,44 +3468,93 @@ load_plugins(NMSettings *self, const char *const *plugins, GError **error) /*****************************************************************************/ static void -pk_hostname_cb(NMAuthChain *chain, GDBusMethodInvocation *context, gpointer user_data) +_save_hostname_write_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + NMSettings *self; + GDBusMethodInvocation *context; + gs_free char *hostname = NULL; + gs_unref_object NMAuthSubject *auth_subject = NULL; + gs_unref_object GCancellable *cancellable = NULL; + gs_free_error GError *error = NULL; + + nm_utils_user_data_unpack(user_data, &self, &context, &auth_subject, &hostname, &cancellable); + + nm_hostname_manager_write_hostname_finish(NM_HOSTNAME_MANAGER(source), result, &error); + + nm_audit_log_control_op(NM_AUDIT_OP_HOSTNAME_SAVE, + hostname ?: "", + !error, + auth_subject, + error ? error->message : NULL); + + if (nm_utils_error_is_cancelled(error)) { + g_dbus_method_invocation_return_error_literal(context, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FAILED, + "NetworkManager is shutting down"); + return; + } + + if (error) { + g_dbus_method_invocation_take_error(context, + g_error_new(NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FAILED, + "Saving the hostname failed: %s", + error->message)); + return; + } + + g_dbus_method_invocation_return_value(context, NULL); +} + +static void +_save_hostname_pk_cb(NMAuthChain *chain, GDBusMethodInvocation *context, gpointer user_data) { NMSettings *self = NM_SETTINGS(user_data); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self); NMAuthCallResult result; - GError *error = NULL; - const char *hostname; + gs_free char *hostname = NULL; nm_assert(G_IS_DBUS_METHOD_INVOCATION(context)); c_list_unlink(nm_auth_chain_parent_lst_list(chain)); result = nm_auth_chain_get_result(chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME); - hostname = nm_auth_chain_get_data(chain, "hostname"); + hostname = nm_auth_chain_steal_data(chain, "hostname"); - /* If our NMSettingsConnection is already gone, do nothing */ if (result != NM_AUTH_CALL_RESULT_YES) { - error = g_error_new_literal(NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_PERMISSION_DENIED, - NM_UTILS_ERROR_MSG_INSUFF_PRIV); - } else { - if (!nm_hostname_manager_write_hostname(priv->hostname_manager, hostname)) { - error = g_error_new_literal(NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_FAILED, - "Saving the hostname failed."); - } + nm_audit_log_control_op(NM_AUDIT_OP_HOSTNAME_SAVE, + hostname ?: "", + FALSE, + nm_auth_chain_get_subject(chain), + NM_UTILS_ERROR_MSG_INSUFF_PRIV); + g_dbus_method_invocation_return_error_literal(context, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_PERMISSION_DENIED, + NM_UTILS_ERROR_MSG_INSUFF_PRIV); + return; } - nm_audit_log_control_op(NM_AUDIT_OP_HOSTNAME_SAVE, - hostname, - !error, - nm_auth_chain_get_subject(chain), - error ? error->message : NULL); + if (!priv->shutdown_cancellable) { + /* we only keep a weak pointer on the cancellable, so we can + * wrap it up after use. We almost never require this, because + * SaveHostname is almost never called. */ + priv->shutdown_cancellable = g_cancellable_new(); + g_object_add_weak_pointer(G_OBJECT(priv->shutdown_cancellable), + (gpointer *) &priv->shutdown_cancellable); + } - if (error) - g_dbus_method_invocation_take_error(context, error); - else - g_dbus_method_invocation_return_value(context, NULL); + nm_hostname_manager_write_hostname( + priv->hostname_manager, + hostname, + priv->shutdown_cancellable, + _save_hostname_write_cb, + nm_utils_user_data_pack(self, + context, + g_object_ref(nm_auth_chain_get_subject(chain)), + hostname, + g_object_ref(priv->shutdown_cancellable))); + g_steal_pointer(&hostname); } static void @@ -3523,13 +3576,13 @@ impl_settings_save_hostname(NMDBusObject *obj, g_variant_get(parameters, "(&s)", &hostname); /* Minimal validation of the hostname */ - if (!nm_utils_validate_hostname(hostname)) { + if (nm_str_not_empty(hostname) && !nm_utils_validate_hostname(hostname)) { error_code = NM_SETTINGS_ERROR_INVALID_HOSTNAME; error_reason = "The hostname was too long or contained invalid characters"; goto err; } - chain = nm_auth_chain_new_context(invocation, pk_hostname_cb, self); + chain = nm_auth_chain_new_context(invocation, _save_hostname_pk_cb, self); if (!chain) { error_code = NM_SETTINGS_ERROR_PERMISSION_DENIED; error_reason = NM_UTILS_ERROR_MSG_REQ_AUTH_FAILED; @@ -3538,7 +3591,7 @@ impl_settings_save_hostname(NMDBusObject *obj, c_list_link_tail(&priv->auth_lst_head, nm_auth_chain_parent_lst_list(chain)); nm_auth_chain_add_call(chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, TRUE); - nm_auth_chain_set_data(chain, "hostname", g_strdup(hostname), g_free); + nm_auth_chain_set_data(chain, "hostname", nm_strdup_not_empty(hostname), g_free); return; err: nm_audit_log_control_op(NM_AUDIT_OP_HOSTNAME_SAVE, hostname, FALSE, invocation, error_reason); @@ -3842,13 +3895,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 +3912,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 +3933,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 +4154,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)); @@ -4121,6 +4175,12 @@ dispose(GObject *object) g_clear_object(&priv->session_monitor); } + if (priv->shutdown_cancellable) { + g_object_remove_weak_pointer(G_OBJECT(priv->shutdown_cancellable), + (gpointer *) &priv->shutdown_cancellable); + g_cancellable_cancel(g_steal_pointer(&priv->shutdown_cancellable)); + } + G_OBJECT_CLASS(nm_settings_parent_class)->dispose(object); } @@ -4154,8 +4214,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/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index e62c0227..6452d72a 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -393,7 +393,9 @@ make_connection_setting(const char *file, const char *v; gs_free char *stable_id = NULL; const char *const *iter; - int vint64, i_val; + gint32 vint32; + gint64 vint64; + int i_val; ifcfg_name = utils_get_ifcfg_name(file, TRUE); if (!ifcfg_name) @@ -586,8 +588,8 @@ make_connection_setting(const char *file, break; } - vint64 = svGetValueInt64(ifcfg, "AUTH_RETRIES", 10, -1, G_MAXINT32, -1); - g_object_set(s_con, NM_SETTING_CONNECTION_AUTH_RETRIES, (int) vint64, NULL); + vint32 = svGetValueInt64(ifcfg, "AUTH_RETRIES", 10, -1, G_MAXINT32, -1); + g_object_set(s_con, NM_SETTING_CONNECTION_AUTH_RETRIES, (int) vint32, NULL); nm_clear_g_free(&value); v = svGetValue(ifcfg, "DEVTIMEOUT", &value); @@ -643,6 +645,14 @@ make_connection_setting(const char *file, PARSE_WARNING("invalid DNS_OVER_TLS setting"); g_object_set(s_con, NM_SETTING_CONNECTION_DNS_OVER_TLS, i_val, NULL); + i_val = NM_MPTCP_FLAGS_NONE; + if (!svGetValueEnum(ifcfg, "MPTCP_FLAGS", nm_mptcp_flags_get_type(), &i_val, NULL)) + PARSE_WARNING("invalid MPTCP_FLAGS setting"); + g_object_set(s_con, NM_SETTING_CONNECTION_MPTCP_FLAGS, (guint) i_val, NULL); + + vint32 = svGetValueInt64(ifcfg, "WAIT_ACTIVATION_DELAY", 10, -1, G_MAXINT32, -1); + g_object_set(s_con, NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY, (int) vint32, NULL); + return NM_SETTING(s_con); } @@ -772,7 +782,7 @@ read_full_ip4_address(shvarFile *ifcfg, if (!read_ip4_address(ifcfg, numbered_tag(tag, "NETMASK", which), &has_key, &a, error)) return FALSE; if (has_key) - prefix = nm_utils_ip4_netmask_to_prefix(a); + prefix = _nm_utils_ip4_netmask_to_prefix(a); else { if (base_addr) prefix = nm_ip_address_get_prefix(base_addr); @@ -845,6 +855,7 @@ typedef struct { union { guint8 uint8; guint32 uint32; + gboolean boolean; const char *str; struct { guint32 uint32; @@ -873,6 +884,9 @@ enum { PARSE_LINE_ATTR_ROUTE_INITCWND, PARSE_LINE_ATTR_ROUTE_INITRWND, PARSE_LINE_ATTR_ROUTE_MTU, + PARSE_LINE_ATTR_ROUTE_ADVMSS, + PARSE_LINE_ATTR_ROUTE_RTO_MIN, + PARSE_LINE_ATTR_ROUTE_QUICKACK, /* iproute2 arguments that only matter when parsing the file. */ PARSE_LINE_ATTR_ROUTE_TO, @@ -886,6 +900,7 @@ enum { #define PARSE_LINE_TYPE_UINT8 '8' #define PARSE_LINE_TYPE_UINT32 'u' #define PARSE_LINE_TYPE_UINT32_WITH_LOCK 'l' +#define PARSE_LINE_TYPE_BOOL 'b' #define PARSE_LINE_TYPE_ADDR 'a' #define PARSE_LINE_TYPE_ADDR_WITH_PREFIX 'p' #define PARSE_LINE_TYPE_IFNAME 'i' @@ -972,6 +987,11 @@ parse_route_line(const char *line, .key = NM_IP_ROUTE_ATTRIBUTE_CWND, .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_ADVMSS] = + { + .key = NM_IP_ROUTE_ATTRIBUTE_ADVMSS, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, + }, [PARSE_LINE_ATTR_ROUTE_INITCWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITCWND, @@ -987,7 +1007,16 @@ parse_route_line(const char *line, .key = NM_IP_ROUTE_ATTRIBUTE_MTU, .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - + [PARSE_LINE_ATTR_ROUTE_QUICKACK] = + { + .key = NM_IP_ROUTE_ATTRIBUTE_QUICKACK, + .type = PARSE_LINE_TYPE_BOOL, + }, + [PARSE_LINE_ATTR_ROUTE_RTO_MIN] = + { + .key = NM_IP_ROUTE_ATTRIBUTE_RTO_MIN, + .type = PARSE_LINE_TYPE_UINT32, + }, [PARSE_LINE_ATTR_ROUTE_TO] = { .key = "to", @@ -1090,6 +1119,9 @@ parse_route_line(const char *line, case PARSE_LINE_TYPE_UINT32_WITH_LOCK: i_words++; goto parse_line_type_uint32_with_lock; + case PARSE_LINE_TYPE_BOOL: + i_words++; + goto parse_line_type_bool; case PARSE_LINE_TYPE_ADDR: i_words++; goto parse_line_type_addr; @@ -1218,6 +1250,22 @@ parse_line_type_uint32_with_lock: i_words++; goto next; +parse_line_type_bool: + s = words[i_words]; + if (!s) + goto err_word_missing_argument; + p_data->v.boolean = !!_nm_utils_ascii_str_to_int64(s, 10, 0, 1, 0); + if (errno) { + g_set_error(error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Argument for \"%s\" is not a valid boolean number", + w); + return -EINVAL; + } + i_words++; + goto next; + parse_line_type_ifname: s = words[i_words]; if (!s) @@ -1370,6 +1418,9 @@ next:; p_info->key, g_variant_new_uint32(p_data->v.uint32_with_lock.uint32)); break; + case PARSE_LINE_TYPE_BOOL: + nm_ip_route_set_attribute(route, p_info->key, g_variant_new_boolean(p_data->v.boolean)); + break; case PARSE_LINE_TYPE_ADDR: case PARSE_LINE_TYPE_ADDR_WITH_PREFIX: nm_ip_route_set_attribute( @@ -1445,7 +1496,7 @@ read_one_ip4_route(shvarFile *ifcfg, guint32 which, NMIPRoute **out_route, GErro error)) return FALSE; if (has_key) { - prefix = nm_utils_ip4_netmask_to_prefix(netmask); + prefix = _nm_utils_ip4_netmask_to_prefix(netmask); if (netmask != _nm_utils_ip4_prefix_to_netmask(prefix)) { g_set_error(error, NM_SETTINGS_ERROR, @@ -1786,6 +1837,7 @@ make_ip4_setting(shvarFile *ifcfg, int priority; const char *const *item; guint32 route_table; + int ipv4_link_local; nm_assert(out_has_defroute && !*out_has_defroute); @@ -1858,6 +1910,14 @@ make_ip4_setting(shvarFile *ifcfg, route_table = 0; } + ipv4_link_local = NM_SETTING_IP4_LL_DEFAULT; + if (!svGetValueEnum(ifcfg, + "IPV4_LINK_LOCAL", + nm_setting_ip4_link_local_get_type(), + &ipv4_link_local, + NULL)) + PARSE_WARNING("invalid IPV4_LINK_LOCAL setting"); + g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, method, @@ -1873,6 +1933,8 @@ make_ip4_setting(shvarFile *ifcfg, svGetValueInt64(ifcfg, "IPV4_ROUTE_METRIC", 10, -1, G_MAXUINT32, -1), NM_SETTING_IP_CONFIG_ROUTE_TABLE, (guint) route_table, + NM_SETTING_IP4_CONFIG_LINK_LOCAL, + ipv4_link_local, NULL); if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) @@ -2498,7 +2560,13 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea } } - i_val = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64; + /* IPv6 tokenized interface identifier */ + nm_clear_g_free(&value); + v = svGetValueStr(ifcfg, "IPV6_TOKEN", &value); + if (v) + g_object_set(s_ip6, NM_SETTING_IP6_CONFIG_TOKEN, v, NULL); + + i_val = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64; if (!svGetValueEnum(ifcfg, "IPV6_ADDR_GEN_MODE", nm_setting_ip6_config_addr_gen_mode_get_type(), @@ -2506,15 +2574,14 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea &local)) { PARSE_WARNING("%s", local->message); g_clear_error(&local); + } else if (errno == ENOENT) { + /* The key is not specified. If "v" (IPV6_TOKEN) is set, + * we default to EUI64. Otherwise, the connection would not verify. */ + if (v) + i_val = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64; } g_object_set(s_ip6, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, i_val, NULL); - /* IPv6 tokenized interface identifier */ - nm_clear_g_free(&value); - v = svGetValueStr(ifcfg, "IPV6_TOKEN", &value); - if (v) - g_object_set(s_ip6, NM_SETTING_IP6_CONFIG_TOKEN, v, NULL); - /* DNS servers * Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting()) */ diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index 15e01ba9..e1ef8174 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -960,6 +960,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { _KEY_TYPE("IPV4_DHCP_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV4_DNS_PRIORITY", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV4_FAILURE_FATAL", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("IPV4_LINK_LOCAL", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV4_REQUIRED_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV4_ROUTE_METRIC", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("IPV4_ROUTE_TABLE", NMS_IFCFG_KEY_TYPE_IS_PLAIN), @@ -1005,6 +1006,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { _KEY_TYPE("MDNS", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("METRIC", NMS_IFCFG_KEY_TYPE_IS_NUMBERED), _KEY_TYPE("MODE", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("MPTCP_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("MTU", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("MUD_URL", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("MULTI_CONNECT", NMS_IFCFG_KEY_TYPE_IS_PLAIN), @@ -1061,6 +1063,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { _KEY_TYPE("VLAN_INGRESS_PRIORITY_MAP", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("VRF", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("VRF_UUID", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("WAIT_ACTIVATION_DELAY", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("WEP_KEY_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("WPA_ALLOW_WPA", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("WPA_ALLOW_WPA2", NMS_IFCFG_KEY_TYPE_IS_PLAIN), diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index d7a1cfc6..d1f8dbad 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -33,7 +33,7 @@ typedef struct { NMSIfcfgKeyTypeFlags key_flags; } NMSIfcfgKeyTypeInfo; -extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[253]; +extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[256]; const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info(const char *key, gssize *out_idx); diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 551f2b91..96efc9e5 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -2095,6 +2095,7 @@ write_connection_setting(NMSettingConnection *s_con, shvarFile *ifcfg) NMSettingConnectionMdns mdns; NMSettingConnectionLlmnr llmnr; NMSettingConnectionDnsOverTls dns_over_tls; + NMMptcpFlags mptcp_flags; guint32 vuint32; const char *tmp, *mud_url; @@ -2258,6 +2259,9 @@ write_connection_setting(NMSettingConnection *s_con, shvarFile *ifcfg) vint = nm_setting_connection_get_auth_retries(s_con); svSetValueInt64_cond(ifcfg, "AUTH_RETRIES", vint >= 0, vint); + vint32 = nm_setting_connection_get_wait_activation_delay(s_con); + svSetValueInt64_cond(ifcfg, "WAIT_ACTIVATION_DELAY", vint32 >= 0, vint32); + vint32 = nm_setting_connection_get_wait_device_timeout(s_con); if (vint32 == -1) { /* pass */ @@ -2286,13 +2290,18 @@ write_connection_setting(NMSettingConnection *s_con, shvarFile *ifcfg) nm_setting_connection_dns_over_tls_get_type(), dns_over_tls); } + + mptcp_flags = nm_setting_connection_get_mptcp_flags(s_con); + if (mptcp_flags != NM_MPTCP_FLAGS_NONE) + svSetValueEnum(ifcfg, "MPTCP_FLAGS", nm_mptcp_flags_get_type(), mptcp_flags); } static char * get_route_attributes_string(NMIPRoute *route, int family) { gs_free const char **names = NULL; - GVariant *attr, *lock; + GVariant *attr; + GVariant *lock; GString *str; guint i, len; @@ -2317,6 +2326,7 @@ get_route_attributes_string(NMIPRoute *route, int family) continue; if (NM_IN_STRSET(names[i], + NM_IP_ROUTE_ATTRIBUTE_ADVMSS, NM_IP_ROUTE_ATTRIBUTE_WINDOW, NM_IP_ROUTE_ATTRIBUTE_CWND, NM_IP_ROUTE_ATTRIBUTE_INITCWND, @@ -2332,12 +2342,12 @@ get_route_attributes_string(NMIPRoute *route, int family) names[i], (lock && g_variant_get_boolean(lock)) ? "lock " : "", g_variant_get_uint32(attr)); - } else if (strstr(names[i], "lock-")) { + } else if (NM_STR_HAS_PREFIX(names[i], "lock-")) { const char *n = &(names[i])[NM_STRLEN("lock-")]; - attr = nm_ip_route_get_attribute(route, n); - if (!attr) { - g_string_append_printf(str, "%s lock 0", n); + if (!nm_ip_route_get_attribute(route, n)) { + if (g_variant_get_boolean(attr)) + g_string_append_printf(str, "%s lock 0", n); } else { /* we also have a corresponding attribute with the numeric value. The * lock setting is handled above. */ @@ -2346,8 +2356,12 @@ get_route_attributes_string(NMIPRoute *route, int family) g_string_append_printf(str, "%s %u", names[i], (unsigned) g_variant_get_byte(attr)); } else if (nm_streq(names[i], NM_IP_ROUTE_ATTRIBUTE_TOS)) { g_string_append_printf(str, "%s 0x%02x", names[i], (unsigned) g_variant_get_byte(attr)); - } else if (nm_streq(names[i], NM_IP_ROUTE_ATTRIBUTE_TABLE)) { + } else if (NM_IN_STRSET(names[i], + NM_IP_ROUTE_ATTRIBUTE_TABLE, + NM_IP_ROUTE_ATTRIBUTE_RTO_MIN)) { g_string_append_printf(str, "%s %u", names[i], (unsigned) g_variant_get_uint32(attr)); + } else if (nm_streq(names[i], NM_IP_ROUTE_ATTRIBUTE_QUICKACK)) { + g_string_append_printf(str, "%s %u", names[i], (unsigned) g_variant_get_boolean(attr)); } else if (nm_streq(names[i], NM_IP_ROUTE_ATTRIBUTE_ONLINK)) { if (g_variant_get_boolean(attr)) g_string_append(str, "onlink"); @@ -2733,6 +2747,7 @@ write_ip4_setting(NMConnection *connection, gboolean has_netmask; NMDhcpHostnameFlags flags; const char *const *strv; + NMSettingIP4LinkLocal ipv4_link_local; NM_SET_OUT(out_route_content_svformat, NULL); NM_SET_OUT(out_route_content, NULL); @@ -2839,6 +2854,14 @@ write_ip4_setting(NMConnection *connection, value = nm_setting_ip_config_get_dhcp_hostname(s_ip4); svSetValueStr(ifcfg, "DHCP_HOSTNAME", value); + ipv4_link_local = nm_setting_ip4_config_get_link_local(NM_SETTING_IP4_CONFIG(s_ip4)); + if (ipv4_link_local != NM_SETTING_IP4_LL_DEFAULT) { + svSetValueEnum(ifcfg, + "IPV4_LINK_LOCAL", + nm_setting_ip4_link_local_get_type(), + ipv4_link_local); + } + value = nm_setting_ip4_config_get_dhcp_fqdn(NM_SETTING_IP4_CONFIG(s_ip4)); svSetValueStr(ifcfg, "DHCP_FQDN", value); @@ -3149,7 +3172,7 @@ write_ip6_setting(NMConnection *connection, shvarFile *ifcfg, GString **out_rout /* IPv6 Address generation mode */ addr_gen_mode = nm_setting_ip6_config_get_addr_gen_mode(NM_SETTING_IP6_CONFIG(s_ip6)); - if (addr_gen_mode != NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64) { + if (addr_gen_mode != NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64) { svSetValueEnum(ifcfg, "IPV6_ADDR_GEN_MODE", nm_setting_ip6_config_addr_gen_mode_get_type(), diff --git a/src/core/settings/plugins/ifcfg-rh/shvar.c b/src/core/settings/plugins/ifcfg-rh/shvar.c index 2ca49558..fe8187c3 100644 --- a/src/core/settings/plugins/ifcfg-rh/shvar.c +++ b/src/core/settings/plugins/ifcfg-rh/shvar.c @@ -1328,6 +1328,7 @@ svGetValueEnum(shvarFile *s, const char *key, GType gtype, int *out_value, GErro if (!svalue) { /* don't touch out_value. The caller is supposed * to initialize it with the default value. */ + errno = ENOENT; return TRUE; } @@ -1339,10 +1340,12 @@ svGetValueEnum(shvarFile *s, const char *key, GType gtype, int *out_value, GErro err_token, svalue, key); + errno = EINVAL; return FALSE; } NM_SET_OUT(out_value, value); + errno = 0; return TRUE; } diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected index 71d2cda8..1330382d 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected @@ -13,4 +13,4 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_User_1.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_User_1.cexpected index a48be78a..15ced3ab 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_User_1.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_User_1.cexpected @@ -28,7 +28,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test User 1" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected index ccc0f35a..1aeb2cdc 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected @@ -13,7 +13,7 @@ IPV4_FAILURE_FATAL=no IPV6INIT=no IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Bond Main" UUID=${UUID} DEVICE=bond0 diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Permissions.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Permissions.cexpected index d4a978b6..a7df77e4 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Permissions.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Permissions.cexpected @@ -7,7 +7,7 @@ IPV4_FAILURE_FATAL=no IPV6INIT=no IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Permissions" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Proxy_Basic.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Proxy_Basic.cexpected index 716eedc2..7fcd2c15 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Proxy_Basic.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Proxy_Basic.cexpected @@ -9,7 +9,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Proxy Basic" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Routing_Rules.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Routing_Rules.cexpected index 0c2fa035..d03e9a0d 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Routing_Rules.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Routing_Rules.cexpected @@ -3,12 +3,13 @@ PROXY_METHOD=none BROWSER_ONLY=no BOOTPROTO=dhcp DEFROUTE=yes +IPV4_LINK_LOCAL=enabled IPV4_FAILURE_FATAL=no IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default ROUTING_RULE_1="priority 10 from 0.0.0.0/0 table 1" ROUTING_RULE_2="priority 10 to 192.167.8.0/24 table 2" ROUTING_RULE6_3="priority 10 from ::/0 table 10" diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_VLAN_reorder_hdr.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_VLAN_reorder_hdr.cexpected index 9c2a1ff0..6a233664 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_VLAN_reorder_hdr.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_VLAN_reorder_hdr.cexpected @@ -15,7 +15,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write VLAN reorder_hdr" UUID=${UUID} ONBOOT=no diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_AP_Mode.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_AP_Mode.cexpected index ccec2b81..caeaaff8 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_AP_Mode.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_AP_Mode.cexpected @@ -13,7 +13,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Wi-Fi AP Mode" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Band_A.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Band_A.cexpected index ddbd986f..7e3d4f02 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Band_A.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Band_A.cexpected @@ -12,7 +12,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Wi-Fi Band A" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected index 495a24d3..01a091ec 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_Hidden.cexpected @@ -11,7 +11,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Wi-Fi Hidden" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_always.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_always.cexpected index aec6918a..7fa0fc98 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_always.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_always.cexpected @@ -12,7 +12,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Wi-Fi MAC always" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_default.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_default.cexpected index 9d47163f..1b4ca948 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_default.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_default.cexpected @@ -11,7 +11,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Wi-Fi MAC default" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_missing.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_missing.cexpected index 43c07ddb..089d1442 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_missing.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_missing.cexpected @@ -12,7 +12,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Wi-Fi MAC missing" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_never.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_never.cexpected index 21f2e2de..880db3f7 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_never.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_WiFi_MAC_never.cexpected @@ -12,7 +12,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Wi-Fi MAC never" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_LEAP.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_LEAP.cexpected index f1b01a21..b9129c59 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_LEAP.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_LEAP.cexpected @@ -13,7 +13,7 @@ IPV4_FAILURE_FATAL=no IPV6INIT=no IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Wifi LEAP" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_WEP_104_ASCII.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_WEP_104_ASCII.cexpected index 60540fbe..2dd8958b 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_WEP_104_ASCII.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wifi_WEP_104_ASCII.cexpected @@ -12,7 +12,7 @@ IPV4_FAILURE_FATAL=no IPV6INIT=no IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Wifi WEP 104 ASCII" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected index 214f5da5..8dd2cbff 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected @@ -9,7 +9,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Wired Auto-Negotiate" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected index fe864c43..bc2806a9 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected @@ -19,6 +19,7 @@ ARPING_WAIT=1 IPV6INIT=no IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=eui64 NAME="Test Write Wired Static Routes" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected index de66dcdd..34f89b5e 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected @@ -9,7 +9,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Wired Wake-on-LAN" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_match.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_match.cexpected index 908cb917..318fae5d 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_match.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_match.cexpected @@ -10,6 +10,7 @@ IPV4_FAILURE_FATAL=no IPV6INIT=no IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=eui64 NAME="Test Write Wired with Match setting" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-dcb-test.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-dcb-test.cexpected index fef36f2f..0a9ef3d4 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-dcb-test.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-dcb-test.cexpected @@ -33,7 +33,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME=dcb-test UUID=${UUID} DEVICE=eth0 diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-random_wifi_connection.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-random_wifi_connection.cexpected index 1f5e04ff..0a5c2ccf 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-random_wifi_connection.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-random_wifi_connection.cexpected @@ -10,6 +10,7 @@ IPV4_FAILURE_FATAL=no IPV6INIT=no IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=eui64 NAME="random wifi connection" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-random_wifi_connection_2.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-random_wifi_connection_2.cexpected index 3dcdbda0..8a874d24 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-random_wifi_connection_2.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-random_wifi_connection_2.cexpected @@ -10,6 +10,7 @@ IPV4_FAILURE_FATAL=no IPV6INIT=no IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=eui64 NAME="random wifi connection 2" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ip6-disabled.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ip6-disabled.cexpected index b3199c01..9cba7e20 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ip6-disabled.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-ip6-disabled.cexpected @@ -8,6 +8,7 @@ IPV6_DISABLED=yes IPV6INIT=no IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=eui64 NAME="Test Write Wired Disabled IP6" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-link_local b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-link_local new file mode 100644 index 00000000..cfc963fb --- /dev/null +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-link_local @@ -0,0 +1,3 @@ +TYPE=Ethernet +BOOTPROTO=dhcp +IPV4_LINK_LOCAL=enabled diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-sriov-write.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-sriov-write.cexpected index a77c615d..121ead79 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-sriov-write.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-sriov-write.cexpected @@ -14,7 +14,7 @@ IPV4_FAILURE_FATAL=no IPV6INIT=no IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write SR-IOV config" UUID=${UUID} DEVICE=eth0 diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write-empty.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write-empty.cexpected index 1125ef55..8f513922 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write-empty.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write-empty.cexpected @@ -11,7 +11,7 @@ IPV4_FAILURE_FATAL=no IPV6INIT=no IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write TC config" UUID=${UUID} DEVICE=eth0 diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write.cexpected index d87efd72..698bda3a 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write.cexpected @@ -12,7 +12,7 @@ IPV4_FAILURE_FATAL=no IPV6INIT=no IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write TC config" UUID=${UUID} DEVICE=eth0 diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-1.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-1.cexpected index 5186f90c..11fd060e 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-1.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-1.cexpected @@ -8,7 +8,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME=test_roundtrip_ethtool UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-2.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-2.cexpected index 5632ebec..abd74bbd 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-2.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-2.cexpected @@ -9,7 +9,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME=test_roundtrip_ethtool UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-3.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-3.cexpected index 96eec43b..962cbdd5 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-3.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-3.cexpected @@ -9,7 +9,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME=test_roundtrip_ethtool UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-4.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-4.cexpected index 90250a30..213045df 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-4.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-4.cexpected @@ -9,7 +9,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME=test_roundtrip_ethtool UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-5.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-5.cexpected index 721eacb2..d3b9c056 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-5.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-5.cexpected @@ -9,7 +9,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME=test_roundtrip_ethtool UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_write_wired_auto_negotiate_on.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_write_wired_auto_negotiate_on.cexpected index 42608576..542f5b5b 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_write_wired_auto_negotiate_on.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_write_wired_auto_negotiate_on.cexpected @@ -9,7 +9,7 @@ IPV6INIT=yes IPV6_AUTOCONF=yes IPV6_DEFROUTE=yes IPV6_FAILURE_FATAL=no -IPV6_ADDR_GEN_MODE=stable-privacy +IPV6_ADDR_GEN_MODE=default NAME="Test Write Wired Auto-Negotiate" UUID=${UUID} ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes index 9c05417e..717ad1ac 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/route-test-wired-static-routes @@ -6,7 +6,7 @@ ADDRESS1=44.55.66.77 NETMASK1=255.255.255.255 GATEWAY1=192.168.1.7 METRIC1=3 -OPTIONS1="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 window 30000 scope 10 initcwnd lock 13 initrwnd 14" +OPTIONS1="mtu lock 9000 cwnd 12 src 1.1.1.1 tos 0x28 window 30000 scope 10 initcwnd lock 13 initrwnd 14 rto_min 300 advmss 1300 quickack 1" ADDRESS2=44.55.66.78 NETMASK2=255.255.255.255 diff --git a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 83e48b81..9fdae4bd 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -668,8 +668,8 @@ test_read_miscellaneous_variables(void) NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; char *expected_mac_blacklist[3] = {"00:16:41:11:22:88", - "00:16:41:11:22:99", - "6a:5d:5a:fa:dd:f0"}; + "00:16:41:11:22:99", + "6a:5d:5a:fa:dd:f0"}; int mac_blacklist_num, i; guint64 expected_timestamp = 0; @@ -1352,6 +1352,7 @@ test_read_wired_static_routes(void) g_assert_cmpint(nm_ip_route_get_prefix(ip4_route), ==, 32); g_assert_cmpstr(nm_ip_route_get_next_hop(ip4_route), ==, "192.168.1.7"); g_assert_cmpint(nm_ip_route_get_metric(ip4_route), ==, 3); + nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_ADVMSS, 1300); nmtst_assert_route_attribute_byte(ip4_route, NM_IP_ROUTE_ATTRIBUTE_TOS, 0x28); nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_WINDOW, 30000); nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_CWND, 12); @@ -1360,6 +1361,8 @@ test_read_wired_static_routes(void) nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_MTU, 9000); nmtst_assert_route_attribute_boolean(ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, TRUE); nmtst_assert_route_attribute_boolean(ip4_route, NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, TRUE); + nmtst_assert_route_attribute_uint32(ip4_route, NM_IP_ROUTE_ATTRIBUTE_RTO_MIN, 300); + nmtst_assert_route_attribute_boolean(ip4_route, NM_IP_ROUTE_ATTRIBUTE_QUICKACK, TRUE); nmtst_assert_route_attribute_string(ip4_route, NM_IP_ROUTE_ATTRIBUTE_SRC, "1.1.1.1"); nmtst_assert_route_attribute_byte(ip4_route, NM_IP_ROUTE_ATTRIBUTE_SCOPE, 10); @@ -2027,17 +2030,17 @@ test_read_wired_aliases_good(gconstpointer test_data) NMSettingIPConfig *s_ip4; int expected_num_addresses; const char *expected_address_0[] = {"192.168.1.5", - "192.168.1.6", - "192.168.1.9", - "192.168.1.99", - NULL}; + "192.168.1.6", + "192.168.1.9", + "192.168.1.99", + NULL}; const char *expected_address_3[] = {"192.168.1.5", "192.168.1.6", NULL}; const char *expected_label_0[] = { - NULL, - "aliasem0:1", - "aliasem0:2", - "aliasem0:99", - NULL, + NULL, + "aliasem0:1", + "aliasem0:2", + "aliasem0:99", + NULL, }; const char *expected_label_3[] = { NULL, @@ -4538,7 +4541,12 @@ test_write_routing_rules(void) _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRED); s_ip4 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP4_CONFIG); - g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL); + g_object_set(s_ip4, + NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NM_SETTING_IP4_CONFIG_LINK_LOCAL, + NM_SETTING_IP4_LL_ENABLED, + NULL); s_ip6 = _nm_connection_new_setting(connection, NM_TYPE_SETTING_IP6_CONFIG); g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); @@ -4633,6 +4641,34 @@ test_write_wired_dhcp_plus_ip(void) nmtst_assert_connection_equals(connection, TRUE, reread, FALSE); } +static void +test_read_write_link_local(void) +{ + nmtst_auto_unlinkfile char *testfile = NULL; + gs_unref_object NMConnection *connection = NULL; + gs_unref_object NMConnection *reread = NULL; + NMSettingIPConfig *s_ip4; + + connection = + _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-link_local", NULL, TYPE_ETHERNET, NULL); + + s_ip4 = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_IP4_CONFIG); + g_assert(nm_setting_ip4_config_get_link_local(NM_SETTING_IP4_CONFIG(s_ip4)) + == NM_SETTING_IP4_LL_ENABLED); + + g_object_set(s_ip4, NM_SETTING_IP4_CONFIG_LINK_LOCAL, NM_SETTING_IP4_LL_DISABLED, NULL); + + _writer_new_connection(connection, TEST_SCRATCH_DIR, &testfile); + + reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL); + + nmtst_assert_connection_equals(connection, TRUE, reread, FALSE); + + s_ip4 = nmtst_connection_assert_setting(reread, NM_TYPE_SETTING_IP4_CONFIG); + g_assert(nm_setting_ip4_config_get_link_local(NM_SETTING_IP4_CONFIG(s_ip4)) + == NM_SETTING_IP4_LL_DISABLED); +} + static void test_read_write_wired_dhcp_send_hostname(void) { @@ -8153,8 +8189,8 @@ test_read_infiniband(void) char *unmanaged = NULL; const char *mac; char expected_mac_address[INFINIBAND_ALEN] = {0x80, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, - 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, - 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22}; + 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, + 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22}; const char *transport_mode; connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-infiniband", @@ -10245,6 +10281,7 @@ main(int argc, char **argv) g_test_add_func(TPATH "read-dhcp", test_read_wired_dhcp); g_test_add_func(TPATH "read-dhcp-plus-ip", test_read_wired_dhcp_plus_ip); g_test_add_func(TPATH "read-shared-plus-ip", test_read_wired_shared_plus_ip); + g_test_add_func(TPATH "read-write-link-local", test_read_write_link_local); g_test_add_func(TPATH "read-dhcp-send-hostname", test_read_write_wired_dhcp_send_hostname); g_test_add_func(TPATH "read-dhcpv6-hostname-fallback", test_read_wired_dhcpv6_hostname_fallback); diff --git a/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c b/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c index c079266e..a1d6781b 100644 --- a/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c +++ b/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c @@ -451,7 +451,7 @@ update_ip4_setting_from_if_block(NMConnection *connection, if_block *block, GErr netmask_v); return FALSE; } else { - netmask_int = nm_utils_ip4_netmask_to_prefix(tmp_mask); + netmask_int = _nm_utils_ip4_netmask_to_prefix(tmp_mask); } } diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c index efb9bfce..1d7de8d2 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 11a8e416..1307d4b2 100644 --- a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c +++ b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c @@ -1805,8 +1805,8 @@ test_read_infiniband_connection(void) NMSettingInfiniband *s_ib; const char *mac; guint8 expected_mac[INFINIBAND_ALEN] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, - 0x77, 0x88, 0x99, 0x01, 0x12, 0x23, 0x34, - 0x45, 0x56, 0x67, 0x78, 0x89, 0x90}; + 0x77, 0x88, 0x99, 0x01, 0x12, 0x23, 0x34, + 0x45, 0x56, 0x67, 0x78, 0x89, 0x90}; const char *expected_id = "Test InfiniBand Connection"; const char *expected_uuid = "4e80a56d-c99f-4aad-a6dd-b449bc398c57"; @@ -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/supplicant/nm-supplicant-interface.c b/src/core/supplicant/nm-supplicant-interface.c index e7ac0e58..fa8b4e37 100644 --- a/src/core/supplicant/nm-supplicant-interface.c +++ b/src/core/supplicant/nm-supplicant-interface.c @@ -3174,7 +3174,7 @@ _signal_handle(NMSupplicantInterface *self, _set_p2p_assigned_addr(iface, addr_data, - nm_utils_ip4_netmask_to_prefix(netmask)); + _nm_utils_ip4_netmask_to_prefix(netmask)); } else { _LOGW("P2P: GroupStarted signaled invalid IP Address information"); } diff --git a/src/core/tests/config/test-config.c b/src/core/tests/config/test-config.c index fa7fae07..17a66b06 100644 --- a/src/core/tests/config/test-config.c +++ b/src/core/tests/config/test-config.c @@ -1103,9 +1103,9 @@ test_config_set_values(void) const char *CONFIG_USER = BUILD_DIR "/test-set-values-user.conf"; const char *CONFIG_INTERN = BUILD_DIR "/test-set-values-intern.conf"; const char *atomic_section_prefixes[] = { - "atomic-prefix-1.", - "atomic-prefix-2.", - NULL, + "atomic-prefix-1.", + "atomic-prefix-2.", + NULL, }; g_assert(g_file_set_contents(CONFIG_USER, "", 0, NULL)); diff --git a/src/core/tests/test-core-with-expect.c b/src/core/tests/test-core-with-expect.c index eca098c4..de510c76 100644 --- a/src/core/tests/test-core-with-expect.c +++ b/src/core/tests/test-core-with-expect.c @@ -227,11 +227,11 @@ do_test_nm_utils_kill_child(void) { GLogLevelFlags fatal_mask; char *argv_watchdog[] = { - "bash", - "-c", - "sleep 4; " - "kill -KILL 0; #watchdog for #" TEST_TOKEN, - NULL, + "bash", + "-c", + "sleep 4; " + "kill -KILL 0; #watchdog for #" TEST_TOKEN, + NULL, }; char *argv1[] = { "bash", diff --git a/src/core/tests/test-core.c b/src/core/tests/test-core.c index 11a7f323..c260788e 100644 --- a/src/core/tests/test-core.c +++ b/src/core/tests/test-core.c @@ -2353,21 +2353,21 @@ test_nm_utils_dhcp_client_id_systemd_node_specific(gconstpointer test_data) { const int TEST_IDX = GPOINTER_TO_INT(test_data); const guint8 HASH_KEY[16] = {0x80, - 0x11, - 0x8c, - 0xc2, - 0xfe, - 0x4a, - 0x03, - 0xee, - 0x3e, - 0xd6, - 0x0c, - 0x6f, - 0x36, - 0x39, - 0x14, - 0x09}; + 0x11, + 0x8c, + 0xc2, + 0xfe, + 0x4a, + 0x03, + 0xee, + 0x3e, + 0xd6, + 0x0c, + 0x6f, + 0x36, + 0x39, + 0x14, + 0x09}; const guint16 duid_type_en = htons(2); const guint32 systemd_pen = htonl(43793); const struct { diff --git a/src/core/tests/test-l3cfg.c b/src/core/tests/test-l3cfg.c index 924d98f1..a9ac4004 100644 --- a/src/core/tests/test-l3cfg.c +++ b/src/core/tests/test-l3cfg.c @@ -821,7 +821,7 @@ _test_l3_ipv6ll_find_lladdr(TestL3IPv6LLData *tdata, int ifindex) g_assert(tdata); - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex); + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex); nm_platform_iter_obj_for_each (&iter, tdata->f->platform, &lookup, &obj) { const NMPlatformIP6Address *a = NMP_OBJECT_CAST_IP6_ADDRESS(obj); diff --git a/src/core/tests/test-systemd.c b/src/core/tests/test-systemd.c index 71a6a60d..cf31ec33 100644 --- a/src/core/tests/test-systemd.c +++ b/src/core/tests/test-systemd.c @@ -12,27 +12,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) { @@ -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 ad9950dd..2bcb6f69 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/libnm.ver b/src/libnm-client-impl/libnm.ver index b6d566fc..e414b7e6 100644 --- a/src/libnm-client-impl/libnm.ver +++ b/src/libnm-client-impl/libnm.ver @@ -1,3 +1,11 @@ +# This is the symbol version script of libnm for the linker. +# +# Note that once a stable release is done, all version nodes so +# far must not change anymore. E.g. after 1.36.0 release, libnm_1_36_0 +# node (and all other version nodes) are frozen. +# +# Only add/remove symbols in the section for the current development +# version, at the bottom of the file. libnm_1_0_0 { global: nm_802_11_ap_flags_get_type; @@ -1826,4 +1834,13 @@ libnm_1_38_0 { global: nm_client_get_radio_flags; nm_radio_flags_get_type; -} libnm_1_36_0; \ No newline at end of file +} libnm_1_36_0; + +libnm_1_40_0 { +global: + nm_conn_wireguard_import; + nm_mptcp_flags_get_type; + nm_setting_connection_get_wait_activation_delay; + nm_setting_ip4_link_local_get_type; + nm_setting_ip6_config_get_mtu; +} libnm_1_38_0; diff --git a/src/libnm-client-impl/meson.build b/src/libnm-client-impl/meson.build index 2026f98d..46464a63 100644 --- a/src/libnm-client-impl/meson.build +++ b/src/libnm-client-impl/meson.build @@ -5,6 +5,7 @@ libnm_client_impl_sources = files( 'nm-active-connection.c', 'nm-checkpoint.c', 'nm-client.c', + 'nm-conn-utils.c', 'nm-dbus-helpers.c', 'nm-device-6lowpan.c', 'nm-device-adsl.c', diff --git a/src/libnm-client-impl/nm-client.c b/src/libnm-client-impl/nm-client.c index 8476679b..a2ca8333 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-conn-utils.c b/src/libnm-client-impl/nm-conn-utils.c new file mode 100644 index 00000000..5d04cd32 --- /dev/null +++ b/src/libnm-client-impl/nm-conn-utils.c @@ -0,0 +1,593 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2013 - 2015 Red Hat, Inc. + */ + +#include "libnm-client-impl/nm-default-libnm.h" + +#include "libnm-client-public/nm-conn-utils.h" + +#include + +#include "libnmc-base/nm-client-utils.h" +#include "libnm-glib-aux/nm-io-utils.h" +#include "libnm-glib-aux/nm-secret-utils.h" +#include "nm-simple-connection.h" + +static gboolean +_wg_complete_peer(GPtrArray **p_peers, + NMWireGuardPeer *peer_take, + gsize peer_start_line_nr, + const char *filename, + GError **error) +{ + nm_auto_unref_wgpeer NMWireGuardPeer *peer = peer_take; + gs_free_error GError *local = NULL; + + if (!peer) + return TRUE; + + if (!nm_wireguard_peer_is_valid(peer, TRUE, TRUE, &local)) { + nm_utils_error_set(error, + NM_UTILS_ERROR_UNKNOWN, + _("Invalid peer starting at %s:%zu: %s"), + filename, + peer_start_line_nr, + local->message); + return FALSE; + } + + if (!*p_peers) + *p_peers = g_ptr_array_new_with_free_func((GDestroyNotify) nm_wireguard_peer_unref); + g_ptr_array_add(*p_peers, g_steal_pointer(&peer)); + return TRUE; +} + +static gboolean +_line_match(char *line, const char *key, gsize key_len, const char **out_key, char **out_value) +{ + nm_assert(line); + nm_assert(key); + nm_assert(strlen(key) == key_len); + nm_assert(!strchr(key, '=')); + nm_assert(out_key && !*out_key); + nm_assert(out_value && !*out_value); + + /* Note that `wg-quick` (linux.bash) does case-insensitive comparison (shopt -s nocasematch). + * `wg setconf` does case-insensitive comparison too (with strncasecmp, which is locale dependent). + * + * We do a case-insensitive comparison of the key, however in a locale-independent manner. */ + + if (g_ascii_strncasecmp(line, key, key_len) != 0) + return FALSE; + + if (line[key_len] != '=') + return FALSE; + + *out_key = key; + *out_value = &line[key_len + 1]; + return TRUE; +} + +#define line_match(line, key, out_key, out_value) \ + _line_match((line), "" key "", NM_STRLEN(key), (out_key), (out_value)) + +static gboolean +value_split_word(char **line_remainder, char **out_word) +{ + char *str; + + if ((*line_remainder)[0] == '\0') + return FALSE; + + *out_word = *line_remainder; + + str = strchrnul(*line_remainder, ','); + if (str[0] == ',') { + str[0] = '\0'; + *line_remainder = &str[1]; + } else + *line_remainder = str; + return TRUE; +} + +/** + * nm_conn_wireguard_import: + * @filename: name of the file to attempt to read into a new #NMConnection + * @error: on return, an error or %NULL + * + * Returns: (transfer full): a new #NMConnection imported from @path, or %NULL + * on error or if the file with @filename was not recognized as a WireGuard config + * + * Since: 1.40 + */ +NMConnection * +nm_conn_wireguard_import(const char *filename, GError **error) +{ + nm_auto_clear_secret_ptr NMSecretPtr file_content = NM_SECRET_PTR_INIT(); + char ifname[IFNAMSIZ]; + gs_free char *uuid = NULL; + gboolean ifname_valid = FALSE; + const char *cstr; + char *line_remainder; + gs_unref_object NMConnection *connection = NULL; + NMSettingConnection *s_con; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + NMSettingWireGuard *s_wg; + gs_free_error GError *local = NULL; + enum { + LINE_CONTEXT_INIT, + LINE_CONTEXT_INTERFACE, + LINE_CONTEXT_PEER, + } line_context; + gsize line_nr; + gsize current_peer_start_line_nr = 0; + nm_auto_unref_wgpeer NMWireGuardPeer *current_peer = NULL; + gs_unref_ptrarray GPtrArray *data_dns_search = NULL; + gs_unref_ptrarray GPtrArray *data_dns_v4 = NULL; + gs_unref_ptrarray GPtrArray *data_dns_v6 = NULL; + gs_unref_ptrarray GPtrArray *data_addr_v4 = NULL; + gs_unref_ptrarray GPtrArray *data_addr_v6 = NULL; + gs_unref_ptrarray GPtrArray *data_peers = NULL; + const char *data_private_key = NULL; + gint64 data_table; + guint data_listen_port = 0; + guint data_fwmark = 0; + guint data_mtu = 0; + int is_v4; + guint i; + + g_return_val_if_fail(filename, NULL); + g_return_val_if_fail(!error || !*error, NULL); + + /* contrary to "wg-quick", we never interpret the filename as "/etc/wireguard/$INTERFACE.conf". + * If the filename has no '/', it is interpreted as relative to the current working directory. + * However, we do require a suitable filename suffix and that the name corresponds to the interface + * name. */ + cstr = strrchr(filename, '/'); + cstr = cstr ? &cstr[1] : filename; + if (NM_STR_HAS_SUFFIX(cstr, ".conf")) { + gsize len = strlen(cstr) - NM_STRLEN(".conf"); + + if (len > 0 && len < sizeof(ifname)) { + memcpy(ifname, cstr, len); + ifname[len] = '\0'; + + if (nm_utils_ifname_valid(ifname, NMU_IFACE_KERNEL, NULL)) + ifname_valid = TRUE; + } + } + if (!ifname_valid) { + nm_utils_error_set_literal(error, + NM_UTILS_ERROR_UNKNOWN, + _("The name of the WireGuard config must be a valid interface " + "name followed by \".conf\"")); + return FALSE; + } + + if (!nm_utils_file_get_contents(-1, + filename, + 10 * 1024 * 1024, + NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET, + &file_content.str, + &file_content.len, + NULL, + error)) { + return NULL; + } + + /* We interpret the file like `wg-quick up` and `wg setconf` do. + * + * Of course the WireGuard scripts do something fundamentlly different. They + * perform actions to configure the WireGuard link in kernel, add routes and + * addresses, and call resolvconf. It all happens at the time when the script + * run. + * + * This code here instead generates a NetworkManager connection profile so that + * NetworkManager will apply a similar configuration when later activating the profile. */ + +#define _TABLE_AUTO ((gint64) -1) +#define _TABLE_OFF ((gint64) -2) + + data_table = _TABLE_AUTO; + + line_remainder = file_content.str; + line_context = LINE_CONTEXT_INIT; + line_nr = 0; + while (line_remainder[0] != '\0') { + const char *matched_key = NULL; + char *value = NULL; + char *line; + char ch; + gint64 i64; + + line_nr++; + + line = line_remainder; + line_remainder = strchrnul(line, '\n'); + if (line_remainder[0] != '\0') + (line_remainder++)[0] = '\0'; + + /* Drop all spaces and truncate at first '#'. + * See wg's config_read_line(). + * + * Note that wg-quick doesn't do that. + * + * Neither `wg setconf` nor `wg-quick` does a strict parsing. + * We don't either. Just try to interpret the file (mostly) the same as + * they would. + */ + { + gsize l, n; + + n = 0; + for (l = 0; (ch = line[l]); l++) { + if (g_ascii_isspace(ch)) { + /* wg-setconf strips all whitespace before parsing the content. That means, + * *[I nterface]" will be accepted. We do that too. */ + continue; + } + if (ch == '#') + break; + line[n++] = line[l]; + } + if (n == 0) + continue; + line[n] = '\0'; + } + + if (g_ascii_strcasecmp(line, "[Interface]") == 0) { + if (!_wg_complete_peer(&data_peers, + g_steal_pointer(¤t_peer), + current_peer_start_line_nr, + filename, + error)) + return FALSE; + line_context = LINE_CONTEXT_INTERFACE; + continue; + } + + if (g_ascii_strcasecmp(line, "[Peer]") == 0) { + if (!_wg_complete_peer(&data_peers, + g_steal_pointer(¤t_peer), + current_peer_start_line_nr, + filename, + error)) + return FALSE; + current_peer_start_line_nr = line_nr; + current_peer = nm_wireguard_peer_new(); + line_context = LINE_CONTEXT_PEER; + continue; + } + + if (line_context == LINE_CONTEXT_INTERFACE) { + if (line_match(line, "Address", &matched_key, &value)) { + char *value_word; + + while (value_split_word(&value, &value_word)) { + GPtrArray **p_data_addr; + NMIPAddr addr_bin; + int addr_family; + int prefix_len; + + if (!nm_utils_parse_inaddr_prefix_bin(AF_UNSPEC, + value_word, + &addr_family, + &addr_bin, + &prefix_len)) + goto fail_invalid_value; + + p_data_addr = (addr_family == AF_INET) ? &data_addr_v4 : &data_addr_v6; + + if (!*p_data_addr) + *p_data_addr = + g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_address_unref); + + g_ptr_array_add( + *p_data_addr, + nm_ip_address_new_binary( + addr_family, + &addr_bin, + prefix_len == -1 ? ((addr_family == AF_INET) ? 32 : 128) : prefix_len, + NULL)); + } + continue; + } + + if (line_match(line, "MTU", &matched_key, &value)) { + i64 = _nm_utils_ascii_str_to_int64(value, 0, 0, G_MAXUINT32, -1); + if (i64 == -1) + goto fail_invalid_value; + + /* wg-quick accepts the "MTU" value, but it also fetches routes to + * autodetect it. NetworkManager won't do that, we can only configure + * an explicit MTU or no autodetection will be performed. */ + data_mtu = i64; + continue; + } + + if (line_match(line, "DNS", &matched_key, &value)) { + char *value_word; + + while (value_split_word(&value, &value_word)) { + GPtrArray **p_data_dns; + NMIPAddr addr_bin; + int addr_family; + + if (nm_utils_parse_inaddr_bin(AF_UNSPEC, value_word, &addr_family, &addr_bin)) { + p_data_dns = (addr_family == AF_INET) ? &data_dns_v4 : &data_dns_v6; + if (!*p_data_dns) + *p_data_dns = g_ptr_array_new_with_free_func(g_free); + + g_ptr_array_add(*p_data_dns, + nm_utils_inet_ntop_dup(addr_family, &addr_bin)); + continue; + } + + if (!data_dns_search) + data_dns_search = g_ptr_array_new_with_free_func(g_free); + g_ptr_array_add(data_dns_search, g_strdup(value_word)); + } + continue; + } + + if (line_match(line, "Table", &matched_key, &value)) { + if (nm_streq(value, "auto")) + data_table = _TABLE_AUTO; + else if (nm_streq(value, "off")) + data_table = _TABLE_OFF; + else { + /* we don't support table names from /etc/iproute2/rt_tables + * But we accept hex like `ip route add` would. */ + i64 = _nm_utils_ascii_str_to_int64(value, 0, 0, G_MAXINT32, -1); + if (i64 == -1) + goto fail_invalid_value; + data_table = i64; + } + continue; + } + + if (line_match(line, "PreUp", &matched_key, &value) + || line_match(line, "PreDown", &matched_key, &value) + || line_match(line, "PostUp", &matched_key, &value) + || line_match(line, "PostDown", &matched_key, &value)) { + /* we don't run any scripts. Silently ignore these parameters. */ + continue; + } + + if (line_match(line, "SaveConfig", &matched_key, &value)) { + /* we ignore the setting, but enforce that it's either true or false (like + * wg-quick. */ + if (!NM_IN_STRSET(value, "true", "false")) + goto fail_invalid_value; + continue; + } + + if (line_match(line, "ListenPort", &matched_key, &value)) { + /* we don't use getaddrinfo(), unlike `wg setconf`. Just interpret + * the port as plain decimal number. */ + i64 = _nm_utils_ascii_str_to_int64(value, 10, 0, 0xFFFF, -1); + if (i64 == -1) + goto fail_invalid_value; + data_listen_port = i64; + continue; + } + + if (line_match(line, "FwMark", &matched_key, &value)) { + if (nm_streq(value, "off")) + data_fwmark = 0; + else { + i64 = _nm_utils_ascii_str_to_int64(value, 0, 0, G_MAXINT32, -1); + if (i64 == -1) + goto fail_invalid_value; + data_fwmark = i64; + } + continue; + } + + if (line_match(line, "PrivateKey", &matched_key, &value)) { + if (!nm_utils_base64secret_decode(value, NM_WIREGUARD_PUBLIC_KEY_LEN, NULL)) + goto fail_invalid_secret; + data_private_key = value; + continue; + } + + goto fail_invalid_line; + } + + if (line_context == LINE_CONTEXT_PEER) { + if (line_match(line, "Endpoint", &matched_key, &value)) { + if (!nm_wireguard_peer_set_endpoint(current_peer, value, FALSE)) + goto fail_invalid_value; + continue; + } + + if (line_match(line, "PublicKey", &matched_key, &value)) { + if (!nm_wireguard_peer_set_public_key(current_peer, value, FALSE)) + goto fail_invalid_value; + continue; + } + + if (line_match(line, "AllowedIPs", &matched_key, &value)) { + char *value_word; + + while (value_split_word(&value, &value_word)) { + if (!nm_wireguard_peer_append_allowed_ip(current_peer, value_word, FALSE)) + goto fail_invalid_value; + } + continue; + } + + if (line_match(line, "PersistentKeepalive", &matched_key, &value)) { + if (nm_streq(value, "off")) + i64 = 0; + else { + i64 = _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXUINT16, -1); + if (i64 == -1) + goto fail_invalid_value; + } + nm_wireguard_peer_set_persistent_keepalive(current_peer, i64); + continue; + } + + if (line_match(line, "PresharedKey", &matched_key, &value)) { + if (!nm_wireguard_peer_set_preshared_key(current_peer, value, FALSE)) + goto fail_invalid_secret; + nm_wireguard_peer_set_preshared_key_flags(current_peer, + NM_SETTING_SECRET_FLAG_NONE); + continue; + } + + goto fail_invalid_line; + } + +fail_invalid_line: + nm_utils_error_set(error, + NM_UTILS_ERROR_INVALID_ARGUMENT, + _("unrecognized line at %s:%zu"), + filename, + line_nr); + return FALSE; +fail_invalid_value: + nm_utils_error_set(error, + NM_UTILS_ERROR_INVALID_ARGUMENT, + _("invalid value for '%s' at %s:%zu"), + matched_key, + filename, + line_nr); + return FALSE; +fail_invalid_secret: + nm_utils_error_set(error, + NM_UTILS_ERROR_INVALID_ARGUMENT, + _("invalid secret '%s' at %s:%zu"), + matched_key, + filename, + line_nr); + return FALSE; + } + + if (!_wg_complete_peer(&data_peers, + g_steal_pointer(¤t_peer), + current_peer_start_line_nr, + filename, + error)) + return FALSE; + + connection = nm_simple_connection_new(); + s_con = NM_SETTING_CONNECTION(nm_setting_connection_new()); + nm_connection_add_setting(connection, NM_SETTING(s_con)); + s_ip4 = NM_SETTING_IP_CONFIG(nm_setting_ip4_config_new()); + nm_connection_add_setting(connection, NM_SETTING(s_ip4)); + s_ip6 = NM_SETTING_IP_CONFIG(nm_setting_ip6_config_new()); + nm_connection_add_setting(connection, NM_SETTING(s_ip6)); + s_wg = NM_SETTING_WIREGUARD(nm_setting_wireguard_new()); + nm_connection_add_setting(connection, NM_SETTING(s_wg)); + + uuid = nm_utils_uuid_generate(); + + g_object_set(s_con, + NM_SETTING_CONNECTION_ID, + ifname, + NM_SETTING_CONNECTION_UUID, + uuid, + NM_SETTING_CONNECTION_TYPE, + NM_SETTING_WIREGUARD_SETTING_NAME, + NM_SETTING_CONNECTION_INTERFACE_NAME, + ifname, + NULL); + + g_object_set(s_wg, + NM_SETTING_WIREGUARD_PRIVATE_KEY, + data_private_key, + NM_SETTING_WIREGUARD_LISTEN_PORT, + data_listen_port, + NM_SETTING_WIREGUARD_FWMARK, + data_fwmark, + NM_SETTING_WIREGUARD_MTU, + data_mtu, + NULL); + + if (data_peers) { + for (i = 0; i < data_peers->len; i++) + nm_setting_wireguard_append_peer(s_wg, data_peers->pdata[i]); + } + + for (is_v4 = 0; is_v4 < 2; is_v4++) { + const char *method_disabled = + is_v4 ? NM_SETTING_IP4_CONFIG_METHOD_DISABLED : NM_SETTING_IP6_CONFIG_METHOD_DISABLED; + const char *method_manual = + is_v4 ? NM_SETTING_IP4_CONFIG_METHOD_MANUAL : NM_SETTING_IP6_CONFIG_METHOD_MANUAL; + NMSettingIPConfig *s_ip = is_v4 ? s_ip4 : s_ip6; + GPtrArray *data_dns = is_v4 ? data_dns_v4 : data_dns_v6; + GPtrArray *data_addr = is_v4 ? data_addr_v4 : data_addr_v6; + GPtrArray *data_dns_search2 = data_dns_search; + + if (!data_addr) { + /* When specifying "DNS", we also require an "Address" for the same address + * family. That is because a NMSettingIPConfig cannot have @method_disabled + * and DNS settings at the same time. + * + * We don't have addresses. Silently ignore the DNS setting. */ + data_dns = NULL; + data_dns_search2 = NULL; + } + + g_object_set(s_ip, + NM_SETTING_IP_CONFIG_METHOD, + data_addr ? method_manual : method_disabled, + NULL); + + if (data_addr) { + for (i = 0; i < data_addr->len; i++) + nm_setting_ip_config_add_address(s_ip, data_addr->pdata[i]); + } + if (data_dns) { + for (i = 0; i < data_dns->len; i++) + nm_setting_ip_config_add_dns(s_ip, data_dns->pdata[i]); + + /* Of the wg-quick doesn't specify a search domain, assume the user + * wants to use the domain server for all searches. */ + if (!data_dns_search2) + nm_setting_ip_config_add_dns_search(s_ip, "~"); + } + if (data_dns_search2) { + for (i = 0; i < data_dns_search2->len; i++) + nm_setting_ip_config_add_dns_search(s_ip, data_dns_search2->pdata[i]); + } + + if (data_table == _TABLE_AUTO) { + /* in the "auto" setting, wg-quick adds peer-routes automatically to the main + * table. NetworkManager will do that too, but there are differences: + * + * - NetworkManager (contrary to wg-quick) does not check whether the peer-route is necessary. + * It will always add a route for each allowed-ips range, even if there is already another + * route that would ensure packets to the endpoint are routed via the WireGuard interface. + * If you don't want that, disable "wireguard.peer-routes", and add the necessary routes + * yourself to "ipv4.routes" and "ipv6.routes". + * + * - With "auto", wg-quick also configures policy routing to handle default-routes (/0) to + * avoid routing loops. + * The imported connection profile will have wireguard.ip4-auto-default-route and + * wireguard.ip6-auto-default-route set to "default". It will thus configure wg-quick's + * policy routing if the profile has any AllowedIPs ranges with /0. + */ + } else if (data_table == _TABLE_OFF) { + if (is_v4) { + g_object_set(s_wg, NM_SETTING_WIREGUARD_PEER_ROUTES, FALSE, NULL); + } + } else { + g_object_set(s_ip, NM_SETTING_IP_CONFIG_ROUTE_TABLE, (guint) data_table, NULL); + } + } + + if (!nm_connection_normalize(connection, NULL, NULL, &local)) { + nm_utils_error_set(error, + NM_UTILS_ERROR_INVALID_ARGUMENT, + _("Failed to create WireGuard connection: %s"), + local->message); + return FALSE; + } + + return g_steal_pointer(&connection); +} diff --git a/src/libnm-client-impl/nm-default-libnm.h b/src/libnm-client-impl/nm-default-libnm.h index 5b3a8e51..859766a3 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 a8363c93..be6d56e4 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 26fceb3b..38f9e472 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 d7bd9cbe..d81b5516 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 fb72f250..6e667ac6 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 b062ea9e..616aca50 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 @@ -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 b9db20bb..cdbe7fbc 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 db5f31ea..9d9cfa25 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-impl/nm-property-infos-dbus.xml b/src/libnm-client-impl/nm-property-infos-dbus.xml index 25c9c728..f875cf34 100644 --- a/src/libnm-client-impl/nm-property-infos-dbus.xml +++ b/src/libnm-client-impl/nm-property-infos-dbus.xml @@ -18,7 +18,7 @@ - + diff --git a/src/libnm-client-impl/nm-property-infos-ifcfg-rh.xml b/src/libnm-client-impl/nm-property-infos-ifcfg-rh.xml index d051725d..b0ad2d21 100644 --- a/src/libnm-client-impl/nm-property-infos-ifcfg-rh.xml +++ b/src/libnm-client-impl/nm-property-infos-ifcfg-rh.xml @@ -8,7 +8,7 @@ - + @@ -17,8 +17,8 @@ - - + + diff --git a/src/libnm-client-impl/nm-property-infos-nmcli.xml b/src/libnm-client-impl/nm-property-infos-nmcli.xml index 8e39a7a2..63d187d3 100644 --- a/src/libnm-client-impl/nm-property-infos-nmcli.xml +++ b/src/libnm-client-impl/nm-property-infos-nmcli.xml @@ -28,6 +28,9 @@ For example "192.0.2.0/24 10.1.1.1 77, 198.51.100.0/24". Various attributes are supported: +"advmss" - an unsigned 32 bit integer. + + "cwnd" - an unsigned 32 bit integer. @@ -37,6 +40,9 @@ Various attributes are supported: "initrwnd" - an unsigned 32 bit integer. +"lock-advmss" - a boolean value. + + "lock-cwnd" - a boolean value. @@ -58,6 +64,13 @@ Various attributes are supported: "onlink" - a boolean value. +"quickack" - a boolean value. + + +"rto_min" - an unsigned 32 bit integer. +The value is in milliseconds. + + "scope" - an unsigned 8 bit integer. IPv4 only. @@ -101,6 +114,9 @@ next hop addresses, optional route metric, optional attribute. The valid syntax Various attributes are supported: +"advmss" - an unsigned 32 bit integer. + + "cwnd" - an unsigned 32 bit integer. @@ -113,6 +129,9 @@ Various attributes are supported: "initrwnd" - an unsigned 32 bit integer. +"lock-advmss" - a boolean value. + + "lock-cwnd" - a boolean value. @@ -134,6 +153,13 @@ Various attributes are supported: "onlink" - a boolean value. +"quickack" - a boolean value. + + +"rto_min" - an unsigned 32 bit integer. +The value is in milliseconds. + + "src" - an IPv6 address. diff --git a/src/libnm-client-impl/nm-settings-docs-gir.xml b/src/libnm-client-impl/nm-settings-docs-gir.xml index 77a95b51..0306dcd9 100644 --- a/src/libnm-client-impl/nm-settings-docs-gir.xml +++ b/src/libnm-client-impl/nm-settings-docs-gir.xml @@ -1,537 +1,406 @@ - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + The number of retries for the authentication. Zero means to try indefinitely; -1 means to use a global default. If the global default is not set, the authentication retries for 3 times before failing the connection. + + Currently, this only applies to 802-1x authentication. The number of retries for the authentication. Zero means to try indefinitely; -1 means to use a global default. If the global default is not set, the authentication retries for 3 times before failing the connection. Currently, this only applies to 802-1x authentication. Whether or not the connection should be automatically connected by NetworkManager when the resources for the connection are available. TRUE to automatically activate the connection, FALSE to require manual intervention to activate the connection. + + Autoconnect happens when the circumstances are suitable. That means for example that the device is currently managed and not active. Autoconnect thus never replaces or competes with an already active profile. + + Note that autoconnect is not implemented for VPN profiles. See "secondaries" as an alternative to automatically connect VPN profiles. + + If multiple profiles are ready to autoconnect on the same device, the one with the better "connection.autoconnect-priority" is chosen. If the priorities are equal, then the most recently connected profile is activated. If the profiles were not connected earlier or their "connection.timestamp" is identical, the choice is undefined. + + Depending on "connection.multi-connect", a profile can (auto)connect only once at a time or multiple times. Whether or not the connection should be automatically connected by NetworkManager when the resources for the connection are available. TRUE to automatically activate the connection, FALSE to require manual intervention to activate the connection. Autoconnect happens when the circumstances are suitable. That means for example that the device is currently managed and not active. Autoconnect thus never replaces or competes with an already active profile. Note that autoconnect is not implemented for VPN profiles. See "secondaries" as an alternative to automatically connect VPN profiles. If multiple profiles are ready to autoconnect on the same device, the one with the better "connection.autoconnect-priority" is chosen. If the priorities are equal, then the most recently connected profile is activated. If the profiles were not connected earlier or their "connection.timestamp" is identical, the choice is undefined. Depending on "connection.multi-connect", a profile can (auto)connect only once at a time or multiple times. The autoconnect priority in range -999 to 999. If the connection is set to autoconnect, connections with higher priority will be preferred. The higher number means higher priority. Defaults to 0. Note that this property only matters if there are more than one candidate profile to select for autoconnect. In case of equal priority, the profile used most recently is chosen. The autoconnect priority in range -999 to 999. If the connection is set to autoconnect, connections with higher priority will be preferred. The higher number means higher priority. Defaults to 0. Note that this property only matters if there are more than one candidate profile to select for autoconnect. In case of equal priority, the profile used most recently is chosen. The number of times a connection should be tried when autoactivating before giving up. Zero means forever, -1 means the global default (4 times if not overridden). Setting this to 1 means to try activation only once before blocking autoconnect. Note that after a timeout, NetworkManager will try to autoconnect again. The number of times a connection should be tried when autoactivating before giving up. Zero means forever, -1 means the global default (4 times if not overridden). Setting this to 1 means to try activation only once before blocking autoconnect. Note that after a timeout, NetworkManager will try to autoconnect again. Whether or not slaves of this connection should be automatically brought up when NetworkManager activates this connection. This only has a real effect for master connections. The properties "autoconnect", "autoconnect-priority" and "autoconnect-retries" are unrelated to this setting. The permitted values are: 0: leave slave connections untouched, 1: activate all the slave connections with this connection, -1: default. If -1 (default) is set, global connection.autoconnect-slaves is read to determine the real value. If it is default as well, this fallbacks to 0. Whether or not slaves of this connection should be automatically brought up when NetworkManager activates this connection. This only has a real effect for master connections. The properties "autoconnect", "autoconnect-priority" and "autoconnect-retries" are unrelated to this setting. The permitted values are: 0: leave slave connections untouched, 1: activate all the slave connections with this connection, -1: default. If -1 (default) is set, global connection.autoconnect-slaves is read to determine the real value. If it is default as well, this fallbacks to 0. Whether DNSOverTls (dns-over-tls) is enabled for the connection. DNSOverTls is a technology which uses TLS to encrypt dns traffic. + + The permitted values are: "yes" (2) use DNSOverTls and disabled fallback, "opportunistic" (1) use DNSOverTls but allow fallback to unencrypted resolution, "no" (0) don't ever use DNSOverTls. If unspecified "default" depends on the plugin used. Systemd-resolved uses global setting. + + This feature requires a plugin which supports DNSOverTls. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved. Whether DNSOverTls (dns-over-tls) is enabled for the connection. DNSOverTls is a technology which uses TLS to encrypt dns traffic. The permitted values are: "yes" (2) use DNSOverTls and disabled fallback, "opportunistic" (1) use DNSOverTls but allow fallback to unencrypted resolution, "no" (0) don't ever use DNSOverTls. If unspecified "default" depends on the plugin used. Systemd-resolved uses global setting. This feature requires a plugin which supports DNSOverTls. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved. If greater than zero, delay success of IP addressing until either the timeout is reached, or an IP gateway replies to a ping. If greater than zero, delay success of IP addressing until either the timeout is reached, or an IP gateway replies to a ping. A human readable unique identifier for the connection, like "Work Wi-Fi" or "T-Mobile 3G". A human readable unique identifier for the connection, like "Work Wi-Fi" or "T-Mobile 3G". The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). + + For software devices this specifies the name of the created device. + + For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface. The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). For software devices this specifies the name of the created device. For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface. Whether LLDP is enabled for the connection. Whether LLDP is enabled for the connection. Whether Link-Local Multicast Name Resolution (LLMNR) is enabled for the connection. LLMNR is a protocol based on the Domain Name System (DNS) packet format that allows both IPv4 and IPv6 hosts to perform name resolution for hosts on the same local link. + + The permitted values are: "yes" (2) register hostname and resolving for the connection, "no" (0) disable LLMNR for the interface, "resolve" (1) do not register hostname but allow resolving of LLMNR host names If unspecified, "default" ultimately depends on the DNS plugin (which for systemd-resolved currently means "yes"). + + This feature requires a plugin which supports LLMNR. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved. Whether Link-Local Multicast Name Resolution (LLMNR) is enabled for the connection. LLMNR is a protocol based on the Domain Name System (DNS) packet format that allows both IPv4 and IPv6 hosts to perform name resolution for hosts on the same local link. The permitted values are: "yes" (2) register hostname and resolving for the connection, "no" (0) disable LLMNR for the interface, "resolve" (1) do not register hostname but allow resolving of LLMNR host names If unspecified, "default" ultimately depends on the DNS plugin (which for systemd-resolved currently means "yes"). This feature requires a plugin which supports LLMNR. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved. Interface name of the master device or UUID of the master connection. Interface name of the master device or UUID of the master connection. Whether mDNS is enabled for the connection. + + The permitted values are: "yes" (2) register hostname and resolving for the connection, "no" (0) disable mDNS for the interface, "resolve" (1) do not register hostname but allow resolving of mDNS host names and "default" (-1) to allow lookup of a global default in NetworkManager.conf. If unspecified, "default" ultimately depends on the DNS plugin (which for systemd-resolved currently means "no"). + + This feature requires a plugin which supports mDNS. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved. Whether mDNS is enabled for the connection. The permitted values are: "yes" (2) register hostname and resolving for the connection, "no" (0) disable mDNS for the interface, "resolve" (1) do not register hostname but allow resolving of mDNS host names and "default" (-1) to allow lookup of a global default in NetworkManager.conf. If unspecified, "default" ultimately depends on the DNS plugin (which for systemd-resolved currently means "no"). This feature requires a plugin which supports mDNS. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved. Whether the connection is metered. + + When updating this property on a currently activated connection, the change takes effect immediately. Whether the connection is metered. When updating this property on a currently activated connection, the change takes effect immediately. Whether to configure MPTCP endpoints and the address flags. If MPTCP is enabled in NetworkManager, it will configure the addresses of the interface as MPTCP endpoints. Note that IPv4 loopback addresses (127.0.0.0/8), IPv4 link local addresses (169.254.0.0/16), the IPv6 loopback address (::1), IPv6 link local addresses (fe80::/10), IPv6 unique local addresses (ULA, fc00::/7) and IPv6 privacy extension addresses (rfc3041, ipv6.ip6-privacy) will be excluded from being configured as endpoints. + + If "disabled" (0x1), MPTCP handling for the interface is disabled and no endpoints are registered. + + The flag "enabled-on-global-iface" (0x2) means that MPTCP handling is enabled if the interface configures a default route in the main routing table. This choice is per-address family, for example if there is an IPv4 default route 0.0.0.0/0, IPv4 endpoints are configured. + + The "enabled" (0x4) flag means that MPTCP handling is explicitly enabled. This flag can also be implied from the presence of other flags. + + If MPTCP handling is enabled, then endpoints will be configured with the specified address flags "signal" (0x10), "subflow" (0x20), "backup" (0x40), "fullmesh" (0x80). See ip-mptcp(8) manual for additional information about the flags. + + If the flags are zero, the global connection default from NetworkManager.conf is honored. If still unspecified, the fallback is either "disabled" or "enabled-on-global-iface,subflow" depending on "/proc/sys/net/mptcp/enabled". + + NetworkManager does not change the MPTCP limits nor enable MPTCP via "/proc/sys/net/mptcp/enabled". That is a host configuration which the admin can change via sysctl and ip-mptcp. + + Strict reverse path filtering (rp_filter) breaks many MPTCP use cases, so when MPTCP handling for IPv4 addresses on the interface is enabled, NetworkManager would loosen the strict reverse path filtering (1) to the loose setting (2). Whether to configure MPTCP endpoints and the address flags. If MPTCP is enabled in NetworkManager, it will configure the addresses of the interface as MPTCP endpoints. Note that IPv4 loopback addresses (127.0.0.0/8), IPv4 link local addresses (169.254.0.0/16), the IPv6 loopback address (::1), IPv6 link local addresses (fe80::/10), IPv6 unique local addresses (ULA, fc00::/7) and IPv6 privacy extension addresses (rfc3041, ipv6.ip6-privacy) will be excluded from being configured as endpoints. If "disabled" (0x1), MPTCP handling for the interface is disabled and no endpoints are registered. The flag "enabled-on-global-iface" (0x2) means that MPTCP handling is enabled if the interface configures a default route in the main routing table. This choice is per-address family, for example if there is an IPv4 default route 0.0.0.0/0, IPv4 endpoints are configured. The "enabled" (0x4) flag means that MPTCP handling is explicitly enabled. This flag can also be implied from the presence of other flags. If MPTCP handling is enabled, then endpoints will be configured with the specified address flags "signal" (0x10), "subflow" (0x20), "backup" (0x40), "fullmesh" (0x80). See ip-mptcp(8) manual for additional information about the flags. If the flags are zero, the global connection default from NetworkManager.conf is honored. If still unspecified, the fallback is either "disabled" or "enabled-on-global-iface,subflow" depending on "/proc/sys/net/mptcp/enabled". NetworkManager does not change the MPTCP limits nor enable MPTCP via "/proc/sys/net/mptcp/enabled". That is a host configuration which the admin can change via sysctl and ip-mptcp. Strict reverse path filtering (rp_filter) breaks many MPTCP use cases, so when MPTCP handling for IPv4 addresses on the interface is enabled, NetworkManager would loosen the strict reverse path filtering (1) to the loose setting (2). If configured, set to a Manufacturer Usage Description (MUD) URL that points to manufacturer-recommended network policies for IoT devices. It is transmitted as a DHCPv4 or DHCPv6 option. The value must be a valid URL starting with "https://". + + The special value "none" is allowed to indicate that no MUD URL is used. + + If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the ultimate default is "none". If configured, set to a Manufacturer Usage Description (MUD) URL that points to manufacturer-recommended network policies for IoT devices. It is transmitted as a DHCPv4 or DHCPv6 option. The value must be a valid URL starting with "https://". The special value "none" is allowed to indicate that no MUD URL is used. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the ultimate default is "none". Specifies whether the profile can be active multiple times at a particular moment. The value is of type NMConnectionMultiConnect. Specifies whether the profile can be active multiple times at a particular moment. The value is of type NMConnectionMultiConnect. An array of strings defining what access a given user has to this connection. If this is NULL or empty, all users are allowed to access this connection; otherwise users are allowed if and only if they are in this list. When this is not empty, the connection can be active only when one of the specified users is logged into an active session. Each entry is of the form "[type]:[id]:[reserved]"; for example, "user:dcbw:blah". + + At this time only the "user" [type] is allowed. Any other values are ignored and reserved for future use. [id] is the username that this permission refers to, which may not contain the ":" character. Any [reserved] information present must be ignored and is reserved for future use. All of [type], [id], and [reserved] must be valid UTF-8. An array of strings defining what access a given user has to this connection. If this is NULL or empty, all users are allowed to access this connection; otherwise users are allowed if and only if they are in this list. When this is not empty, the connection can be active only when one of the specified users is logged into an active session. Each entry is of the form "[type]:[id]:[reserved]"; for example, "user:dcbw:blah". At this time only the "user" [type] is allowed. Any other values are ignored and reserved for future use. [id] is the username that this permission refers to, which may not contain the ":" character. Any [reserved] information present must be ignored and is reserved for future use. All of [type], [id], and [reserved] must be valid UTF-8. FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified. FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified. List of connection UUIDs that should be activated when the base connection itself is activated. Currently, only VPN connections are supported. List of connection UUIDs that should be activated when the base connection itself is activated. Currently, only VPN connections are supported. Setting name of the device type of this slave's master connection (eg, "bond"), or NULL if this connection is not a slave. Setting name of the device type of this slave's master connection (eg, "bond"), or NULL if this connection is not a slave. This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. + + The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. + + Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. + + The '$' character is treated special to perform dynamic substitutions at runtime. Currently, supported are "${CONNECTION}", "${DEVICE}", "${MAC}", "${BOOT}", "${RANDOM}". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that "${DEVICE}" corresponds to the interface name of the device and "${MAC}" is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as "$$". For example, set it to "${CONNECTION}-${BOOT}-${DEVICE}" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. + + If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to "${CONNECTION}" and uses a unique, fixed ID for the connection. This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. The '$' character is treated special to perform dynamic substitutions at runtime. Currently, supported are "${CONNECTION}", "${DEVICE}", "${MAC}", "${BOOT}", "${RANDOM}". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that "${DEVICE}" corresponds to the interface name of the device and "${MAC}" is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as "$$". For example, set it to "${CONNECTION}-${BOOT}-${DEVICE}" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to "${CONNECTION}" and uses a unique, fixed ID for the connection. The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. + + NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved). The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved). Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, "802-3-ethernet" or "802-11-wireless" or "bluetooth", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, "vpn" or "bridge", etc). Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, "802-3-ethernet" or "802-11-wireless" or "bluetooth", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, "vpn" or "bridge", etc). A universally unique identifier for the connection, for example generated with libuuid. It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network. For example, it should not be changed when the "id" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or "type" property changes. + + The UUID must be in the format "2815492f-7e56-435e-b2e9-246bd7cdc664" (ie, contains only hexadecimal characters and "-"). A universally unique identifier for the connection, for example generated with libuuid. It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network. For example, it should not be changed when the "id" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or "type" property changes. The UUID must be in the format "2815492f-7e56-435e-b2e9-246bd7cdc664" (ie, contains only hexadecimal characters and "-"). Time in milliseconds to wait for connection to be considered activated. The wait will start after the pre-up dispatcher event. + + The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time. Time in milliseconds to wait for connection to be considered activated. The wait will start after the pre-up dispatcher event. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time. Timeout in milliseconds to wait for device at startup. During boot, devices may take a while to be detected by the driver. This property will cause to delay NetworkManager-wait-online.service and nm-online to give the device a chance to appear. This works by waiting for the given timeout until a compatible device for the profile is available and managed. + + The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time. Timeout in milliseconds to wait for device at startup. During boot, devices may take a while to be detected by the driver. This property will cause to delay NetworkManager-wait-online.service and nm-online to give the device a chance to appear. This works by waiting for the given timeout until a compatible device for the profile is available and managed. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time. The trust level of a the connection. Free form case-insensitive string (for example "Home", "Work", "Public"). NULL or unspecified zone means the connection will be placed in the default zone as defined by the firewall. + + When updating this property on a currently activated connection, the change takes effect immediately. The trust level of a the connection. Free form case-insensitive string (for example "Home", "Work", "Public"). NULL or unspecified zone means the connection will be placed in the default zone as defined by the firewall. When updating this property on a currently activated connection, the change takes effect immediately. If given, specifies the parent interface name or parent connection UUID from which this 6LowPAN interface should be created. If given, specifies the parent interface name or parent connection UUID from which this 6LowPAN interface should be created. List of strings to be matched against the altSubjectName of the certificate presented by the authentication server. If the list is empty, no verification of the server certificate's altSubjectName is performed. List of strings to be matched against the altSubjectName of the certificate presented by the authentication server. If the list is empty, no verification of the server certificate's altSubjectName is performed. Anonymous identity string for EAP authentication methods. Used as the unencrypted identity with EAP types that support different tunneled identity like EAP-TTLS. Anonymous identity string for EAP authentication methods. Used as the unencrypted identity with EAP types that support different tunneled identity like EAP-TTLS. A timeout for the authentication. Zero means the global default; if the global default is not set, the authentication timeout is 25 seconds. A timeout for the authentication. Zero means the global default; if the global default is not set, the authentication timeout is 25 seconds. Contains the CA certificate if used by the EAP method specified in the "eap" property. + + Certificate data is specified using a "scheme"; three are currently supported: blob, path and pkcs#11 URL. When using the blob scheme this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended. + + Note that enabling NMSetting8021x:system-ca-certs will override this setting to use the built-in path, if the built-in path is not a directory. Contains the CA certificate if used by the EAP method specified in the "eap" property. Certificate data is specified using a "scheme"; three are currently supported: blob, path and pkcs#11 URL. When using the blob scheme this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended. Note that enabling NMSetting8021x:system-ca-certs will override this setting to use the built-in path, if the built-in path is not a directory. The password used to access the CA certificate stored in "ca-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. The password used to access the CA certificate stored in "ca-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. Flags indicating how to handle the "ca-cert-password" property. Flags indicating how to handle the "ca-cert-password" property. UTF-8 encoded path to a directory containing PEM or DER formatted certificates to be added to the verification chain in addition to the certificate specified in the "ca-cert" property. + + If NMSetting8021x:system-ca-certs is enabled and the built-in CA path is an existing directory, then this setting is ignored. UTF-8 encoded path to a directory containing PEM or DER formatted certificates to be added to the verification chain in addition to the certificate specified in the "ca-cert" property. If NMSetting8021x:system-ca-certs is enabled and the built-in CA path is an existing directory, then this setting is ignored. Contains the client certificate if used by the EAP method specified in the "eap" property. + + Certificate data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme (which is backwards compatible with NM 0.7.x) this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. Contains the client certificate if used by the EAP method specified in the "eap" property. Certificate data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme (which is backwards compatible with NM 0.7.x) this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. The password used to access the client certificate stored in "client-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. The password used to access the client certificate stored in "client-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. Flags indicating how to handle the "client-cert-password" property. Flags indicating how to handle the "client-cert-password" property. Constraint for server domain name. If set, this list of FQDNs is used as a match requirement for dNSName element(s) of the certificate presented by the authentication server. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using the same comparison. Multiple valid FQDNs can be passed as a ";" delimited list. Constraint for server domain name. If set, this list of FQDNs is used as a match requirement for dNSName element(s) of the certificate presented by the authentication server. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using the same comparison. Multiple valid FQDNs can be passed as a ";" delimited list. Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison. Since version 1.24, multiple valid FQDNs can be passed as a ";" delimited list. Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison. Since version 1.24, multiple valid FQDNs can be passed as a ";" delimited list. The allowed EAP method to be used when authenticating to the network with 802.1x. Valid methods are: "leap", "md5", "tls", "peap", "ttls", "pwd", and "fast". Each method requires different configuration using the properties of this setting; refer to wpa_supplicant documentation for the allowed combinations. The allowed EAP method to be used when authenticating to the network with 802.1x. Valid methods are: "leap", "md5", "tls", "peap", "ttls", "pwd", and "fast". Each method requires different configuration using the properties of this setting; refer to wpa_supplicant documentation for the allowed combinations. Identity string for EAP authentication methods. Often the user's user or login name. Identity string for EAP authentication methods. Often the user's user or login name. Whether the 802.1X authentication is optional. If TRUE, the activation will continue even after a timeout or an authentication failure. Setting the property to TRUE is currently allowed only for Ethernet connections. If set to FALSE, the activation can continue only after a successful authentication. Whether the 802.1X authentication is optional. If TRUE, the activation will continue even after a timeout or an authentication failure. Setting the property to TRUE is currently allowed only for Ethernet connections. If set to FALSE, the activation can continue only after a successful authentication. UTF-8 encoded file path containing PAC for EAP-FAST. UTF-8 encoded file path containing PAC for EAP-FAST. UTF-8 encoded password used for EAP authentication methods. If both the "password" property and the "password-raw" property are specified, "password" is preferred. UTF-8 encoded password used for EAP authentication methods. If both the "password" property and the "password-raw" property are specified, "password" is preferred. Flags indicating how to handle the "password" property. Flags indicating how to handle the "password" property. Password used for EAP authentication methods, given as a byte array to allow passwords in other encodings than UTF-8 to be used. If both the "password" property and the "password-raw" property are specified, "password" is preferred. Password used for EAP authentication methods, given as a byte array to allow passwords in other encodings than UTF-8 to be used. If both the "password" property and the "password-raw" property are specified, "password" is preferred. Flags indicating how to handle the "password-raw" property. Flags indicating how to handle the "password-raw" property. Specifies authentication flags to use in "phase 1" outer authentication using NMSetting8021xAuthFlags options. The individual TLS versions can be explicitly disabled. If a certain TLS disable flag is not set, it is up to the supplicant to allow or forbid it. The TLS options map to tls_disable_tlsv1_x settings. See the wpa_supplicant documentation for more details. Specifies authentication flags to use in "phase 1" outer authentication using NMSetting8021xAuthFlags options. The individual TLS versions can be explicitly disabled. If a certain TLS disable flag is not set, it is up to the supplicant to allow or forbid it. The TLS options map to tls_disable_tlsv1_x settings. See the wpa_supplicant documentation for more details. Enables or disables in-line provisioning of EAP-FAST credentials when FAST is specified as the EAP method in the "eap" property. Recognized values are "0" (disabled), "1" (allow unauthenticated provisioning), "2" (allow authenticated provisioning), and "3" (allow both authenticated and unauthenticated provisioning). See the wpa_supplicant documentation for more details. Enables or disables in-line provisioning of EAP-FAST credentials when FAST is specified as the EAP method in the "eap" property. Recognized values are "0" (disabled), "1" (allow unauthenticated provisioning), "2" (allow authenticated provisioning), and "3" (allow both authenticated and unauthenticated provisioning). See the wpa_supplicant documentation for more details. Forces use of the new PEAP label during key derivation. Some RADIUS servers may require forcing the new PEAP label to interoperate with PEAPv1. Set to "1" to force use of the new PEAP label. See the wpa_supplicant documentation for more details. Forces use of the new PEAP label during key derivation. Some RADIUS servers may require forcing the new PEAP label to interoperate with PEAPv1. Set to "1" to force use of the new PEAP label. See the wpa_supplicant documentation for more details. Forces which PEAP version is used when PEAP is set as the EAP method in the "eap" property. When unset, the version reported by the server will be used. Sometimes when using older RADIUS servers, it is necessary to force the client to use a particular PEAP version. To do so, this property may be set to "0" or "1" to force that specific PEAP version. Forces which PEAP version is used when PEAP is set as the EAP method in the "eap" property. When unset, the version reported by the server will be used. Sometimes when using older RADIUS servers, it is necessary to force the client to use a particular PEAP version. To do so, this property may be set to "0" or "1" to force that specific PEAP version. List of strings to be matched against the altSubjectName of the certificate presented by the authentication server during the inner "phase 2" authentication. If the list is empty, no verification of the server certificate's altSubjectName is performed. List of strings to be matched against the altSubjectName of the certificate presented by the authentication server during the inner "phase 2" authentication. If the list is empty, no verification of the server certificate's altSubjectName is performed. Specifies the allowed "phase 2" inner authentication method when an EAP method that uses an inner TLS tunnel is specified in the "eap" property. For TTLS this property selects one of the supported non-EAP inner methods: "pap", "chap", "mschap", "mschapv2" while "phase2-autheap" selects an EAP inner method. For PEAP this selects an inner EAP method, one of: "gtc", "otp", "md5" and "tls". Each "phase 2" inner method requires specific parameters for successful authentication; see the wpa_supplicant documentation for more details. Both "phase2-auth" and "phase2-autheap" cannot be specified. Specifies the allowed "phase 2" inner authentication method when an EAP method that uses an inner TLS tunnel is specified in the "eap" property. For TTLS this property selects one of the supported non-EAP inner methods: "pap", "chap", "mschap", "mschapv2" while "phase2-autheap" selects an EAP inner method. For PEAP this selects an inner EAP method, one of: "gtc", "otp", "md5" and "tls". Each "phase 2" inner method requires specific parameters for successful authentication; see the wpa_supplicant documentation for more details. Both "phase2-auth" and "phase2-autheap" cannot be specified. Specifies the allowed "phase 2" inner EAP-based authentication method when TTLS is specified in the "eap" property. Recognized EAP-based "phase 2" methods are "md5", "mschapv2", "otp", "gtc", and "tls". Each "phase 2" inner method requires specific parameters for successful authentication; see the wpa_supplicant documentation for more details. Specifies the allowed "phase 2" inner EAP-based authentication method when TTLS is specified in the "eap" property. Recognized EAP-based "phase 2" methods are "md5", "mschapv2", "otp", "gtc", and "tls". Each "phase 2" inner method requires specific parameters for successful authentication; see the wpa_supplicant documentation for more details. Contains the "phase 2" CA certificate if used by the EAP method specified in the "phase2-auth" or "phase2-autheap" properties. + + Certificate data is specified using a "scheme"; three are currently supported: blob, path and pkcs#11 URL. When using the blob scheme this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended. + + Note that enabling NMSetting8021x:system-ca-certs will override this setting to use the built-in path, if the built-in path is not a directory. Contains the "phase 2" CA certificate if used by the EAP method specified in the "phase2-auth" or "phase2-autheap" properties. Certificate data is specified using a "scheme"; three are currently supported: blob, path and pkcs#11 URL. When using the blob scheme this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended. Note that enabling NMSetting8021x:system-ca-certs will override this setting to use the built-in path, if the built-in path is not a directory. The password used to access the "phase2" CA certificate stored in "phase2-ca-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. The password used to access the "phase2" CA certificate stored in "phase2-ca-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. Flags indicating how to handle the "phase2-ca-cert-password" property. Flags indicating how to handle the "phase2-ca-cert-password" property. UTF-8 encoded path to a directory containing PEM or DER formatted certificates to be added to the verification chain in addition to the certificate specified in the "phase2-ca-cert" property. + + If NMSetting8021x:system-ca-certs is enabled and the built-in CA path is an existing directory, then this setting is ignored. UTF-8 encoded path to a directory containing PEM or DER formatted certificates to be added to the verification chain in addition to the certificate specified in the "phase2-ca-cert" property. If NMSetting8021x:system-ca-certs is enabled and the built-in CA path is an existing directory, then this setting is ignored. Contains the "phase 2" client certificate if used by the EAP method specified in the "phase2-auth" or "phase2-autheap" properties. + + Certificate data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme (which is backwards compatible with NM 0.7.x) this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended. Contains the "phase 2" client certificate if used by the EAP method specified in the "phase2-auth" or "phase2-autheap" properties. Certificate data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme (which is backwards compatible with NM 0.7.x) this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended. The password used to access the "phase2" client certificate stored in "phase2-client-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. The password used to access the "phase2" client certificate stored in "phase2-client-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. Flags indicating how to handle the "phase2-client-cert-password" property. Flags indicating how to handle the "phase2-client-cert-password" property. Constraint for server domain name. If set, this list of FQDNs is used as a match requirement for dNSName element(s) of the certificate presented by the authentication server during the inner "phase 2" authentication. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using the same comparison. Multiple valid FQDNs can be passed as a ";" delimited list. Constraint for server domain name. If set, this list of FQDNs is used as a match requirement for dNSName element(s) of the certificate presented by the authentication server during the inner "phase 2" authentication. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using the same comparison. Multiple valid FQDNs can be passed as a ";" delimited list. Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server during the inner "phase 2" authentication. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison. Since version 1.24, multiple valid FQDNs can be passed as a ";" delimited list. Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server during the inner "phase 2" authentication. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison. Since version 1.24, multiple valid FQDNs can be passed as a ";" delimited list. Contains the "phase 2" inner private key when the "phase2-auth" or "phase2-autheap" property is set to "tls". + + Key data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme and private keys, this property should be set to the key's encrypted PEM encoded data. When using private keys with the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte. When using PKCS#12 format private keys and the blob scheme, this property should be set to the PKCS#12 data and the "phase2-private-key-password" property must be set to password used to decrypt the PKCS#12 certificate and key. When using PKCS#12 files and the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte, and as with the blob scheme the "phase2-private-key-password" property must be set to the password used to decode the PKCS#12 private key and certificate. Contains the "phase 2" inner private key when the "phase2-auth" or "phase2-autheap" property is set to "tls". Key data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme and private keys, this property should be set to the key's encrypted PEM encoded data. When using private keys with the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte. When using PKCS#12 format private keys and the blob scheme, this property should be set to the PKCS#12 data and the "phase2-private-key-password" property must be set to password used to decrypt the PKCS#12 certificate and key. When using PKCS#12 files and the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte, and as with the blob scheme the "phase2-private-key-password" property must be set to the password used to decode the PKCS#12 private key and certificate. The password used to decrypt the "phase 2" private key specified in the "phase2-private-key" property when the private key either uses the path scheme, or is a PKCS#12 format key. The password used to decrypt the "phase 2" private key specified in the "phase2-private-key" property when the private key either uses the path scheme, or is a PKCS#12 format key. Flags indicating how to handle the "phase2-private-key-password" property. Flags indicating how to handle the "phase2-private-key-password" property. Substring to be matched against the subject of the certificate presented by the authentication server during the inner "phase 2" authentication. When unset, no verification of the authentication server certificate's subject is performed. This property provides little security, if any, and its use is deprecated in favor of NMSetting8021x:phase2-domain-suffix-match. Substring to be matched against the subject of the certificate presented by the authentication server during the inner "phase 2" authentication. When unset, no verification of the authentication server certificate's subject is performed. This property provides little security, if any, and its use is deprecated in favor of NMSetting8021x:phase2-domain-suffix-match. PIN used for EAP authentication methods. PIN used for EAP authentication methods. Flags indicating how to handle the "pin" property. Flags indicating how to handle the "pin" property. Contains the private key when the "eap" property is set to "tls". + + Key data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme and private keys, this property should be set to the key's encrypted PEM encoded data. When using private keys with the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte. When using PKCS#12 format private keys and the blob scheme, this property should be set to the PKCS#12 data and the "private-key-password" property must be set to password used to decrypt the PKCS#12 certificate and key. When using PKCS#12 files and the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte, and as with the blob scheme the "private-key-password" property must be set to the password used to decode the PKCS#12 private key and certificate. + + WARNING: "private-key" is not a "secret" property, and thus unencrypted private key data using the BLOB scheme may be readable by unprivileged users. Private keys should always be encrypted with a private key password to prevent unauthorized access to unencrypted private key data. Contains the private key when the "eap" property is set to "tls". Key data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme and private keys, this property should be set to the key's encrypted PEM encoded data. When using private keys with the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte. When using PKCS#12 format private keys and the blob scheme, this property should be set to the PKCS#12 data and the "private-key-password" property must be set to password used to decrypt the PKCS#12 certificate and key. When using PKCS#12 files and the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte, and as with the blob scheme the "private-key-password" property must be set to the password used to decode the PKCS#12 private key and certificate. WARNING: "private-key" is not a "secret" property, and thus unencrypted private key data using the BLOB scheme may be readable by unprivileged users. Private keys should always be encrypted with a private key password to prevent unauthorized access to unencrypted private key data. The password used to decrypt the private key specified in the "private-key" property when the private key either uses the path scheme, or if the private key is a PKCS#12 format key. The password used to decrypt the private key specified in the "private-key" property when the private key either uses the path scheme, or if the private key is a PKCS#12 format key. Flags indicating how to handle the "private-key-password" property. Flags indicating how to handle the "private-key-password" property. Substring to be matched against the subject of the certificate presented by the authentication server. When unset, no verification of the authentication server certificate's subject is performed. This property provides little security, if any, and its use is deprecated in favor of NMSetting8021x:domain-suffix-match. Substring to be matched against the subject of the certificate presented by the authentication server. When unset, no verification of the authentication server certificate's subject is performed. This property provides little security, if any, and its use is deprecated in favor of NMSetting8021x:domain-suffix-match. When TRUE, overrides the "ca-path" and "phase2-ca-path" properties using the system CA directory specified at configure time with the --system-ca-path switch. The certificates in this directory are added to the verification chain in addition to any certificates specified by the "ca-cert" and "phase2-ca-cert" properties. If the path provided with --system-ca-path is rather a file name (bundle of trusted CA certificates), it overrides "ca-cert" and "phase2-ca-cert" properties instead (sets ca_cert/ca_cert2 options for wpa_supplicant). When TRUE, overrides the "ca-path" and "phase2-ca-path" properties using the system CA directory specified at configure time with the --system-ca-path switch. The certificates in this directory are added to the verification chain in addition to any certificates specified by the "ca-cert" and "phase2-ca-cert" properties. If the path provided with --system-ca-path is rather a file name (bundle of trusted CA certificates), it overrides "ca-cert" and "phase2-ca-cert" properties instead (sets ca_cert/ca_cert2 options for wpa_supplicant). Encapsulation of ADSL connection. Can be "vcmux" or "llc". Encapsulation of ADSL connection. Can be "vcmux" or "llc". Password used to authenticate with the ADSL service. Password used to authenticate with the ADSL service. Flags indicating how to handle the "password" property. Flags indicating how to handle the "password" property. ADSL connection protocol. Can be "pppoa", "pppoe" or "ipoatm". ADSL connection protocol. Can be "pppoa", "pppoe" or "ipoatm". Username used to authenticate with the ADSL service. Username used to authenticate with the ADSL service. VCI of ADSL connection VCI of ADSL connection VPI of ADSL connection VPI of ADSL connection The Bluetooth address of the device. The Bluetooth address of the device. Either "dun" for Dial-Up Networking connections or "panu" for Personal Area Networking connections to devices supporting the NAP profile. Either "dun" for Dial-Up Networking connections or "panu" for Personal Area Networking connections to devices supporting the NAP profile. Dictionary of key/value pairs of bonding options. Both keys and values must be strings. Option names must contain only alphanumeric characters (ie, [a-zA-Z0-9]). Dictionary of key/value pairs of bonding options. Both keys and values must be strings. Option names must contain only alphanumeric characters (ie, [a-zA-Z0-9]). The queue ID of this bond port. The maximum value of queue ID is the number of TX queues currently active in device. The queue ID of this bond port. The maximum value of queue ID is the number of TX queues currently active in device. The Ethernet MAC address aging time, in seconds. The Ethernet MAC address aging time, in seconds. The Spanning Tree Protocol (STP) forwarding delay, in seconds. The Spanning Tree Protocol (STP) forwarding delay, in seconds. If specified, The MAC address of the multicast group this bridge uses for STP. + + The address must be a link-local address in standard Ethernet MAC address format, ie an address of the form 01:80:C2:00:00:0X, with X in [0, 4..F]. If not specified the default value is 01:80:C2:00:00:00. If specified, The MAC address of the multicast group this bridge uses for STP. The address must be a link-local address in standard Ethernet MAC address format, ie an address of the form 01:80:C2:00:00:0X, with X in [0, 4..F]. If not specified the default value is 01:80:C2:00:00:00. A mask of group addresses to forward. Usually, group addresses in the range from 01:80:C2:00:00:00 to 01:80:C2:00:00:0F are not forwarded according to standards. This property is a mask of 16 bits, each corresponding to a group address in that range that must be forwarded. The mask can't have bits 0, 1 or 2 set because they are used for STP, MAC pause frames and LACP. A mask of group addresses to forward. Usually, group addresses in the range from 01:80:C2:00:00:00 to 01:80:C2:00:00:0F are not forwarded according to standards. This property is a mask of 16 bits, each corresponding to a group address in that range that must be forwarded. The mask can't have bits 0, 1 or 2 set because they are used for STP, MAC pause frames and LACP. The Spanning Tree Protocol (STP) hello time, in seconds. The Spanning Tree Protocol (STP) hello time, in seconds. If specified, the MAC address of bridge. When creating a new bridge, this MAC address will be set. + + If this field is left unspecified, the "ethernet.cloned-mac-address" is referred instead to generate the initial MAC address. Note that setting "ethernet.cloned-mac-address" anyway overwrites the MAC address of the bridge later while activating the bridge. Hence, this property is deprecated. Deprecated: 1 If specified, the MAC address of bridge. When creating a new bridge, this MAC address will be set. If this field is left unspecified, the "ethernet.cloned-mac-address" is referred instead to generate the initial MAC address. Note that setting "ethernet.cloned-mac-address" anyway overwrites the MAC address of the bridge later while activating the bridge. Hence, this property is deprecated. Deprecated: 1 The Spanning Tree Protocol (STP) maximum message age, in seconds. The Spanning Tree Protocol (STP) maximum message age, in seconds. Set maximum size of multicast hash table (value must be a power of 2). Set maximum size of multicast hash table (value must be a power of 2). Set the number of queries the bridge will send before stopping forwarding a multicast group after a "leave" message has been received. Set the number of queries the bridge will send before stopping forwarding a multicast group after a "leave" message has been received. Set interval (in deciseconds) between queries to find remaining members of a group, after a "leave" message is received. Set interval (in deciseconds) between queries to find remaining members of a group, after a "leave" message is received. Set delay (in deciseconds) after which the bridge will leave a group, if no membership reports for this group are received. Set delay (in deciseconds) after which the bridge will leave a group, if no membership reports for this group are received. Enable or disable sending of multicast queries by the bridge. If not specified the option is disabled. Enable or disable sending of multicast queries by the bridge. If not specified the option is disabled. If no queries are seen after this delay (in deciseconds) has passed, the bridge will start to send its own queries. If no queries are seen after this delay (in deciseconds) has passed, the bridge will start to send its own queries. Interval (in deciseconds) between queries sent by the bridge after the end of the startup phase. Interval (in deciseconds) between queries sent by the bridge after the end of the startup phase. Set the Max Response Time/Max Response Delay (in deciseconds) for IGMP/MLD queries sent by the bridge. Set the Max Response Time/Max Response Delay (in deciseconds) for IGMP/MLD queries sent by the bridge. If enabled the bridge's own IP address is used as the source address for IGMP queries otherwise the default of 0.0.0.0 is used. If enabled the bridge's own IP address is used as the source address for IGMP queries otherwise the default of 0.0.0.0 is used. Sets bridge's multicast router. Multicast-snooping must be enabled for this option to work. + + Supported values are: 'auto', 'disabled', 'enabled' to which kernel assigns the numbers 1, 0, and 2, respectively. If not specified the default value is 'auto' (1). Sets bridge's multicast router. Multicast-snooping must be enabled for this option to work. Supported values are: 'auto', 'disabled', 'enabled' to which kernel assigns the numbers 1, 0, and 2, respectively. If not specified the default value is 'auto' (1). Controls whether IGMP snooping is enabled for this bridge. Note that if snooping was automatically disabled due to hash collisions, the system may refuse to enable the feature until the collisions are resolved. Controls whether IGMP snooping is enabled for this bridge. Note that if snooping was automatically disabled due to hash collisions, the system may refuse to enable the feature until the collisions are resolved. Set the number of IGMP queries to send during startup phase. Set the number of IGMP queries to send during startup phase. Sets the time (in deciseconds) between queries sent out at startup to determine membership information. Sets the time (in deciseconds) between queries sent out at startup to determine membership information. Sets the Spanning Tree Protocol (STP) priority for this bridge. Lower values are "better"; the lowest priority bridge will be elected the root bridge. Sets the Spanning Tree Protocol (STP) priority for this bridge. Lower values are "better"; the lowest priority bridge will be elected the root bridge. Controls whether Spanning Tree Protocol (STP) is enabled for this bridge. Controls whether Spanning Tree Protocol (STP) is enabled for this bridge. The default PVID for the ports of the bridge, that is the VLAN id assigned to incoming untagged frames. The default PVID for the ports of the bridge, that is the VLAN id assigned to incoming untagged frames. Control whether VLAN filtering is enabled on the bridge. Control whether VLAN filtering is enabled on the bridge. If specified, the protocol used for VLAN filtering. + + Supported values are: '802.1Q', '802.1ad'. If not specified the default value is '802.1Q'. If specified, the protocol used for VLAN filtering. Supported values are: '802.1Q', '802.1ad'. If not specified the default value is '802.1Q'. Controls whether per-VLAN stats accounting is enabled. Controls whether per-VLAN stats accounting is enabled. Array of bridge VLAN objects. In addition to the VLANs specified here, the bridge will also have the default-pvid VLAN configured by the bridge.vlan-default-pvid property. + + In nmcli the VLAN list can be specified with the following syntax: + + $vid [pvid] [untagged] [, $vid [pvid] [untagged]]... + + where $vid is either a single id between 1 and 4094 or a range, represented as a couple of ids separated by a dash. Array of bridge VLAN objects. In addition to the VLANs specified here, the bridge will also have the default-pvid VLAN configured by the bridge.vlan-default-pvid property. In nmcli the VLAN list can be specified with the following syntax: $vid [pvid] [untagged] [, $vid [pvid] [untagged]]... where $vid is either a single id between 1 and 4094 or a range, represented as a couple of ids separated by a dash. Enables or disables "hairpin mode" for the port, which allows frames to be sent back out through the port the frame was received on. Enables or disables "hairpin mode" for the port, which allows frames to be sent back out through the port the frame was received on. The Spanning Tree Protocol (STP) port cost for destinations via this port. The Spanning Tree Protocol (STP) port cost for destinations via this port. The Spanning Tree Protocol (STP) priority of this bridge port. The Spanning Tree Protocol (STP) priority of this bridge port. Array of bridge VLAN objects. In addition to the VLANs specified here, the port will also have the default-pvid VLAN configured on the bridge by the bridge.vlan-default-pvid property. + + In nmcli the VLAN list can be specified with the following syntax: + + $vid [pvid] [untagged] [, $vid [pvid] [untagged]]... + + where $vid is either a single id between 1 and 4094 or a range, represented as a couple of ids separated by a dash. Array of bridge VLAN objects. In addition to the VLANs specified here, the port will also have the default-pvid VLAN configured on the bridge by the bridge.vlan-default-pvid property. In nmcli the VLAN list can be specified with the following syntax: $vid [pvid] [untagged] [, $vid [pvid] [untagged]]... where $vid is either a single id between 1 and 4094 or a range, represented as a couple of ids separated by a dash. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames. The number to dial to establish the connection to the CDMA-based mobile broadband network, if any. If not specified, the default number (#777) is used when required. The number to dial to establish the connection to the CDMA-based mobile broadband network, if any. If not specified, the default number (#777) is used when required. The password used to authenticate with the network, if required. Many providers do not require a password, or accept any password. But if a password is required, it is specified here. The password used to authenticate with the network, if required. Many providers do not require a password, or accept any password. But if a password is required, it is specified here. Flags indicating how to handle the "password" property. Flags indicating how to handle the "password" property. The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here. The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here. Specifies the NMSettingDcbFlags for the DCB FCoE application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). Specifies the NMSettingDcbFlags for the DCB FCoE application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). The FCoE controller mode; either "fabric" or "vn2vn". + + Since 1.34, NULL is the default and means "fabric". Before 1.34, NULL was rejected as invalid and the default was "fabric". The FCoE controller mode; either "fabric" or "vn2vn". Since 1.34, NULL is the default and means "fabric". Before 1.34, NULL was rejected as invalid and the default was "fabric". The highest User Priority (0 - 7) which FCoE frames should use, or -1 for default priority. Only used when the "app-fcoe-flags" property includes the NM_SETTING_DCB_FLAG_ENABLE (0x1) flag. The highest User Priority (0 - 7) which FCoE frames should use, or -1 for default priority. Only used when the "app-fcoe-flags" property includes the NM_SETTING_DCB_FLAG_ENABLE (0x1) flag. Specifies the NMSettingDcbFlags for the DCB FIP application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). Specifies the NMSettingDcbFlags for the DCB FIP application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). The highest User Priority (0 - 7) which FIP frames should use, or -1 for default priority. Only used when the "app-fip-flags" property includes the NM_SETTING_DCB_FLAG_ENABLE (0x1) flag. The highest User Priority (0 - 7) which FIP frames should use, or -1 for default priority. Only used when the "app-fip-flags" property includes the NM_SETTING_DCB_FLAG_ENABLE (0x1) flag. Specifies the NMSettingDcbFlags for the DCB iSCSI application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). Specifies the NMSettingDcbFlags for the DCB iSCSI application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). The highest User Priority (0 - 7) which iSCSI frames should use, or -1 for default priority. Only used when the "app-iscsi-flags" property includes the NM_SETTING_DCB_FLAG_ENABLE (0x1) flag. The highest User Priority (0 - 7) which iSCSI frames should use, or -1 for default priority. Only used when the "app-iscsi-flags" property includes the NM_SETTING_DCB_FLAG_ENABLE (0x1) flag. An array of 8 uint values, where the array index corresponds to the User Priority (0 - 7) and the value indicates the percentage of bandwidth of the priority's assigned group that the priority may use. The sum of all percentages for priorities which belong to the same group must total 100 percents. An array of 8 uint values, where the array index corresponds to the User Priority (0 - 7) and the value indicates the percentage of bandwidth of the priority's assigned group that the priority may use. The sum of all percentages for priorities which belong to the same group must total 100 percents. An array of 8 boolean values, where the array index corresponds to the User Priority (0 - 7) and the value indicates whether or not the corresponding priority should transmit priority pause. An array of 8 boolean values, where the array index corresponds to the User Priority (0 - 7) and the value indicates whether or not the corresponding priority should transmit priority pause. Specifies the NMSettingDcbFlags for DCB Priority Flow Control (PFC). Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). Specifies the NMSettingDcbFlags for DCB Priority Flow Control (PFC). Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). An array of 8 uint values, where the array index corresponds to the Priority Group ID (0 - 7) and the value indicates the percentage of link bandwidth allocated to that group. Allowed values are 0 - 100, and the sum of all values must total 100 percents. An array of 8 uint values, where the array index corresponds to the Priority Group ID (0 - 7) and the value indicates the percentage of link bandwidth allocated to that group. Allowed values are 0 - 100, and the sum of all values must total 100 percents. Specifies the NMSettingDcbFlags for DCB Priority Groups. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). Specifies the NMSettingDcbFlags for DCB Priority Groups. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). An array of 8 uint values, where the array index corresponds to the User Priority (0 - 7) and the value indicates the Priority Group ID. Allowed Priority Group ID values are 0 - 7 or 15 for the unrestricted group. An array of 8 uint values, where the array index corresponds to the User Priority (0 - 7) and the value indicates the Priority Group ID. Allowed Priority Group ID values are 0 - 7 or 15 for the unrestricted group. An array of 8 boolean values, where the array index corresponds to the User Priority (0 - 7) and the value indicates whether or not the priority may use all of the bandwidth allocated to its assigned group. An array of 8 boolean values, where the array index corresponds to the User Priority (0 - 7) and the value indicates whether or not the priority may use all of the bandwidth allocated to its assigned group. An array of 8 uint values, where the array index corresponds to the User Priority (0 - 7) and the value indicates the traffic class (0 - 7) to which the priority is mapped. An array of 8 uint values, where the array index corresponds to the User Priority (0 - 7) and the value indicates the traffic class (0 - 7) to which the priority is mapped. The GPRS Access Point Name specifying the APN used when establishing a data session with the GSM-based network. The APN often determines how the user will be billed for their network usage and whether the user has access to the Internet or just a provider-specific walled-garden, so it is important to use the correct APN for the user's mobile broadband plan. The APN may only be composed of the characters a-z, 0-9, ., and - per GSM 03.60 Section 14.9. The GPRS Access Point Name specifying the APN used when establishing a data session with the GSM-based network. The APN often determines how the user will be billed for their network usage and whether the user has access to the Internet or just a provider-specific walled-garden, so it is important to use the correct APN for the user's mobile broadband plan. The APN may only be composed of the characters a-z, 0-9, ., and - per GSM 03.60 Section 14.9. When TRUE, the settings such as APN, username, or password will default to values that match the network the modem will register to in the Mobile Broadband Provider database. When TRUE, the settings such as APN, username, or password will default to values that match the network the modem will register to in the Mobile Broadband Provider database. The device unique identifier (as given by the WWAN management service) which this connection applies to. If given, the connection will only apply to the specified device. The device unique identifier (as given by the WWAN management service) which this connection applies to. If given, the connection will only apply to the specified device. When TRUE, only connections to the home network will be allowed. Connections to roaming networks will not be made. When TRUE, only connections to the home network will be allowed. Connections to roaming networks will not be made. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames. The Network ID (GSM LAI format, ie MCC-MNC) to force specific network registration. If the Network ID is specified, NetworkManager will attempt to force the device to register only on the specified network. This can be used to ensure that the device does not roam when direct roaming control of the device is not otherwise possible. The Network ID (GSM LAI format, ie MCC-MNC) to force specific network registration. If the Network ID is specified, NetworkManager will attempt to force the device to register only on the specified network. This can be used to ensure that the device does not roam when direct roaming control of the device is not otherwise possible. Legacy setting that used to help establishing PPP data sessions for GSM-based modems. Deprecated: 1 Legacy setting that used to help establishing PPP data sessions for GSM-based modems. Deprecated: 1 The password used to authenticate with the network, if required. Many providers do not require a password, or accept any password. But if a password is required, it is specified here. The password used to authenticate with the network, if required. Many providers do not require a password, or accept any password. But if a password is required, it is specified here. Flags indicating how to handle the "password" property. Flags indicating how to handle the "password" property. If the SIM is locked with a PIN it must be unlocked before any other operations are requested. Specify the PIN here to allow operation of the device. If the SIM is locked with a PIN it must be unlocked before any other operations are requested. Specify the PIN here to allow operation of the device. Flags indicating how to handle the "pin" property. Flags indicating how to handle the "pin" property. The SIM card unique identifier (as given by the WWAN management service) which this connection applies to. If given, the connection will apply to any device also allowed by "device-id" which contains a SIM card matching the given identifier. The SIM card unique identifier (as given by the WWAN management service) which this connection applies to. If given, the connection will apply to any device also allowed by "device-id" which contains a SIM card matching the given identifier. A MCC/MNC string like "310260" or "21601" identifying the specific mobile network operator which this connection applies to. If given, the connection will apply to any device also allowed by "device-id" and "sim-id" which contains a SIM card provisioned by the given operator. A MCC/MNC string like "310260" or "21601" identifying the specific mobile network operator which this connection applies to. If given, the connection will apply to any device also allowed by "device-id" and "sim-id" which contains a SIM card provisioned by the given operator. The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here. The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here. Whether the system hostname can be determined from DHCP on this connection. + + When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1). Whether the system hostname can be determined from DHCP on this connection. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1). Whether the system hostname can be determined from reverse DNS lookup of addresses on this device. + + When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1). Whether the system hostname can be determined from reverse DNS lookup of addresses on this device. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1). If set to NM_TERNARY_TRUE (1), NetworkManager attempts to get the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this device only when the device has the default route for the given address family (IPv4/IPv6). + + If set to NM_TERNARY_FALSE (0), the hostname can be set from this device even if it doesn't have the default route. + + When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_FALSE (0). If set to NM_TERNARY_TRUE (1), NetworkManager attempts to get the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this device only when the device has the default route for the given address family (IPv4/IPv6). If set to NM_TERNARY_FALSE (0), the hostname can be set from this device even if it doesn't have the default route. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_FALSE (0). The relative priority of this connection to determine the system hostname. A lower numerical value is better (higher priority). A connection with higher priority is considered before connections with lower priority. + + If the value is zero, it can be overridden by a global value from NetworkManager configuration. If the property doesn't have a value in the global configuration, the value is assumed to be 100. + + Negative values have the special effect of excluding other connections with a greater numerical priority value; so in presence of at least one negative priority, only connections with the lowest priority value will be used to determine the hostname. The relative priority of this connection to determine the system hostname. A lower numerical value is better (higher priority). A connection with higher priority is considered before connections with lower priority. If the value is zero, it can be overridden by a global value from NetworkManager configuration. If the property doesn't have a value in the global configuration, the value is assumed to be 100. Negative values have the special effect of excluding other connections with a greater numerical priority value; so in presence of at least one negative priority, only connections with the lowest priority value will be used to determine the hostname. If specified, this connection will only apply to the IPoIB device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing). If specified, this connection will only apply to the IPoIB device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing). If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames. The InfiniBand P_Key to use for this device. A value of -1 means to use the default P_Key (aka "the P_Key at index 0"). Otherwise, it is a 16-bit unsigned integer, whose high bit is set if it is a "full membership" P_Key. The InfiniBand P_Key to use for this device. A value of -1 means to use the default P_Key (aka "the P_Key at index 0"). Otherwise, it is a 16-bit unsigned integer, whose high bit is set if it is a "full membership" P_Key. The interface name of the parent device of this device. Normally NULL, but if the "p_key" property is set, then you must specify the base device by setting either this property or "mac-address". The interface name of the parent device of this device. Normally NULL, but if the "p_key" property is set, then you must specify the base device by setting either this property or "mac-address". The IP-over-InfiniBand transport mode. Either "datagram" or "connected". The IP-over-InfiniBand transport mode. Either "datagram" or "connected". Array of IP addresses. Array of IP addresses. Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. + + The property is currently implemented only for IPv4. Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4. A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. + + The special values "mac" and "perm-mac" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. + + The special value "ipv6-duid" uses the DUID from "ipv6.dhcp-duid" property as an RFC4361-compliant client identifier. As IAID it uses "ipv4.dhcp-iaid" and falls back to "ipv6.dhcp-iaid" if unset. + + The special value "duid" generates a RFC4361-compliant client identifier based on "ipv4.dhcp-iaid" and uses a DUID generated by hashing /etc/machine-id. + + The special value "stable" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If you set the stable-id, you may want to include the "${DEVICE}" or "${MAC}" specifier to get a per-device key. + + If unset, a globally configured default is used. If still unset, the default depends on the DHCP plugin. A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values "mac" and "perm-mac" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value "ipv6-duid" uses the DUID from "ipv6.dhcp-duid" property as an RFC4361-compliant client identifier. As IAID it uses "ipv4.dhcp-iaid" and falls back to "ipv6.dhcp-iaid" if unset. The special value "duid" generates a RFC4361-compliant client identifier based on "ipv4.dhcp-iaid" and uses a DUID generated by hashing /etc/machine-id. The special value "stable" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If you set the stable-id, you may want to include the "${DEVICE}" or "${MAC}" specifier to get a per-device key. If unset, a globally configured default is used. If still unset, the default depends on the DHCP plugin. If the "dhcp-send-hostname" property is TRUE, then the specified FQDN will be sent to the DHCP server when acquiring a lease. This property and "dhcp-hostname" are mutually exclusive and cannot be set at the same time. If the "dhcp-send-hostname" property is TRUE, then the specified FQDN will be sent to the DHCP server when acquiring a lease. This property and "dhcp-hostname" are mutually exclusive and cannot be set at the same time. If the "dhcp-send-hostname" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and "dhcp-fqdn" are mutually exclusive and cannot be set at the same time. If the "dhcp-send-hostname" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and "dhcp-fqdn" are mutually exclusive and cannot be set at the same time. Flags for the DHCP hostname and FQDN. + + Currently, this property only includes flags to control the FQDN flags set in the DHCP FQDN option. Supported FQDN flags are NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) and NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE (0x4). When no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is set, the DHCP FQDN option will contain no flag. Otherwise, if no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is not set, the standard FQDN flags are set in the request: NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) for IPv4 and NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1) for IPv6. + + When this property is set to the default value NM_DHCP_HOSTNAME_FLAG_NONE (0x0), a global default is looked up in NetworkManager configuration. If that value is unset or also NM_DHCP_HOSTNAME_FLAG_NONE (0x0), then the standard FQDN flags described above are sent in the DHCP requests. Flags for the DHCP hostname and FQDN. Currently, this property only includes flags to control the FQDN flags set in the DHCP FQDN option. Supported FQDN flags are NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) and NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE (0x4). When no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is set, the DHCP FQDN option will contain no flag. Otherwise, if no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is not set, the standard FQDN flags are set in the request: NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) for IPv4 and NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1) for IPv6. When this property is set to the default value NM_DHCP_HOSTNAME_FLAG_NONE (0x0), a global default is looked up in NetworkManager configuration. If that value is unset or also NM_DHCP_HOSTNAME_FLAG_NONE (0x0), then the standard FQDN flags described above are sent in the DHCP requests. A string containing the "Identity Association Identifier" (IAID) used by the DHCP client. The property is a 32-bit decimal value or a special value among "mac", "perm-mac", "ifname" and "stable". When set to "mac" (or "perm-mac"), the last 4 bytes of the current (or permanent) MAC address are used as IAID. When set to "ifname", the IAID is computed by hashing the interface name. The special value "stable" can be used to generate an IAID based on the stable-id (see connection.stable-id), a per-host key and the interface name. When the property is unset, the value from global configuration is used; if no global default is set then the IAID is assumed to be "ifname". Note that at the moment this property is ignored for IPv6 by dhclient, which always derives the IAID from the MAC address. A string containing the "Identity Association Identifier" (IAID) used by the DHCP client. The property is a 32-bit decimal value or a special value among "mac", "perm-mac", "ifname" and "stable". When set to "mac" (or "perm-mac"), the last 4 bytes of the current (or permanent) MAC address are used as IAID. When set to "ifname", the IAID is computed by hashing the interface name. The special value "stable" can be used to generate an IAID based on the stable-id (see connection.stable-id), a per-host key and the interface name. When the property is unset, the value from global configuration is used; if no global default is set then the IAID is assumed to be "ifname". Note that at the moment this property is ignored for IPv6 by dhclient, which always derives the IAID from the MAC address. Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers. + + For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. "192.168.122.0/24"). + + This property is currently not implemented for DHCPv6. Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers. For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. "192.168.122.0/24"). This property is currently not implemented for DHCPv6. If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer. If the "dhcp-hostname" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent. If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer. If the "dhcp-hostname" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent. A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). + + Set to 2147483647 (MAXINT32) for infinity. A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). Set to 2147483647 (MAXINT32) for infinity. The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server. + + Since 1.28 The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server. Since 1.28 Array of IP addresses of DNS servers. Array of IP addresses of DNS servers. Array of DNS options as described in man 5 resolv.conf. + + NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. + + The currently supported options are "attempts", "debug", "edns0", "inet6", "ip6-bytestring", "ip6-dotint", "ndots", "no-check-names", "no-ip6-dotint", "no-reload", "no-tld-query", "rotate", "single-request", "single-request-reopen", "timeout", "trust-ad", "use-vc". + + The "trust-ad" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have "trust-ad" enabled. + + When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then "edns0" and "trust-ad" are automatically added. Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are "attempts", "debug", "edns0", "inet6", "ip6-bytestring", "ip6-dotint", "ndots", "no-check-names", "no-ip6-dotint", "no-reload", "no-tld-query", "rotate", "single-request", "single-request-reopen", "timeout", "trust-ad", "use-vc". The "trust-ad" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have "trust-ad" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then "edns0" and "trust-ad" are automatically added. DNS servers priority. + + The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). + + Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. + + Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. + + Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. + + When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. + + When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the "rotate" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. + + When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured. DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the "rotate" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured. List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. + + When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. + + When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting "ignore-auto-dns". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15). List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting "ignore-auto-dns". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15). The gateway associated with this configuration. This is only meaningful if "addresses" is also set. + + The gateway's main purpose is to control the next hop of the standard default route on the device. Hence, the gateway property conflicts with "never-default" and will be automatically dropped if the IP configuration is set to never-default. + + As an alternative to set the gateway, configure a static default route with /0 as prefix length. The gateway associated with this configuration. This is only meaningful if "addresses" is also set. The gateway's main purpose is to control the next hop of the standard default route on the device. Hence, the gateway property conflicts with "never-default" and will be automatically dropped if the IP configuration is set to never-default. As an alternative to set the gateway, configure a static default route with /0 as prefix length. When "method" is set to "auto" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the "dns" and "dns-search" properties, if any, are used. When "method" is set to "auto" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the "dns" and "dns-search" properties, if any, are used. When "method" is set to "auto" and this property to TRUE, automatically configured routes are ignored and only routes specified in the "routes" property, if any, are used. When "method" is set to "auto" and this property to TRUE, automatically configured routes are ignored and only routes specified in the "routes" property, if any, are used. Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. + + When set to "auto", the value is dependent on "ipv4.method". When set to "default", it honors the global connection default, before falling back to "auto". Note that if "ipv4.method" is "disabled", then link local addressing is always disabled too. The default is "default". + + Since 1.40 Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. When set to "auto", the value is dependent on "ipv4.method". When set to "default", it honors the global connection default, before falling back to "auto". Note that if "ipv4.method" is "disabled", then link local addressing is always disabled too. The default is "default". Since 1.40 If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out. Note that at least one IP configuration must succeed or overall network configuration will still fail. For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully. If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out. Note that at least one IP configuration must succeed or overall network configuration will still fail. For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully. IP configuration method. + + NMSettingIP4Config and NMSettingIP6Config both support "disabled", "auto", "manual", and "link-local". See the subclass-specific documentation for other values. + + In general, for the "auto" method, properties such as "dns" and "routes" specify information that is added on to the information returned from automatic configuration. The "ignore-auto-routes" and "ignore-auto-dns" properties modify this behavior. + + For methods that imply no upstream network, such as "shared" or "link-local", these properties must be empty. + + For IPv4 method "shared", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared. IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support "disabled", "auto", "manual", and "link-local". See the subclass-specific documentation for other values. In general, for the "auto" method, properties such as "dns" and "routes" specify information that is added on to the information returned from automatic configuration. The "ignore-auto-routes" and "ignore-auto-dns" properties modify this behavior. For methods that imply no upstream network, such as "shared" or "link-local", these properties must be empty. For IPv4 method "shared", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared. If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager. If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager. The minimum time interval in milliseconds for which dynamic IP configuration should be tried before the connection succeeds. + + This property is useful for example if both IPv4 and IPv6 are enabled and are allowed to fail. Normally the connection succeeds as soon as one of the two address families completes; by setting a required timeout for e.g. IPv4, one can ensure that even if IP6 succeeds earlier than IPv4, NetworkManager waits some time for IPv4 before the connection becomes active. + + Note that if "may-fail" is FALSE for the same address family, this property has no effect as NetworkManager needs to wait for the full DHCP timeout. + + A zero value means that no required timeout is present, -1 means the default value (either configuration ipvx.required-timeout override or zero). The minimum time interval in milliseconds for which dynamic IP configuration should be tried before the connection succeeds. This property is useful for example if both IPv4 and IPv6 are enabled and are allowed to fail. Normally the connection succeeds as soon as one of the two address families completes; by setting a required timeout for e.g. IPv4, one can ensure that even if IP6 succeeds earlier than IPv4, NetworkManager waits some time for IPv4 before the connection becomes active. Note that if "may-fail" is FALSE for the same address family, this property has no effect as NetworkManager needs to wait for the full DHCP timeout. A zero value means that no required timeout is present, -1 means the default value (either configuration ipvx.required-timeout override or zero). The default metric for routes that don't explicitly specify a metric. The default value -1 means that the metric is chosen automatically based on the device type. The metric applies to dynamic routes, manual (static) routes that don't have an explicit metric setting, address prefix routes, and the default route. Note that for IPv6, the kernel accepts zero (0) but coerces it to 1024 (user default). Hence, setting this property to zero effectively mean setting it to 1024. For IPv4, zero is a regular value for the metric. The default metric for routes that don't explicitly specify a metric. The default value -1 means that the metric is chosen automatically based on the device type. The metric applies to dynamic routes, manual (static) routes that don't have an explicit metric setting, address prefix routes, and the default route. Note that for IPv6, the kernel accepts zero (0) but coerces it to 1024 (user default). Hence, setting this property to zero effectively mean setting it to 1024. For IPv4, zero is a regular value for the metric. Enable policy routing (source routing) and set the routing table used when adding routes. + + This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. + + If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. + + Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager. Enable policy routing (source routing) and set the routing table used when adding routes. This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager. Array of IP routes. Array of IP routes. Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0), NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64 (2) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT (3). + + If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. + + The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. + + The special values "default" and "default-or-eui64" will fallback to the global connection default in as documented in NetworkManager.conf(5) manual. If the global default is not specified, the fallback value is "stable-privacy" or "eui64", respectively. + + For libnm, the property defaults to "default" since 1.40. Previously it defaulted to "stable-privacy". On D-Bus, the absence of an addr-gen-mode setting equals "default". For keyfile plugin, the absence of the setting on disk means "default-or-eui64" so that the property doesn't change on upgrade from older versions. + + Note that this setting is distinct from the Privacy Extensions as configured by "ip6-privacy" property and it does not affect the temporary addresses configured with this option. Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0), NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64 (2) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT (3). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. The special values "default" and "default-or-eui64" will fallback to the global connection default in as documented in NetworkManager.conf(5) manual. If the global default is not specified, the fallback value is "stable-privacy" or "eui64", respectively. For libnm, the property defaults to "default" since 1.40. Previously it defaulted to "stable-privacy". On D-Bus, the absence of an addr-gen-mode setting equals "default". For keyfile plugin, the absence of the setting on disk means "default-or-eui64" so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by "ip6-privacy" property and it does not affect the temporary addresses configured with this option. Array of IP addresses. Array of IP addresses. Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. + + The property is currently implemented only for IPv4. Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4. A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. + + The special value "lease" will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and "dhclient" is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. + + The special values "llt" and "ll" will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. + + The special values "stable-llt", "stable-ll" and "stable-uuid" will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. You may want to include the "${DEVICE}" or "${MAC}" specifier in the stable-id, in case this profile gets activated on multiple devices. So, the link-layer address of "stable-ll" and "stable-llt" will be a generated address derived from the stable id. The DUID-LLT time value in the "stable-llt" option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in "llt"). + + When the property is unset, the global value provided for "ipv6.dhcp-duid" is used. If no global value is provided, the default "lease" value is assumed. A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value "lease" will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and "dhclient" is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values "llt" and "ll" will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values "stable-llt", "stable-ll" and "stable-uuid" will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. You may want to include the "${DEVICE}" or "${MAC}" specifier in the stable-id, in case this profile gets activated on multiple devices. So, the link-layer address of "stable-ll" and "stable-llt" will be a generated address derived from the stable id. The DUID-LLT time value in the "stable-llt" option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in "llt"). When the property is unset, the global value provided for "ipv6.dhcp-duid" is used. If no global value is provided, the default "lease" value is assumed. If the "dhcp-send-hostname" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and "dhcp-fqdn" are mutually exclusive and cannot be set at the same time. If the "dhcp-send-hostname" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and "dhcp-fqdn" are mutually exclusive and cannot be set at the same time. Flags for the DHCP hostname and FQDN. + + Currently, this property only includes flags to control the FQDN flags set in the DHCP FQDN option. Supported FQDN flags are NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) and NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE (0x4). When no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is set, the DHCP FQDN option will contain no flag. Otherwise, if no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is not set, the standard FQDN flags are set in the request: NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) for IPv4 and NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1) for IPv6. + + When this property is set to the default value NM_DHCP_HOSTNAME_FLAG_NONE (0x0), a global default is looked up in NetworkManager configuration. If that value is unset or also NM_DHCP_HOSTNAME_FLAG_NONE (0x0), then the standard FQDN flags described above are sent in the DHCP requests. Flags for the DHCP hostname and FQDN. Currently, this property only includes flags to control the FQDN flags set in the DHCP FQDN option. Supported FQDN flags are NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) and NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE (0x4). When no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is set, the DHCP FQDN option will contain no flag. Otherwise, if no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is not set, the standard FQDN flags are set in the request: NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) for IPv4 and NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1) for IPv6. When this property is set to the default value NM_DHCP_HOSTNAME_FLAG_NONE (0x0), a global default is looked up in NetworkManager configuration. If that value is unset or also NM_DHCP_HOSTNAME_FLAG_NONE (0x0), then the standard FQDN flags described above are sent in the DHCP requests. A string containing the "Identity Association Identifier" (IAID) used by the DHCP client. The property is a 32-bit decimal value or a special value among "mac", "perm-mac", "ifname" and "stable". When set to "mac" (or "perm-mac"), the last 4 bytes of the current (or permanent) MAC address are used as IAID. When set to "ifname", the IAID is computed by hashing the interface name. The special value "stable" can be used to generate an IAID based on the stable-id (see connection.stable-id), a per-host key and the interface name. When the property is unset, the value from global configuration is used; if no global default is set then the IAID is assumed to be "ifname". Note that at the moment this property is ignored for IPv6 by dhclient, which always derives the IAID from the MAC address. A string containing the "Identity Association Identifier" (IAID) used by the DHCP client. The property is a 32-bit decimal value or a special value among "mac", "perm-mac", "ifname" and "stable". When set to "mac" (or "perm-mac"), the last 4 bytes of the current (or permanent) MAC address are used as IAID. When set to "ifname", the IAID is computed by hashing the interface name. The special value "stable" can be used to generate an IAID based on the stable-id (see connection.stable-id), a per-host key and the interface name. When the property is unset, the value from global configuration is used; if no global default is set then the IAID is assumed to be "ifname". Note that at the moment this property is ignored for IPv6 by dhclient, which always derives the IAID from the MAC address. Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers. + + For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. "192.168.122.0/24"). + + This property is currently not implemented for DHCPv6. Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers. For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. "192.168.122.0/24"). This property is currently not implemented for DHCPv6. If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer. If the "dhcp-hostname" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent. If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer. If the "dhcp-hostname" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent. A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). + + Set to 2147483647 (MAXINT32) for infinity. A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). Set to 2147483647 (MAXINT32) for infinity. Array of IP addresses of DNS servers. Array of IP addresses of DNS servers. Array of DNS options as described in man 5 resolv.conf. + + NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. + + The currently supported options are "attempts", "debug", "edns0", "inet6", "ip6-bytestring", "ip6-dotint", "ndots", "no-check-names", "no-ip6-dotint", "no-reload", "no-tld-query", "rotate", "single-request", "single-request-reopen", "timeout", "trust-ad", "use-vc". + + The "trust-ad" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have "trust-ad" enabled. + + When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then "edns0" and "trust-ad" are automatically added. Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are "attempts", "debug", "edns0", "inet6", "ip6-bytestring", "ip6-dotint", "ndots", "no-check-names", "no-ip6-dotint", "no-reload", "no-tld-query", "rotate", "single-request", "single-request-reopen", "timeout", "trust-ad", "use-vc". The "trust-ad" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have "trust-ad" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then "edns0" and "trust-ad" are automatically added. DNS servers priority. + + The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). + + Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. + + Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. + + Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. + + When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. + + When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the "rotate" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. + + When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured. DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the "rotate" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured. List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. + + When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. + + When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting "ignore-auto-dns". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15). List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting "ignore-auto-dns". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15). The gateway associated with this configuration. This is only meaningful if "addresses" is also set. + + The gateway's main purpose is to control the next hop of the standard default route on the device. Hence, the gateway property conflicts with "never-default" and will be automatically dropped if the IP configuration is set to never-default. + + As an alternative to set the gateway, configure a static default route with /0 as prefix length. The gateway associated with this configuration. This is only meaningful if "addresses" is also set. The gateway's main purpose is to control the next hop of the standard default route on the device. Hence, the gateway property conflicts with "never-default" and will be automatically dropped if the IP configuration is set to never-default. As an alternative to set the gateway, configure a static default route with /0 as prefix length. When "method" is set to "auto" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the "dns" and "dns-search" properties, if any, are used. When "method" is set to "auto" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the "dns" and "dns-search" properties, if any, are used. When "method" is set to "auto" and this property to TRUE, automatically configured routes are ignored and only routes specified in the "routes" property, if any, are used. When "method" is set to "auto" and this property to TRUE, automatically configured routes are ignored and only routes specified in the "routes" property, if any, are used. Configure IPv6 Privacy Extensions for SLAAC, described in RFC4941. If enabled, it makes the kernel generate a temporary IPv6 address in addition to the public one generated from MAC address via modified EUI-64. This enhances privacy, but could cause problems in some applications, on the other hand. The permitted values are: -1: unknown, 0: disabled, 1: enabled (prefer public address), 2: enabled (prefer temporary addresses). + + Having a per-connection setting set to "-1" (unknown) means fallback to global configuration "ipv6.ip6-privacy". + + If also global configuration is unspecified or set to "-1", fallback to read "/proc/sys/net/ipv6/conf/default/use_tempaddr". + + Note that this setting is distinct from the Stable Privacy addresses that can be enabled with the "addr-gen-mode" property's "stable-privacy" setting as another way of avoiding host tracking with IPv6 addresses. Configure IPv6 Privacy Extensions for SLAAC, described in RFC4941. If enabled, it makes the kernel generate a temporary IPv6 address in addition to the public one generated from MAC address via modified EUI-64. This enhances privacy, but could cause problems in some applications, on the other hand. The permitted values are: -1: unknown, 0: disabled, 1: enabled (prefer public address), 2: enabled (prefer temporary addresses). Having a per-connection setting set to "-1" (unknown) means fallback to global configuration "ipv6.ip6-privacy". If also global configuration is unspecified or set to "-1", fallback to read "/proc/sys/net/ipv6/conf/default/use_tempaddr". Note that this setting is distinct from the Stable Privacy addresses that can be enabled with the "addr-gen-mode" property's "stable-privacy" setting as another way of avoiding host tracking with IPv6 addresses. If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out. Note that at least one IP configuration must succeed or overall network configuration will still fail. For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully. If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out. Note that at least one IP configuration must succeed or overall network configuration will still fail. For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully. IP configuration method. + + NMSettingIP4Config and NMSettingIP6Config both support "disabled", "auto", "manual", and "link-local". See the subclass-specific documentation for other values. + + In general, for the "auto" method, properties such as "dns" and "routes" specify information that is added on to the information returned from automatic configuration. The "ignore-auto-routes" and "ignore-auto-dns" properties modify this behavior. + + For methods that imply no upstream network, such as "shared" or "link-local", these properties must be empty. + + For IPv4 method "shared", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared. IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support "disabled", "auto", "manual", and "link-local". See the subclass-specific documentation for other values. In general, for the "auto" method, properties such as "dns" and "routes" specify information that is added on to the information returned from automatic configuration. The "ignore-auto-routes" and "ignore-auto-dns" properties modify this behavior. For methods that imply no upstream network, such as "shared" or "link-local", these properties must be empty. For IPv4 method "shared", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared. Maximum transmission unit size, in bytes. If zero (the default), the MTU is set automatically from router advertisements or is left equal to the link-layer MTU. If greater than the link-layer MTU, or greater than zero but less than the minimum IPv6 MTU of 1280, this value has no effect. Maximum transmission unit size, in bytes. If zero (the default), the MTU is set automatically from router advertisements or is left equal to the link-layer MTU. If greater than the link-layer MTU, or greater than zero but less than the minimum IPv6 MTU of 1280, this value has no effect. If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager. If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager. A timeout for waiting Router Advertisements in seconds. If zero (the default), a globally configured default is used. If still unspecified, the timeout depends on the sysctl settings of the device. + + Set to 2147483647 (MAXINT32) for infinity. A timeout for waiting Router Advertisements in seconds. If zero (the default), a globally configured default is used. If still unspecified, the timeout depends on the sysctl settings of the device. Set to 2147483647 (MAXINT32) for infinity. The minimum time interval in milliseconds for which dynamic IP configuration should be tried before the connection succeeds. + + This property is useful for example if both IPv4 and IPv6 are enabled and are allowed to fail. Normally the connection succeeds as soon as one of the two address families completes; by setting a required timeout for e.g. IPv4, one can ensure that even if IP6 succeeds earlier than IPv4, NetworkManager waits some time for IPv4 before the connection becomes active. + + Note that if "may-fail" is FALSE for the same address family, this property has no effect as NetworkManager needs to wait for the full DHCP timeout. + + A zero value means that no required timeout is present, -1 means the default value (either configuration ipvx.required-timeout override or zero). The minimum time interval in milliseconds for which dynamic IP configuration should be tried before the connection succeeds. This property is useful for example if both IPv4 and IPv6 are enabled and are allowed to fail. Normally the connection succeeds as soon as one of the two address families completes; by setting a required timeout for e.g. IPv4, one can ensure that even if IP6 succeeds earlier than IPv4, NetworkManager waits some time for IPv4 before the connection becomes active. Note that if "may-fail" is FALSE for the same address family, this property has no effect as NetworkManager needs to wait for the full DHCP timeout. A zero value means that no required timeout is present, -1 means the default value (either configuration ipvx.required-timeout override or zero). The default metric for routes that don't explicitly specify a metric. The default value -1 means that the metric is chosen automatically based on the device type. The metric applies to dynamic routes, manual (static) routes that don't have an explicit metric setting, address prefix routes, and the default route. Note that for IPv6, the kernel accepts zero (0) but coerces it to 1024 (user default). Hence, setting this property to zero effectively mean setting it to 1024. For IPv4, zero is a regular value for the metric. The default metric for routes that don't explicitly specify a metric. The default value -1 means that the metric is chosen automatically based on the device type. The metric applies to dynamic routes, manual (static) routes that don't have an explicit metric setting, address prefix routes, and the default route. Note that for IPv6, the kernel accepts zero (0) but coerces it to 1024 (user default). Hence, setting this property to zero effectively mean setting it to 1024. For IPv4, zero is a regular value for the metric. Enable policy routing (source routing) and set the routing table used when adding routes. + + This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. + + If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. + + Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager. Enable policy routing (source routing) and set the routing table used when adding routes. This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager. Array of IP routes. Array of IP routes. Configure the token for draft-chown-6man-tokenised-ipv6-identifiers-02 IPv6 tokenized interface identifiers. Useful with eui64 addr-gen-mode. Configure the token for draft-chown-6man-tokenised-ipv6-identifiers-02 IPv6 tokenized interface identifiers. Useful with eui64 addr-gen-mode. How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels. How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels. Tunnel flags. Currently, the following values are supported: NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS (0x2), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL (0x4), NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV (0x8), NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY (0x10), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK (0x20). They are valid only for IPv6 tunnels. Tunnel flags. Currently, the following values are supported: NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS (0x2), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL (0x4), NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV (0x8), NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY (0x10), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK (0x20). They are valid only for IPv6 tunnels. The flow label to assign to tunnel packets. This property applies only to IPv6 tunnels. The flow label to assign to tunnel packets. This property applies only to IPv6 tunnels. The key used for tunnel input packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used. The key used for tunnel input packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used. The local endpoint of the tunnel; the value can be empty, otherwise it must contain an IPv4 or IPv6 address. The local endpoint of the tunnel; the value can be empty, otherwise it must contain an IPv4 or IPv6 address. The tunneling mode, for example NM_IP_TUNNEL_MODE_IPIP (1) or NM_IP_TUNNEL_MODE_GRE (2). The tunneling mode, for example NM_IP_TUNNEL_MODE_IPIP (1) or NM_IP_TUNNEL_MODE_GRE (2). If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. The key used for tunnel output packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used. The key used for tunnel output packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used. If given, specifies the parent interface name or parent connection UUID the new device will be bound to so that tunneled packets will only be routed via that interface. If given, specifies the parent interface name or parent connection UUID the new device will be bound to so that tunneled packets will only be routed via that interface. Whether to enable Path MTU Discovery on this tunnel. Whether to enable Path MTU Discovery on this tunnel. The remote endpoint of the tunnel; the value must contain an IPv4 or IPv6 address. The remote endpoint of the tunnel; the value must contain an IPv4 or IPv6 address. The type of service (IPv4) or traffic class (IPv6) field to be set on tunneled packets. The type of service (IPv4) or traffic class (IPv6) field to be set on tunneled packets. The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value. The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value. Whether the transmitted traffic must be encrypted. Whether the transmitted traffic must be encrypted. The pre-shared CAK (Connectivity Association Key) for MACsec Key Agreement. The pre-shared CAK (Connectivity Association Key) for MACsec Key Agreement. Flags indicating how to handle the "mka-cak" property. Flags indicating how to handle the "mka-cak" property. The pre-shared CKN (Connectivity-association Key Name) for MACsec Key Agreement. The pre-shared CKN (Connectivity-association Key Name) for MACsec Key Agreement. Specifies how the CAK (Connectivity Association Key) for MKA (MACsec Key Agreement) is obtained. Specifies how the CAK (Connectivity Association Key) for MKA (MACsec Key Agreement) is obtained. If given, specifies the parent interface name or parent connection UUID from which this MACSEC interface should be created. If this property is not specified, the connection must contain an "802-3-ethernet" setting with a "mac-address" property. If given, specifies the parent interface name or parent connection UUID from which this MACSEC interface should be created. If this property is not specified, the connection must contain an "802-3-ethernet" setting with a "mac-address" property. The port component of the SCI (Secure Channel Identifier), between 1 and 65534. The port component of the SCI (Secure Channel Identifier), between 1 and 65534. Specifies whether the SCI (Secure Channel Identifier) is included in every packet. Specifies whether the SCI (Secure Channel Identifier) is included in every packet. Specifies the validation mode for incoming frames. Specifies the validation mode for incoming frames. The macvlan mode, which specifies the communication mechanism between multiple macvlans on the same lower device. The macvlan mode, which specifies the communication mechanism between multiple macvlans on the same lower device. If given, specifies the parent interface name or parent connection UUID from which this MAC-VLAN interface should be created. If this property is not specified, the connection must contain an "802-3-ethernet" setting with a "mac-address" property. If given, specifies the parent interface name or parent connection UUID from which this MAC-VLAN interface should be created. If this property is not specified, the connection must contain an "802-3-ethernet" setting with a "mac-address" property. Whether the interface should be put in promiscuous mode. Whether the interface should be put in promiscuous mode. Whether the interface should be a MACVTAP. Whether the interface should be a MACVTAP. A list of driver names to match. Each element is a shell wildcard pattern. + + See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern. A list of driver names to match. Each element is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern. A list of interface names to match. Each element is a shell wildcard pattern. + + An element can be prefixed with a pipe symbol (|) or an ampersand (&). The former means that the element is optional and the latter means that it is mandatory. If there are any optional elements, than the match evaluates to true if at least one of the optional element matches (logical OR). If there are any mandatory elements, then they all must match (logical AND). By default, an element is optional. This means that an element "foo" behaves the same as "|foo". An element can also be inverted with exclamation mark (!) between the pipe symbol (or the ampersand) and before the pattern. Note that "!foo" is a shortcut for the mandatory match "&!foo". Finally, a backslash can be used at the beginning of the element (after the optional special characters) to escape the start of the pattern. For example, "&\\!a" is an mandatory match for literally "!a". A list of interface names to match. Each element is a shell wildcard pattern. An element can be prefixed with a pipe symbol (|) or an ampersand (&). The former means that the element is optional and the latter means that it is mandatory. If there are any optional elements, than the match evaluates to true if at least one of the optional element matches (logical OR). If there are any mandatory elements, then they all must match (logical AND). By default, an element is optional. This means that an element "foo" behaves the same as "|foo". An element can also be inverted with exclamation mark (!) between the pipe symbol (or the ampersand) and before the pattern. Note that "!foo" is a shortcut for the mandatory match "&!foo". Finally, a backslash can be used at the beginning of the element (after the optional special characters) to escape the start of the pattern. For example, "&\\!a" is an mandatory match for literally "!a". A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or unset, if prefixed with the exclamation mark). The argument must either be a single word, or an assignment (i.e. two words, joined by "="). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching. Wildcard patterns are not supported. + + See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the match. A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or unset, if prefixed with the exclamation mark). The argument must either be a single word, or an assignment (i.e. two words, joined by "="). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching. Wildcard patterns are not supported. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the match. A list of paths to match against the ID_PATH udev property of devices. ID_PATH represents the topological persistent path of a device. It typically contains a subsystem string (pci, usb, platform, etc.) and a subsystem-specific identifier. + + For PCI devices the path has the form "pci-$domain:$bus:$device.$function", where each variable is an hexadecimal value; for example "pci-0000:0a:00.0". + + The path of a device can be obtained with "udevadm info /sys/class/net/$dev | grep ID_PATH=" or by looking at the "path" property exported by NetworkManager ("nmcli -f general.path device show $dev"). + + Each element of the list is a shell wildcard pattern. + + See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern. A list of paths to match against the ID_PATH udev property of devices. ID_PATH represents the topological persistent path of a device. It typically contains a subsystem string (pci, usb, platform, etc.) and a subsystem-specific identifier. For PCI devices the path has the form "pci-$domain:$bus:$device.$function", where each variable is an hexadecimal value; for example "pci-0000:0a:00.0". The path of a device can be obtained with "udevadm info /sys/class/net/$dev | grep ID_PATH=" or by looking at the "path" property exported by NetworkManager ("nmcli -f general.path device show $dev"). Each element of the list is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern. Channel on which the mesh network to join is located. Channel on which the mesh network to join is located. Anycast DHCP MAC address used when requesting an IP address via DHCP. The specific anycast address used determines which DHCP server class answers the request. + + This is currently only implemented by dhclient DHCP plugin. Anycast DHCP MAC address used when requesting an IP address via DHCP. The specific anycast address used determines which DHCP server class answers the request. This is currently only implemented by dhclient DHCP plugin. SSID of the mesh network to join. SSID of the mesh network to join. The data path type. One of "system", "netdev" or empty. The data path type. One of "system", "netdev" or empty. The bridge failure mode. One of "secure", "standalone" or empty. The bridge failure mode. One of "secure", "standalone" or empty. Enable or disable multicast snooping. Enable or disable multicast snooping. Enable or disable RSTP. Enable or disable RSTP. Enable or disable STP. Enable or disable STP. Open vSwitch DPDK device arguments. Open vSwitch DPDK device arguments. Open vSwitch DPDK number of rx queues. Defaults to zero which means to leave the parameter in OVS unspecified and effectively configures one queue. Open vSwitch DPDK number of rx queues. Defaults to zero which means to leave the parameter in OVS unspecified and effectively configures one queue. A dictionary of key/value pairs with exernal-ids for OVS. A dictionary of key/value pairs with exernal-ids for OVS. The interface type. Either "internal", "system", "patch", "dpdk", or empty. The interface type. Either "internal", "system", "patch", "dpdk", or empty. Specifies the name of the interface for the other side of the patch. The patch on the other side must also set this interface as peer. Specifies the name of the interface for the other side of the patch. The patch on the other side must also set this interface as peer. The time port must be inactive in order to be considered down. The time port must be inactive in order to be considered down. Bonding mode. One of "active-backup", "balance-slb", or "balance-tcp". Bonding mode. One of "active-backup", "balance-slb", or "balance-tcp". The time port must be active before it starts forwarding traffic. The time port must be active before it starts forwarding traffic. LACP mode. One of "active", "off", or "passive". LACP mode. One of "active", "off", or "passive". The VLAN tag in the range 0-4095. The VLAN tag in the range 0-4095. The VLAN mode. One of "access", "native-tagged", "native-untagged", "trunk" or unset. The VLAN mode. One of "access", "native-tagged", "native-untagged", "trunk" or unset. If non-zero, instruct pppd to set the serial port to the specified baudrate. This value should normally be left as 0 to automatically choose the speed. If non-zero, instruct pppd to set the serial port to the specified baudrate. This value should normally be left as 0 to automatically choose the speed. If TRUE, specify that pppd should set the serial port to use hardware flow control with RTS and CTS signals. This value should normally be set to FALSE. If TRUE, specify that pppd should set the serial port to use hardware flow control with RTS and CTS signals. This value should normally be set to FALSE. If non-zero, instruct pppd to presume the connection to the peer has failed if the specified number of LCP echo-requests go unanswered by the peer. The "lcp-echo-interval" property must also be set to a non-zero value if this property is used. If non-zero, instruct pppd to presume the connection to the peer has failed if the specified number of LCP echo-requests go unanswered by the peer. The "lcp-echo-interval" property must also be set to a non-zero value if this property is used. If non-zero, instruct pppd to send an LCP echo-request frame to the peer every n seconds (where n is the specified value). Note that some PPP peers will respond to echo requests and some will not, and it is not possible to autodetect this. If non-zero, instruct pppd to send an LCP echo-request frame to the peer every n seconds (where n is the specified value). Note that some PPP peers will respond to echo requests and some will not, and it is not possible to autodetect this. If TRUE, stateful MPPE is used. See pppd documentation for more information on stateful MPPE. If TRUE, stateful MPPE is used. See pppd documentation for more information on stateful MPPE. If non-zero, instruct pppd to request that the peer send packets no larger than the specified size. If non-zero, the MRU should be between 128 and 16384. If non-zero, instruct pppd to request that the peer send packets no larger than the specified size. If non-zero, the MRU should be between 128 and 16384. If non-zero, instruct pppd to send packets no larger than the specified size. If non-zero, instruct pppd to send packets no larger than the specified size. If TRUE, Van Jacobsen TCP header compression will not be requested. If TRUE, Van Jacobsen TCP header compression will not be requested. If TRUE, do not require the other side (usually the PPP server) to authenticate itself to the client. If FALSE, require authentication from the remote side. In almost all cases, this should be TRUE. If TRUE, do not require the other side (usually the PPP server) to authenticate itself to the client. If FALSE, require authentication from the remote side. In almost all cases, this should be TRUE. If TRUE, BSD compression will not be requested. If TRUE, BSD compression will not be requested. If TRUE, "deflate" compression will not be requested. If TRUE, "deflate" compression will not be requested. If TRUE, the CHAP authentication method will not be used. If TRUE, the CHAP authentication method will not be used. If TRUE, the EAP authentication method will not be used. If TRUE, the EAP authentication method will not be used. If TRUE, the MSCHAP authentication method will not be used. If TRUE, the MSCHAP authentication method will not be used. If TRUE, the MSCHAPv2 authentication method will not be used. If TRUE, the MSCHAPv2 authentication method will not be used. If TRUE, the PAP authentication method will not be used. If TRUE, the PAP authentication method will not be used. If TRUE, MPPE (Microsoft Point-to-Point Encryption) will be required for the PPP session. If either 64-bit or 128-bit MPPE is not available the session will fail. Note that MPPE is not used on mobile broadband connections. If TRUE, MPPE (Microsoft Point-to-Point Encryption) will be required for the PPP session. If either 64-bit or 128-bit MPPE is not available the session will fail. Note that MPPE is not used on mobile broadband connections. If TRUE, 128-bit MPPE (Microsoft Point-to-Point Encryption) will be required for the PPP session, and the "require-mppe" property must also be set to TRUE. If 128-bit MPPE is not available the session will fail. If TRUE, 128-bit MPPE (Microsoft Point-to-Point Encryption) will be required for the PPP session, and the "require-mppe" property must also be set to TRUE. If 128-bit MPPE is not available the session will fail. If given, specifies the parent interface name on which this PPPoE connection should be created. If this property is not specified, the connection is activated on the interface specified in "interface-name" of NMSettingConnection. If given, specifies the parent interface name on which this PPPoE connection should be created. If this property is not specified, the connection is activated on the interface specified in "interface-name" of NMSettingConnection. Password used to authenticate with the PPPoE service. Password used to authenticate with the PPPoE service. Flags indicating how to handle the "password" property. Flags indicating how to handle the "password" property. If specified, instruct PPPoE to only initiate sessions with access concentrators that provide the specified service. For most providers, this should be left blank. It is only required if there are multiple access concentrators or a specific service is known to be required. If specified, instruct PPPoE to only initiate sessions with access concentrators that provide the specified service. For most providers, this should be left blank. It is only required if there are multiple access concentrators or a specific service is known to be required. Username used to authenticate with the PPPoE service. Username used to authenticate with the PPPoE service. Whether the proxy configuration is for browser only. Whether the proxy configuration is for browser only. Method for proxy configuration, Default is NM_SETTING_PROXY_METHOD_NONE (0) Method for proxy configuration, Default is NM_SETTING_PROXY_METHOD_NONE (0) PAC script for the connection. This is an UTF-8 encoded javascript code that defines a FindProxyForURL() function. PAC script for the connection. This is an UTF-8 encoded javascript code that defines a FindProxyForURL() function. PAC URL for obtaining PAC file. PAC URL for obtaining PAC file. Speed to use for communication over the serial port. Note that this value usually has no effect for mobile broadband modems as they generally ignore speed settings and use the highest available speed. Speed to use for communication over the serial port. Note that this value usually has no effect for mobile broadband modems as they generally ignore speed settings and use the highest available speed. Byte-width of the serial communication. The 8 in "8n1" for example. Byte-width of the serial communication. The 8 in "8n1" for example. Parity setting of the serial port. Parity setting of the serial port. Time to delay between each byte sent to the modem, in microseconds. Time to delay between each byte sent to the modem, in microseconds. Number of stop bits for communication on the serial port. Either 1 or 2. The 1 in "8n1" for example. Number of stop bits for communication on the serial port. Either 1 or 2. The 1 in "8n1" for example. Whether to autoprobe virtual functions by a compatible driver. + + If set to NM_TERNARY_TRUE (1), the kernel will try to bind VFs to a compatible driver and if this succeeds a new network interface will be instantiated for each VF. + + If set to NM_TERNARY_FALSE (0), VFs will not be claimed and no network interfaces will be created for them. + + When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_TRUE (1). Whether to autoprobe virtual functions by a compatible driver. If set to NM_TERNARY_TRUE (1), the kernel will try to bind VFs to a compatible driver and if this succeeds a new network interface will be instantiated for each VF. If set to NM_TERNARY_FALSE (0), VFs will not be claimed and no network interfaces will be created for them. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_TRUE (1). The total number of virtual functions to create. + + Note that when the sriov setting is present NetworkManager enforces the number of virtual functions on the interface (also when it is zero) during activation and resets it upon deactivation. To prevent any changes to SR-IOV parameters don't add a sriov setting to the connection. The total number of virtual functions to create. Note that when the sriov setting is present NetworkManager enforces the number of virtual functions on the interface (also when it is zero) during activation and resets it upon deactivation. To prevent any changes to SR-IOV parameters don't add a sriov setting to the connection. Array of virtual function descriptors. + + Each VF descriptor is a dictionary mapping attribute names to GVariant values. The 'index' entry is mandatory for each VF. + + When represented as string a VF is in the form: + + "INDEX [ATTR=VALUE[ ATTR=VALUE]...]". + + for example: + + "2 mac=00:11:22:33:44:55 spoof-check=true". + + Multiple VFs can be specified using a comma as separator. Currently, the following attributes are supported: mac, spoof-check, trust, min-tx-rate, max-tx-rate, vlans. + + The "vlans" attribute is represented as a semicolon-separated list of VLAN descriptors, where each descriptor has the form + + "ID[.PRIORITY[.PROTO]]". + + PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad. Array of virtual function descriptors. Each VF descriptor is a dictionary mapping attribute names to GVariant values. The 'index' entry is mandatory for each VF. When represented as string a VF is in the form: "INDEX [ATTR=VALUE[ ATTR=VALUE]...]". for example: "2 mac=00:11:22:33:44:55 spoof-check=true". Multiple VFs can be specified using a comma as separator. Currently, the following attributes are supported: mac, spoof-check, trust, min-tx-rate, max-tx-rate, vlans. The "vlans" attribute is represented as a semicolon-separated list of VLAN descriptors, where each descriptor has the form "ID[.PRIORITY[.PROTO]]". PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad. Array of TC queueing disciplines. + + When the "tc" setting is present, qdiscs from this property are applied upon activation. If the property is empty, all qdiscs are removed and the device will only have the default qdisc assigned by kernel according to the "net.core.default_qdisc" sysctl. + + If the "tc" setting is not present, NetworkManager doesn't touch the qdiscs present on the interface. Array of TC queueing disciplines. When the "tc" setting is present, qdiscs from this property are applied upon activation. If the property is empty, all qdiscs are removed and the device will only have the default qdisc assigned by kernel according to the "net.core.default_qdisc" sysctl. If the "tc" setting is not present, NetworkManager doesn't touch the qdiscs present on the interface. Array of TC traffic filters. + + When the "tc" setting is present, filters from this property are applied upon activation. If the property is empty, NetworkManager removes all the filters. + + If the "tc" setting is not present, NetworkManager doesn't touch the filters present on the interface. Array of TC traffic filters. When the "tc" setting is present, filters from this property are applied upon activation. If the property is empty, NetworkManager removes all the filters. If the "tc" setting is not present, NetworkManager doesn't touch the filters present on the interface. The JSON configuration for the team network interface. The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used. See man teamd.conf for the format details. The JSON configuration for the team network interface. The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used. See man teamd.conf for the format details. Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are: ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-inactive', 'send-always'. See teamd.conf man for more details. Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are: ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-inactive', 'send-always'. See teamd.conf man for more details. Corresponds to the teamd mcast_rejoin.count. Corresponds to the teamd mcast_rejoin.count. Corresponds to the teamd mcast_rejoin.interval. Corresponds to the teamd mcast_rejoin.interval. Corresponds to the teamd notify_peers.count. Corresponds to the teamd notify_peers.count. Corresponds to the teamd notify_peers.interval. Corresponds to the teamd notify_peers.interval. Corresponds to the teamd runner.name. Permitted values are: "roundrobin", "broadcast", "activebackup", "loadbalance", "lacp", "random". Corresponds to the teamd runner.name. Permitted values are: "roundrobin", "broadcast", "activebackup", "loadbalance", "lacp", "random". Corresponds to the teamd runner.active. Corresponds to the teamd runner.active. Corresponds to the teamd runner.agg_select_policy. Corresponds to the teamd runner.agg_select_policy. Corresponds to the teamd runner.fast_rate. Corresponds to the teamd runner.fast_rate. Corresponds to the teamd runner.hwaddr_policy. Corresponds to the teamd runner.hwaddr_policy. Corresponds to the teamd runner.min_ports. Corresponds to the teamd runner.min_ports. Corresponds to the teamd runner.sys_prio. Corresponds to the teamd runner.sys_prio. Corresponds to the teamd runner.tx_balancer.name. Corresponds to the teamd runner.tx_balancer.name. Corresponds to the teamd runner.tx_balancer.interval. Corresponds to the teamd runner.tx_balancer.interval. Corresponds to the teamd runner.tx_hash. Corresponds to the teamd runner.tx_hash. The JSON configuration for the team port. The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used. See man teamd.conf for the format details. The JSON configuration for the team port. The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used. See man teamd.conf for the format details. Corresponds to the teamd ports.PORTIFNAME.lacp_key. Corresponds to the teamd ports.PORTIFNAME.lacp_key. Corresponds to the teamd ports.PORTIFNAME.lacp_prio. Corresponds to the teamd ports.PORTIFNAME.lacp_prio. Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are: ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-inactive', 'send-always'. See teamd.conf man for more details. Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are: ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-inactive', 'send-always'. See teamd.conf man for more details. Corresponds to the teamd ports.PORTIFNAME.prio. Corresponds to the teamd ports.PORTIFNAME.prio. Corresponds to the teamd ports.PORTIFNAME.queue_id. When set to -1 means the parameter is skipped from the json config. Corresponds to the teamd ports.PORTIFNAME.queue_id. When set to -1 means the parameter is skipped from the json config. Corresponds to the teamd ports.PORTIFNAME.sticky. Corresponds to the teamd ports.PORTIFNAME.sticky. The group ID which will own the device. If set to NULL everyone will be able to use the device. The group ID which will own the device. If set to NULL everyone will be able to use the device. The operating mode of the virtual device. Allowed values are NM_SETTING_TUN_MODE_TUN (1) to create a layer 3 device and NM_SETTING_TUN_MODE_TAP (2) to create an Ethernet-like layer 2 one. The operating mode of the virtual device. Allowed values are NM_SETTING_TUN_MODE_TUN (1) to create a layer 3 device and NM_SETTING_TUN_MODE_TAP (2) to create an Ethernet-like layer 2 one. If the property is set to TRUE, the interface will support multiple file descriptors (queues) to parallelize packet sending or receiving. Otherwise, the interface will only support a single queue. If the property is set to TRUE, the interface will support multiple file descriptors (queues) to parallelize packet sending or receiving. Otherwise, the interface will only support a single queue. The user ID which will own the device. If set to NULL everyone will be able to use the device. The user ID which will own the device. If set to NULL everyone will be able to use the device. If TRUE the interface will prepend a 4 byte header describing the physical interface to the packets. If TRUE the interface will prepend a 4 byte header describing the physical interface to the packets. If TRUE the IFF_VNET_HDR the tunnel packets will include a virtio network header. If TRUE the IFF_VNET_HDR the tunnel packets will include a virtio network header. A dictionary of key/value pairs with user data. This data is ignored by NetworkManager and can be used at the users discretion. The keys only support a strict ascii format, but the values can be arbitrary UTF8 strings up to a certain length. A dictionary of key/value pairs with user data. This data is ignored by NetworkManager and can be used at the users discretion. The keys only support a strict ascii format, but the values can be arbitrary UTF8 strings up to a certain length. This property specifies the peer interface name of the veth. This property is mandatory. This property specifies the peer interface name of the veth. This property is mandatory. For outgoing packets, a list of mappings from Linux SKB priorities to 802.1p priorities. The mapping is given in the format "from:to" where both "from" and "to" are unsigned integers, ie "7:3". For outgoing packets, a list of mappings from Linux SKB priorities to 802.1p priorities. The mapping is given in the format "from:to" where both "from" and "to" are unsigned integers, ie "7:3". One or more flags which control the behavior and features of the VLAN interface. Flags include NM_VLAN_FLAG_REORDER_HEADERS (0x1) (reordering of output packet headers), NM_VLAN_FLAG_GVRP (0x2) (use of the GVRP protocol), and NM_VLAN_FLAG_LOOSE_BINDING (0x4) (loose binding of the interface to its master device's operating state). NM_VLAN_FLAG_MVRP (0x8) (use of the MVRP protocol). + + The default value of this property is NM_VLAN_FLAG_REORDER_HEADERS, but it used to be 0. To preserve backward compatibility, the default-value in the D-Bus API continues to be 0 and a missing property on D-Bus is still considered as 0. One or more flags which control the behavior and features of the VLAN interface. Flags include NM_VLAN_FLAG_REORDER_HEADERS (0x1) (reordering of output packet headers), NM_VLAN_FLAG_GVRP (0x2) (use of the GVRP protocol), and NM_VLAN_FLAG_LOOSE_BINDING (0x4) (loose binding of the interface to its master device's operating state). NM_VLAN_FLAG_MVRP (0x8) (use of the MVRP protocol). The default value of this property is NM_VLAN_FLAG_REORDER_HEADERS, but it used to be 0. To preserve backward compatibility, the default-value in the D-Bus API continues to be 0 and a missing property on D-Bus is still considered as 0. The VLAN identifier that the interface created by this connection should be assigned. The valid range is from 0 to 4094, without the reserved id 4095. The VLAN identifier that the interface created by this connection should be assigned. The valid range is from 0 to 4094, without the reserved id 4095. For incoming packets, a list of mappings from 802.1p priorities to Linux SKB priorities. The mapping is given in the format "from:to" where both "from" and "to" are unsigned integers, ie "7:3". For incoming packets, a list of mappings from 802.1p priorities to Linux SKB priorities. The mapping is given in the format "from:to" where both "from" and "to" are unsigned integers, ie "7:3". If given, specifies the parent interface name or parent connection UUID from which this VLAN interface should be created. If this property is not specified, the connection must contain an "802-3-ethernet" setting with a "mac-address" property. If given, specifies the parent interface name or parent connection UUID from which this VLAN interface should be created. If this property is not specified, the connection must contain an "802-3-ethernet" setting with a "mac-address" property. Dictionary of key/value pairs of VPN plugin specific data. Both keys and values must be strings. Dictionary of key/value pairs of VPN plugin specific data. Both keys and values must be strings. If the VPN service supports persistence, and this property is TRUE, the VPN will attempt to stay connected across link changes and outages, until explicitly disconnected. If the VPN service supports persistence, and this property is TRUE, the VPN will attempt to stay connected across link changes and outages, until explicitly disconnected. Dictionary of key/value pairs of VPN plugin specific secrets like passwords or private keys. Both keys and values must be strings. Dictionary of key/value pairs of VPN plugin specific secrets like passwords or private keys. Both keys and values must be strings. D-Bus service name of the VPN plugin that this setting uses to connect to its network. i.e. org.freedesktop.NetworkManager.vpnc for the vpnc plugin. D-Bus service name of the VPN plugin that this setting uses to connect to its network. i.e. org.freedesktop.NetworkManager.vpnc for the vpnc plugin. Timeout for the VPN service to establish the connection. Some services may take quite a long time to connect. Value of 0 means a default timeout, which is 60 seconds (unless overridden by vpn.timeout in configuration file). Values greater than zero mean timeout in seconds. Timeout for the VPN service to establish the connection. Some services may take quite a long time to connect. Value of 0 means a default timeout, which is 60 seconds (unless overridden by vpn.timeout in configuration file). Values greater than zero mean timeout in seconds. If the VPN connection requires a user name for authentication, that name should be provided here. If the connection is available to more than one user, and the VPN requires each user to supply a different name, then leave this property empty. If this property is empty, NetworkManager will automatically supply the username of the user which requested the VPN connection. If the VPN connection requires a user name for authentication, that name should be provided here. If the connection is available to more than one user, and the VPN requires each user to supply a different name, then leave this property empty. If this property is empty, NetworkManager will automatically supply the username of the user which requested the VPN connection. The routing table for this VRF. The routing table for this VRF. Specifies the lifetime in seconds of FDB entries learnt by the kernel. Specifies the lifetime in seconds of FDB entries learnt by the kernel. Specifies the UDP destination port to communicate to the remote VXLAN tunnel endpoint. Specifies the UDP destination port to communicate to the remote VXLAN tunnel endpoint. Specifies the VXLAN Network Identifier (or VXLAN Segment Identifier) to use. Specifies the VXLAN Network Identifier (or VXLAN Segment Identifier) to use. Specifies whether netlink LL ADDR miss notifications are generated. Specifies whether netlink LL ADDR miss notifications are generated. Specifies whether netlink IP ADDR miss notifications are generated. Specifies whether netlink IP ADDR miss notifications are generated. Specifies whether unknown source link layer addresses and IP addresses are entered into the VXLAN device forwarding database. Specifies whether unknown source link layer addresses and IP addresses are entered into the VXLAN device forwarding database. Specifies the maximum number of FDB entries. A value of zero means that the kernel will store unlimited entries. Specifies the maximum number of FDB entries. A value of zero means that the kernel will store unlimited entries. If given, specifies the source IP address to use in outgoing packets. If given, specifies the source IP address to use in outgoing packets. If given, specifies the parent interface name or parent connection UUID. If given, specifies the parent interface name or parent connection UUID. Specifies whether ARP proxy is turned on. Specifies whether ARP proxy is turned on. Specifies the unicast destination IP address to use in outgoing packets when the destination link layer address is not known in the VXLAN device forwarding database, or the multicast IP address to join. Specifies the unicast destination IP address to use in outgoing packets when the destination link layer address is not known in the VXLAN device forwarding database, or the multicast IP address to join. Specifies whether route short circuit is turned on. Specifies whether route short circuit is turned on. Specifies the maximum UDP source port to communicate to the remote VXLAN tunnel endpoint. Specifies the maximum UDP source port to communicate to the remote VXLAN tunnel endpoint. Specifies the minimum UDP source port to communicate to the remote VXLAN tunnel endpoint. Specifies the minimum UDP source port to communicate to the remote VXLAN tunnel endpoint. Specifies the TOS value to use in outgoing packets. Specifies the TOS value to use in outgoing packets. Specifies the time-to-live value to use in outgoing packets. Specifies the time-to-live value to use in outgoing packets. The P2P device that should be connected to. Currently, this is the only way to create or join a group. The P2P device that should be connected to. Currently, this is the only way to create or join a group. The Wi-Fi Display (WFD) Information Elements (IEs) to set. + + Wi-Fi Display requires a protocol specific information element to be set in certain Wi-Fi frames. These can be specified here for the purpose of establishing a connection. This setting is only useful when implementing a Wi-Fi Display client. The Wi-Fi Display (WFD) Information Elements (IEs) to set. Wi-Fi Display requires a protocol specific information element to be set in certain Wi-Fi frames. These can be specified here for the purpose of establishing a connection. This setting is only useful when implementing a Wi-Fi Display client. Flags indicating which mode of WPS is to be used. + + There's little point in changing the default setting as NetworkManager will automatically determine the best method to use. Flags indicating which mode of WPS is to be used. There's little point in changing the default setting as NetworkManager will automatically determine the best method to use. If specified, this connection will only apply to the WiMAX device whose MAC address matches. This property does not change the MAC address of the device (known as MAC spoofing). Deprecated: 1 If specified, this connection will only apply to the WiMAX device whose MAC address matches. This property does not change the MAC address of the device (known as MAC spoofing). Deprecated: 1 Network Service Provider (NSP) name of the WiMAX network this connection should use. Deprecated: 1 Network Service Provider (NSP) name of the WiMAX network this connection should use. Deprecated: 1 When TRUE, setup the interface to accept packets for all MAC addresses. This is enabling the kernel interface flag IFF_PROMISC. When FALSE, the interface will only accept the packets with the interface destination mac address or broadcast. When TRUE, setup the interface to accept packets for all MAC addresses. This is enabling the kernel interface flag IFF_PROMISC. When FALSE, the interface will only accept the packets with the interface destination mac address or broadcast. When TRUE, enforce auto-negotiation of speed and duplex mode. If "speed" and "duplex" properties are both specified, only that single mode will be advertised and accepted during the link auto-negotiation process: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. When FALSE, "speed" and "duplex" properties should be both set or link configuration will be skipped. When TRUE, enforce auto-negotiation of speed and duplex mode. If "speed" and "duplex" properties are both specified, only that single mode will be advertised and accepted during the link auto-negotiation process: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. When FALSE, "speed" and "duplex" properties should be both set or link configuration will be skipped. If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. + + Beside explicitly specifying a MAC address, the special values "preserve", "permanent", "random" and "stable" are supported. "preserve" means not to touch the MAC address on activation. "permanent" means to use the permanent hardware address if the device has one (otherwise this is treated as "preserve"). "random" creates a random MAC address on each connect. "stable" creates a hashed MAC address based on connection.stable-id and a machine dependent key. + + If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to "preserve" (older versions of NetworkManager may use a different default value). + + On D-Bus, this field is expressed as "assigned-mac-address" or the deprecated "cloned-mac-address". If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. Beside explicitly specifying a MAC address, the special values "preserve", "permanent", "random" and "stable" are supported. "preserve" means not to touch the MAC address on activation. "permanent" means to use the permanent hardware address if the device has one (otherwise this is treated as "preserve"). "random" creates a random MAC address on each connect. "stable" creates a hashed MAC address based on connection.stable-id and a machine dependent key. If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to "preserve" (older versions of NetworkManager may use a different default value). On D-Bus, this field is expressed as "assigned-mac-address" or the deprecated "cloned-mac-address". When a value is set, either "half" or "full", configures the device to use the specified duplex mode. If "auto-negotiate" is "yes" the specified duplex mode will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. If the value is unset (the default), the link configuration will be either skipped (if "auto-negotiate" is "no", the default) or will be auto-negotiated (if "auto-negotiate" is "yes") and the local device will advertise all the supported duplex modes. Must be set together with the "speed" property if specified. Before specifying a duplex mode be sure your device supports it. When a value is set, either "half" or "full", configures the device to use the specified duplex mode. If "auto-negotiate" is "yes" the specified duplex mode will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. If the value is unset (the default), the link configuration will be either skipped (if "auto-negotiate" is "no", the default) or will be auto-negotiated (if "auto-negotiate" is "yes") and the local device will advertise all the supported duplex modes. Must be set together with the "speed" property if specified. Before specifying a duplex mode be sure your device supports it. With "cloned-mac-address" setting "random" or "stable", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. + + If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. + + If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting "FE:FF:FF:00:00:00" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the "random" or "stable" algorithm. + + If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of "FE:FF:FF:00:00:00 68:F7:28:00:00:00" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of "02:00:00:00:00:00 00:00:00:00:00:00" will create a fully scrambled globally-administered, burned-in MAC address. + + If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, "02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00" will create a fully scrambled MAC address, randomly locally or globally administered. With "cloned-mac-address" setting "random" or "stable", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting "FE:FF:FF:00:00:00" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the "random" or "stable" algorithm. If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of "FE:FF:FF:00:00:00 68:F7:28:00:00:00" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of "02:00:00:00:00:00 00:00:00:00:00:00" will create a fully scrambled globally-administered, burned-in MAC address. If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, "02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00" will create a fully scrambled MAC address, randomly locally or globally administered. If specified, this connection will only apply to the Ethernet device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing). If specified, this connection will only apply to the Ethernet device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing). If specified, this connection will never apply to the Ethernet device whose permanent MAC address matches an address in the list. Each MAC address is in the standard hex-digits-and-colons notation (00:11:22:33:44:55). If specified, this connection will never apply to the Ethernet device whose permanent MAC address matches an address in the list. Each MAC address is in the standard hex-digits-and-colons notation (00:11:22:33:44:55). If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames. Specific port type to use if the device supports multiple attachment methods. One of "tp" (Twisted Pair), "aui" (Attachment Unit Interface), "bnc" (Thin Ethernet) or "mii" (Media Independent Interface). If the device supports only one port type, this setting is ignored. Specific port type to use if the device supports multiple attachment methods. One of "tp" (Twisted Pair), "aui" (Attachment Unit Interface), "bnc" (Thin Ethernet) or "mii" (Media Independent Interface). If the device supports only one port type, this setting is ignored. s390 network device type; one of "qeth", "lcs", or "ctc", representing the different types of virtual network devices available on s390 systems. s390 network device type; one of "qeth", "lcs", or "ctc", representing the different types of virtual network devices available on s390 systems. Dictionary of key/value pairs of s390-specific device options. Both keys and values must be strings. Allowed keys include "portno", "layer2", "portname", "protocol", among others. Key names must contain only alphanumeric characters (ie, [a-zA-Z0-9]). + + Currently, NetworkManager itself does nothing with this information. However, s390utils ships a udev rule which parses this information and applies it to the interface. Dictionary of key/value pairs of s390-specific device options. Both keys and values must be strings. Allowed keys include "portno", "layer2", "portname", "protocol", among others. Key names must contain only alphanumeric characters (ie, [a-zA-Z0-9]). Currently, NetworkManager itself does nothing with this information. However, s390utils ships a udev rule which parses this information and applies it to the interface. Identifies specific subchannels that this network device uses for communication with z/VM or s390 host. Like the "mac-address" property for non-z/VM devices, this property can be used to ensure this connection only applies to the network device that uses these subchannels. The list should contain exactly 3 strings, and each string may only be composed of hexadecimal characters and the period (.) character. Identifies specific subchannels that this network device uses for communication with z/VM or s390 host. Like the "mac-address" property for non-z/VM devices, this property can be used to ensure this connection only applies to the network device that uses these subchannels. The list should contain exactly 3 strings, and each string may only be composed of hexadecimal characters and the period (.) character. When a value greater than 0 is set, configures the device to use the specified speed. If "auto-negotiate" is "yes" the specified speed will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabit speeds, as in this case link negotiation is mandatory. If the value is unset (0, the default), the link configuration will be either skipped (if "auto-negotiate" is "no", the default) or will be auto-negotiated (if "auto-negotiate" is "yes") and the local device will advertise all the supported speeds. In Mbit/s, ie 100 == 100Mbit/s. Must be set together with the "duplex" property when non-zero. Before specifying a speed value be sure your device supports it. When a value greater than 0 is set, configures the device to use the specified speed. If "auto-negotiate" is "yes" the specified speed will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabit speeds, as in this case link negotiation is mandatory. If the value is unset (0, the default), the link configuration will be either skipped (if "auto-negotiate" is "no", the default) or will be auto-negotiated (if "auto-negotiate" is "yes") and the local device will advertise all the supported speeds. In Mbit/s, ie 100 == 100Mbit/s. Must be set together with the "duplex" property when non-zero. Before specifying a speed value be sure your device supports it. The NMSettingWiredWakeOnLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRED_WAKE_ON_LAN_PHY (0x2), NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST (0x4), NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST (0x8), NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST (0x10), NM_SETTING_WIRED_WAKE_ON_LAN_ARP (0x20), NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC (0x40) or the special values NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager). The NMSettingWiredWakeOnLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRED_WAKE_ON_LAN_PHY (0x2), NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST (0x4), NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST (0x8), NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST (0x10), NM_SETTING_WIRED_WAKE_ON_LAN_ARP (0x20), NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC (0x40) or the special values NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager). If specified, the password used with magic-packet-based Wake-on-LAN, represented as an Ethernet MAC address. If NULL, no password will be required. If specified, the password used with magic-packet-based Wake-on-LAN, represented as an Ethernet MAC address. If NULL, no password will be required. The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise, it is a 32-bit fwmark for outgoing packets. + + Note that "ip4-auto-default-route" or "ip6-auto-default-route" enabled, implies to automatically choose a fwmark. The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise, it is a 32-bit fwmark for outgoing packets. Note that "ip4-auto-default-route" or "ip6-auto-default-route" enabled, implies to automatically choose a fwmark. Whether to enable special handling of the IPv4 default route. If enabled, the IPv4 default route from wireguard.peer-routes will be placed to a dedicated routing-table and two policy routing rules will be added. The fwmark number is also used as routing-table for the default-route, and if fwmark is zero, an unused fwmark/table is chosen automatically. This corresponds to what wg-quick does with Table=auto and what WireGuard calls "Improved Rule-based Routing". + + Note that for this automatism to work, you usually don't want to set ipv4.gateway, because that will result in a conflicting default route. + + Leaving this at the default will enable this option automatically if ipv4.never-default is not set and there are any peers that use a default-route as allowed-ips. Since this automatism only makes sense if you also have a peer with an /0 allowed-ips, it is usually not necessary to enable this explicitly. However, you can disable it if you want to configure your own routing and rules. Whether to enable special handling of the IPv4 default route. If enabled, the IPv4 default route from wireguard.peer-routes will be placed to a dedicated routing-table and two policy routing rules will be added. The fwmark number is also used as routing-table for the default-route, and if fwmark is zero, an unused fwmark/table is chosen automatically. This corresponds to what wg-quick does with Table=auto and what WireGuard calls "Improved Rule-based Routing". Note that for this automatism to work, you usually don't want to set ipv4.gateway, because that will result in a conflicting default route. Leaving this at the default will enable this option automatically if ipv4.never-default is not set and there are any peers that use a default-route as allowed-ips. Since this automatism only makes sense if you also have a peer with an /0 allowed-ips, it is usually not necessary to enable this explicitly. However, you can disable it if you want to configure your own routing and rules. Like ip4-auto-default-route, but for the IPv6 default route. Like ip4-auto-default-route, but for the IPv6 default route. The listen-port. If listen-port is not specified, the port will be chosen randomly when the interface comes up. The listen-port. If listen-port is not specified, the port will be chosen randomly when the interface comes up. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. + + If zero a default MTU is used. Note that contrary to wg-quick's MTU setting, this does not take into account the current routes at the time of activation. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. If zero a default MTU is used. Note that contrary to wg-quick's MTU setting, this does not take into account the current routes at the time of activation. Whether to automatically add routes for the AllowedIPs ranges of the peers. If TRUE (the default), NetworkManager will automatically add routes in the routing tables according to ipv4.route-table and ipv6.route-table. Usually you want this automatism enabled. If FALSE, no such routes are added automatically. In this case, the user may want to configure static routes in ipv4.routes and ipv6.routes, respectively. + + Note that if the peer's AllowedIPs is "0.0.0.0/0" or "::/0" and the profile's ipv4.never-default or ipv6.never-default setting is enabled, the peer route for this peer won't be added automatically. Whether to automatically add routes for the AllowedIPs ranges of the peers. If TRUE (the default), NetworkManager will automatically add routes in the routing tables according to ipv4.route-table and ipv6.route-table. Usually you want this automatism enabled. If FALSE, no such routes are added automatically. In this case, the user may want to configure static routes in ipv4.routes and ipv6.routes, respectively. Note that if the peer's AllowedIPs is "0.0.0.0/0" or "::/0" and the profile's ipv4.never-default or ipv6.never-default setting is enabled, the peer route for this peer won't be added automatically. The 256 bit private-key in base64 encoding. The 256 bit private-key in base64 encoding. Flags indicating how to handle the "private-key" property. Flags indicating how to handle the "private-key" property. Configures AP isolation, which prevents communication between wireless devices connected to this AP. This property can be set to a value different from NM_TERNARY_DEFAULT (-1) only when the interface is configured in AP mode. + + If set to NM_TERNARY_TRUE (1), devices are not able to communicate with each other. This increases security because it protects devices against attacks from other clients in the network. At the same time, it prevents devices to access resources on the same wireless networks as file shares, printers, etc. + + If set to NM_TERNARY_FALSE (0), devices can talk to each other. + + When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_FALSE (0). Configures AP isolation, which prevents communication between wireless devices connected to this AP. This property can be set to a value different from NM_TERNARY_DEFAULT (-1) only when the interface is configured in AP mode. If set to NM_TERNARY_TRUE (1), devices are not able to communicate with each other. This increases security because it protects devices against attacks from other clients in the network. At the same time, it prevents devices to access resources on the same wireless networks as file shares, printers, etc. If set to NM_TERNARY_FALSE (0), devices can talk to each other. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_FALSE (0). 802.11 frequency band of the network. One of "a" for 5GHz 802.11a or "bg" for 2.4GHz 802.11. This will lock associations to the Wi-Fi network to the specific band, i.e. if "a" is specified, the device will not associate with the same network in the 2.4GHz band even if the network's settings are compatible. This setting depends on specific driver capability and may not work with all drivers. 802.11 frequency band of the network. One of "a" for 5GHz 802.11a or "bg" for 2.4GHz 802.11. This will lock associations to the Wi-Fi network to the specific band, i.e. if "a" is specified, the device will not associate with the same network in the 2.4GHz band even if the network's settings are compatible. This setting depends on specific driver capability and may not work with all drivers. If specified, directs the device to only associate with the given access point. This capability is highly driver dependent and not supported by all devices. Note: this property does not control the BSSID used when creating an Ad-Hoc network and is unlikely to in the future. + + Locking a client profile to a certain BSSID will prevent roaming and also disable background scanning. That can be useful, if there is only one access point for the SSID. If specified, directs the device to only associate with the given access point. This capability is highly driver dependent and not supported by all devices. Note: this property does not control the BSSID used when creating an Ad-Hoc network and is unlikely to in the future. Locking a client profile to a certain BSSID will prevent roaming and also disable background scanning. That can be useful, if there is only one access point for the SSID. Wireless channel to use for the Wi-Fi connection. The device will only join (or create for Ad-Hoc networks) a Wi-Fi network on the specified channel. Because channel numbers overlap between bands, this property also requires the "band" property to be set. Wireless channel to use for the Wi-Fi connection. The device will only join (or create for Ad-Hoc networks) a Wi-Fi network on the specified channel. Because channel numbers overlap between bands, this property also requires the "band" property to be set. If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. + + Beside explicitly specifying a MAC address, the special values "preserve", "permanent", "random" and "stable" are supported. "preserve" means not to touch the MAC address on activation. "permanent" means to use the permanent hardware address of the device. "random" creates a random MAC address on each connect. "stable" creates a hashed MAC address based on connection.stable-id and a machine dependent key. + + If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to "preserve" (older versions of NetworkManager may use a different default value). + + On D-Bus, this field is expressed as "assigned-mac-address" or the deprecated "cloned-mac-address". If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. Beside explicitly specifying a MAC address, the special values "preserve", "permanent", "random" and "stable" are supported. "preserve" means not to touch the MAC address on activation. "permanent" means to use the permanent hardware address of the device. "random" creates a random MAC address on each connect. "stable" creates a hashed MAC address based on connection.stable-id and a machine dependent key. If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to "preserve" (older versions of NetworkManager may use a different default value). On D-Bus, this field is expressed as "assigned-mac-address" or the deprecated "cloned-mac-address". With "cloned-mac-address" setting "random" or "stable", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. + + If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. + + If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting "FE:FF:FF:00:00:00" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the "random" or "stable" algorithm. + + If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of "FE:FF:FF:00:00:00 68:F7:28:00:00:00" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of "02:00:00:00:00:00 00:00:00:00:00:00" will create a fully scrambled globally-administered, burned-in MAC address. + + If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, "02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00" will create a fully scrambled MAC address, randomly locally or globally administered. With "cloned-mac-address" setting "random" or "stable", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting "FE:FF:FF:00:00:00" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the "random" or "stable" algorithm. If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of "FE:FF:FF:00:00:00 68:F7:28:00:00:00" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of "02:00:00:00:00:00 00:00:00:00:00:00" will create a fully scrambled globally-administered, burned-in MAC address. If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, "02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00" will create a fully scrambled MAC address, randomly locally or globally administered. If TRUE, indicates that the network is a non-broadcasting network that hides its SSID. This works both in infrastructure and AP mode. + + In infrastructure mode, various workarounds are used for a more reliable discovery of hidden networks, such as probe-scanning the SSID. However, these workarounds expose inherent insecurities with hidden SSID networks, and thus hidden SSID networks should be used with caution. + + In AP mode, the created network does not broadcast its SSID. + + Note that marking the network as hidden may be a privacy issue for you (in infrastructure mode) or client stations (in AP mode), as the explicit probe-scans are distinctly recognizable on the air. If TRUE, indicates that the network is a non-broadcasting network that hides its SSID. This works both in infrastructure and AP mode. In infrastructure mode, various workarounds are used for a more reliable discovery of hidden networks, such as probe-scanning the SSID. However, these workarounds expose inherent insecurities with hidden SSID networks, and thus hidden SSID networks should be used with caution. In AP mode, the created network does not broadcast its SSID. Note that marking the network as hidden may be a privacy issue for you (in infrastructure mode) or client stations (in AP mode), as the explicit probe-scans are distinctly recognizable on the air. If specified, this connection will only apply to the Wi-Fi device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing). If specified, this connection will only apply to the Wi-Fi device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing). A list of permanent MAC addresses of Wi-Fi devices to which this connection should never apply. Each MAC address should be given in the standard hex-digits-and-colons notation (eg "00:11:22:33:44:55"). A list of permanent MAC addresses of Wi-Fi devices to which this connection should never apply. Each MAC address should be given in the standard hex-digits-and-colons notation (eg "00:11:22:33:44:55"). One of NM_SETTING_MAC_RANDOMIZATION_DEFAULT (0) (never randomize unless the user has set a global default to randomize and the supplicant supports randomization), NM_SETTING_MAC_RANDOMIZATION_NEVER (1) (never randomize the MAC address), or NM_SETTING_MAC_RANDOMIZATION_ALWAYS (2) (always randomize the MAC address). This property is deprecated for 'cloned-mac-address'. Deprecated: 1 One of NM_SETTING_MAC_RANDOMIZATION_DEFAULT (0) (never randomize unless the user has set a global default to randomize and the supplicant supports randomization), NM_SETTING_MAC_RANDOMIZATION_NEVER (1) (never randomize the MAC address), or NM_SETTING_MAC_RANDOMIZATION_ALWAYS (2) (always randomize the MAC address). This property is deprecated for 'cloned-mac-address'. Deprecated: 1 Wi-Fi network mode; one of "infrastructure", "mesh", "adhoc" or "ap". If blank, infrastructure is assumed. Wi-Fi network mode; one of "infrastructure", "mesh", "adhoc" or "ap". If blank, infrastructure is assumed. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames. One of NM_SETTING_WIRELESS_POWERSAVE_DISABLE (2) (disable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_ENABLE (3) (enable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_IGNORE (1) (don't touch currently configure setting) or NM_SETTING_WIRELESS_POWERSAVE_DEFAULT (0) (use the globally configured value). All other values are reserved. One of NM_SETTING_WIRELESS_POWERSAVE_DISABLE (2) (disable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_ENABLE (3) (enable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_IGNORE (1) (don't touch currently configure setting) or NM_SETTING_WIRELESS_POWERSAVE_DEFAULT (0) (use the globally configured value). All other values are reserved. If non-zero, directs the device to only use the specified bitrate for communication with the access point. Units are in Kb/s, ie 5500 = 5.5 Mbit/s. This property is highly driver dependent and not all devices support setting a static bitrate. If non-zero, directs the device to only use the specified bitrate for communication with the access point. Units are in Kb/s, ie 5500 = 5.5 Mbit/s. This property is highly driver dependent and not all devices support setting a static bitrate. A list of BSSIDs (each BSSID formatted as a MAC address like "00:11:22:33:44:55") that have been detected as part of the Wi-Fi network. NetworkManager internally tracks previously seen BSSIDs. The property is only meant for reading and reflects the BSSID list of NetworkManager. The changes you make to this property will not be preserved. A list of BSSIDs (each BSSID formatted as a MAC address like "00:11:22:33:44:55") that have been detected as part of the Wi-Fi network. NetworkManager internally tracks previously seen BSSIDs. The property is only meant for reading and reflects the BSSID list of NetworkManager. The changes you make to this property will not be preserved. SSID of the Wi-Fi network. Must be specified. SSID of the Wi-Fi network. Must be specified. If non-zero, directs the device to use the specified transmit power. Units are dBm. This property is highly driver dependent and not all devices support setting a static transmit power. If non-zero, directs the device to use the specified transmit power. Units are dBm. This property is highly driver dependent and not all devices support setting a static transmit power. The NMSettingWirelessWakeOnWLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY (0x2), NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT (0x4), NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC (0x8), NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE (0x10), NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST (0x20), NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE (0x40), NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE (0x80), NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP (0x100) or the special values NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager). The NMSettingWirelessWakeOnWLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY (0x2), NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT (0x4), NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC (0x8), NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE (0x10), NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST (0x20), NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE (0x40), NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE (0x80), NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP (0x100) or the special values NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager). When WEP is used (ie, key-mgmt = "none" or "ieee8021x") indicate the 802.11 authentication algorithm required by the AP here. One of "open" for Open System, "shared" for Shared Key, or "leap" for Cisco LEAP. When using Cisco LEAP (ie, key-mgmt = "ieee8021x" and auth-alg = "leap") the "leap-username" and "leap-password" properties must be specified. When WEP is used (ie, key-mgmt = "none" or "ieee8021x") indicate the 802.11 authentication algorithm required by the AP here. One of "open" for Open System, "shared" for Shared Key, or "leap" for Cisco LEAP. When using Cisco LEAP (ie, key-mgmt = "ieee8021x" and auth-alg = "leap") the "leap-username" and "leap-password" properties must be specified. Indicates whether Fast Initial Link Setup (802.11ai) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE (1) (disable FILS), NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL (2) (enable FILS if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED (3) (enable FILS and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) and no global default is set, FILS will be optionally enabled. Indicates whether Fast Initial Link Setup (802.11ai) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE (1) (disable FILS), NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL (2) (enable FILS if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED (3) (enable FILS and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) and no global default is set, FILS will be optionally enabled. A list of group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of "wep40", "wep104", "tkip", or "ccmp". A list of group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of "wep40", "wep104", "tkip", or "ccmp". Key management used for the connection. One of "none" (WEP or no password protection), "ieee8021x" (Dynamic WEP), "owe" (Opportunistic Wireless Encryption), "wpa-psk" (WPA2 + WPA3 personal), "sae" (WPA3 personal only), "wpa-eap" (WPA2 + WPA3 enterprise) or "wpa-eap-suite-b-192" (WPA3 enterprise only). + + This property must be set for any Wi-Fi connection that uses security. Key management used for the connection. One of "none" (WEP or no password protection), "ieee8021x" (Dynamic WEP), "owe" (Opportunistic Wireless Encryption), "wpa-psk" (WPA2 + WPA3 personal), "sae" (WPA3 personal only), "wpa-eap" (WPA2 + WPA3 enterprise) or "wpa-eap-suite-b-192" (WPA3 enterprise only). This property must be set for any Wi-Fi connection that uses security. The login password for legacy LEAP connections (ie, key-mgmt = "ieee8021x" and auth-alg = "leap"). The login password for legacy LEAP connections (ie, key-mgmt = "ieee8021x" and auth-alg = "leap"). Flags indicating how to handle the "leap-password" property. Flags indicating how to handle the "leap-password" property. The login username for legacy LEAP connections (ie, key-mgmt = "ieee8021x" and auth-alg = "leap"). The login username for legacy LEAP connections (ie, key-mgmt = "ieee8021x" and auth-alg = "leap"). A list of pairwise encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of "tkip" or "ccmp". A list of pairwise encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of "tkip" or "ccmp". Indicates whether Protected Management Frames (802.11w) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE (1) (disable PMF), NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL (2) (enable PMF if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED (3) (enable PMF and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) and no global default is set, PMF will be optionally enabled. Indicates whether Protected Management Frames (802.11w) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE (1) (disable PMF), NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL (2) (enable PMF if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED (3) (enable PMF and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) and no global default is set, PMF will be optionally enabled. List of strings specifying the allowed WPA protocol versions to use. Each element may be one "wpa" (allow WPA) or "rsn" (allow WPA2/RSN). If not specified, both WPA and RSN connections are allowed. List of strings specifying the allowed WPA protocol versions to use. Each element may be one "wpa" (allow WPA) or "rsn" (allow WPA2/RSN). If not specified, both WPA and RSN connections are allowed. Pre-Shared-Key for WPA networks. For WPA-PSK, it's either an ASCII passphrase of 8 to 63 characters that is (as specified in the 802.11i standard) hashed to derive the actual key, or the key in form of 64 hexadecimal character. The WPA3-Personal networks use a passphrase of any length for SAE authentication. Pre-Shared-Key for WPA networks. For WPA-PSK, it's either an ASCII passphrase of 8 to 63 characters that is (as specified in the 802.11i standard) hashed to derive the actual key, or the key in form of 64 hexadecimal character. The WPA3-Personal networks use a passphrase of any length for SAE authentication. Flags indicating how to handle the "psk" property. Flags indicating how to handle the "psk" property. Flags indicating how to handle the "wep-key0", "wep-key1", "wep-key2", and "wep-key3" properties. Flags indicating how to handle the "wep-key0", "wep-key1", "wep-key2", and "wep-key3" properties. Controls the interpretation of WEP keys. Allowed values are NM_WEP_KEY_TYPE_KEY (1), in which case the key is either a 10- or 26-character hexadecimal string, or a 5- or 13-character ASCII password; or NM_WEP_KEY_TYPE_PASSPHRASE (2), in which case the passphrase is provided as a string and will be hashed using the de-facto MD5 method to derive the actual WEP key. Controls the interpretation of WEP keys. Allowed values are NM_WEP_KEY_TYPE_KEY (1), in which case the key is either a 10- or 26-character hexadecimal string, or a 5- or 13-character ASCII password; or NM_WEP_KEY_TYPE_PASSPHRASE (2), in which case the passphrase is provided as a string and will be hashed using the de-facto MD5 method to derive the actual WEP key. Index 0 WEP key. This is the WEP key used in most networks. See the "wep-key-type" property for a description of how this key is interpreted. Index 0 WEP key. This is the WEP key used in most networks. See the "wep-key-type" property for a description of how this key is interpreted. Index 1 WEP key. This WEP index is not used by most networks. See the "wep-key-type" property for a description of how this key is interpreted. Index 1 WEP key. This WEP index is not used by most networks. See the "wep-key-type" property for a description of how this key is interpreted. Index 2 WEP key. This WEP index is not used by most networks. See the "wep-key-type" property for a description of how this key is interpreted. Index 2 WEP key. This WEP index is not used by most networks. See the "wep-key-type" property for a description of how this key is interpreted. Index 3 WEP key. This WEP index is not used by most networks. See the "wep-key-type" property for a description of how this key is interpreted. Index 3 WEP key. This WEP index is not used by most networks. See the "wep-key-type" property for a description of how this key is interpreted. When static WEP is used (ie, key-mgmt = "none") and a non-default WEP key index is used by the AP, put that WEP key index here. Valid values are 0 (default key) through 3. Note that some consumer access points (like the Linksys WRT54G) number the keys 1 - 4. When static WEP is used (ie, key-mgmt = "none") and a non-default WEP key index is used by the AP, put that WEP key index here. Valid values are 0 (default key) through 3. Note that some consumer access points (like the Linksys WRT54G) number the keys 1 - 4. Flags indicating which mode of WPS is to be used if any. + + There's little point in changing the default setting as NetworkManager will automatically determine whether it's feasible to start WPS enrollment from the Access Point capabilities. + + WPS can be disabled by setting this property to a value of 1. Flags indicating which mode of WPS is to be used if any. There's little point in changing the default setting as NetworkManager will automatically determine whether it's feasible to start WPS enrollment from the Access Point capabilities. WPS can be disabled by setting this property to a value of 1. IEEE 802.15.4 channel. A positive integer or -1, meaning "do not set, use whatever the device is already set to". IEEE 802.15.4 channel. A positive integer or -1, meaning "do not set, use whatever the device is already set to". If specified, this connection will only apply to the IEEE 802.15.4 (WPAN) MAC layer device whose permanent MAC address matches. If specified, this connection will only apply to the IEEE 802.15.4 (WPAN) MAC layer device whose permanent MAC address matches. IEEE 802.15.4 channel page. A positive integer or -1, meaning "do not set, use whatever the device is already set to". IEEE 802.15.4 channel page. A positive integer or -1, meaning "do not set, use whatever the device is already set to". IEEE 802.15.4 Personal Area Network (PAN) identifier. IEEE 802.15.4 Personal Area Network (PAN) identifier. Short IEEE 802.15.4 address to be used within a restricted environment. Short IEEE 802.15.4 address to be used within a restricted environment. \ No newline at end of file diff --git a/src/libnm-client-public/NetworkManager.h b/src/libnm-client-public/NetworkManager.h index 66f676a1..1cd94d11 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 + +#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,60 @@ #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-conn-utils.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 3ae4e8d8..5232bcb4 100644 --- a/src/libnm-client-public/meson.build +++ b/src/libnm-client-public/meson.build @@ -9,6 +9,7 @@ libnm_client_headers = files( 'nm-autoptr.h', 'nm-checkpoint.h', 'nm-client.h', + 'nm-conn-utils.h', 'nm-device-6lowpan.h', 'nm-device-adsl.h', 'nm-device-bond.h', @@ -45,7 +46,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 9f9216bb..5a78e34f 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 a65b4f20..5c314826 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 def1f554..456d7f6b 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 2e3e77c4..6307f112 100644 --- a/src/libnm-client-public/nm-client.h +++ b/src/libnm-client-public/nm-client.h @@ -11,8 +11,6 @@ #error "Only 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-conn-utils.h b/src/libnm-client-public/nm-conn-utils.h new file mode 100644 index 00000000..29250c0b --- /dev/null +++ b/src/libnm-client-public/nm-conn-utils.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2013 - 2015 Red Hat, Inc. + */ + +#ifndef __NM_WIREGUARD_IMPORT_H__ +#define __NM_WIREGUARD_IMPORT_H__ + +#if !defined(__NETWORKMANAGER_H_INSIDE__) && !defined(NETWORKMANAGER_COMPILATION) +#error "Only can be included directly." +#endif + +#include "nm-object.h" + +G_BEGIN_DECLS + +NM_AVAILABLE_IN_1_40 +NMConnection *nm_conn_wireguard_import(const char *filename, GError **error); + +G_END_DECLS + +#endif /* __NM_WIREGUARD_IMPORT_H__ */ diff --git a/src/libnm-client-public/nm-device-6lowpan.h b/src/libnm-client-public/nm-device-6lowpan.h index 2388bf38..d5f8a7a5 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 fa8a1278..a4fbec51 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 19e0e046..6edc6106 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 07905195..e3740022 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 c277bae9..fa8d7308 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 d5b8cb24..8b2f7485 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 636e5eb5..828865c7 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 7b543b2f..ff24c6f1 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 3999b2d5..53b16176 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 d7912729..4f55dc0b 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 e468344f..b1ec3637 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 ec7eb640..95699334 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 f9dfc348..4ef17572 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 86ac2ce7..ea3a3096 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 f0ef1547..8c454057 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 12b30a75..1ba7ac3a 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 170067f9..7524cacb 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 ff99d9f9..4003f901 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 eab5e4e6..406949a1 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 cc05b0c1..e1e7310d 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 41b41915..8f61ae20 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 c3920586..c74453fd 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 3b59023a..fbc8b202 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 5264e9ca..7939539d 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 cf68b496..ad0ca436 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 1c767316..287b792e 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 123b95b2..e6228819 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 4a18bd81..756dfb4e 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 b8a7a3bf..8b011851 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 9e9dbea6..f58d3ddb 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 0188f9c2..625efb58 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 c2627f44..5d693fe3 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 99b1948d..9ad15d30 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 efa3aa53..c6daf1e6 100644 --- a/src/libnm-client-public/nm-object.h +++ b/src/libnm-client-public/nm-object.h @@ -11,8 +11,6 @@ #error "Only 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 6104ecb8..f00b25d6 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 b45b12bb..ca7bfa4c 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 81ffe790..00000000 --- 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 - -#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 33ca139d..578c0333 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 f89617a8..9c4facb2 100644 --- a/src/libnm-client-public/nm-vpn-editor.h +++ b/src/libnm-client-public/nm-vpn-editor.h @@ -13,7 +13,6 @@ #include #include -#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 7704c153..fe0d4bc2 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 81fb6730..5187d93d 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 73e6995c..eff27bcb 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 f19272db..9cd4153c 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-aux-intern/nm-libnm-core-utils.c b/src/libnm-core-aux-intern/nm-libnm-core-utils.c index 37518815..ba05b6cd 100644 --- a/src/libnm-core-aux-intern/nm-libnm-core-utils.c +++ b/src/libnm-core-aux-intern/nm-libnm-core-utils.c @@ -40,6 +40,121 @@ _nm_setting_bond_remove_options_arp_interval(NMSettingBond *s_bond) /*****************************************************************************/ +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_ad_select_from_string, + NMBondAdSelect, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_AD_SELECT_NUM <= 3); + + if (name && name[0] < '0' + _NM_BOND_AD_SELECT_NUM && name[0] >= '0' && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_AD_SELECT_STABLE; }, + {"bandwith", NM_BOND_AD_SELECT_BANDWIDTH}, + {"count", NM_BOND_AD_SELECT_COUNT}, + {"stable", NM_BOND_AD_SELECT_STABLE}, ); + +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_arp_all_targets_from_string, + NMBondArpAllTargets, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_ARP_ALL_TARGETS_NUM <= 2); + + if (name && name[0] < '0' + _NM_BOND_ARP_ALL_TARGETS_NUM && name[0] >= '0' + && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_ARP_ALL_TARGETS_ANY; }, + {"all", NM_BOND_ARP_ALL_TARGETS_ALL}, + {"any", NM_BOND_ARP_ALL_TARGETS_ANY}, ); + +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_fail_over_mac_from_string, + NMBondFailOverMac, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_FAIL_OVER_MAC_NUM <= 3); + + if (name && name[0] < '0' + _NM_BOND_FAIL_OVER_MAC_NUM && name[0] >= '0' + && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_FAIL_OVER_MAC_NONE; }, + {"active", NM_BOND_FAIL_OVER_MAC_ACTIVE}, + {"follow", NM_BOND_FAIL_OVER_MAC_FOLLOW}, + {"none", NM_BOND_FAIL_OVER_MAC_NONE}, ); + +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_lacp_rate_from_string, + NMBondLacpRate, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_LACP_RATE_NUM <= 2); + + if (name && name[0] < '0' + _NM_BOND_LACP_RATE_NUM && name[0] >= '0' && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_LACP_RATE_SLOW; }, + {"fast", NM_BOND_LACP_RATE_FAST}, + {"slow", NM_BOND_LACP_RATE_SLOW}, ); + +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_arp_validate_from_string, + NMBondArpValidate, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_ARP_VALIDATE_NUM <= 7); + + if (name && name[0] < '0' + _NM_BOND_ARP_VALIDATE_NUM && name[0] >= '0' + && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_ARP_VALIDATE_NONE; }, + {"active", NM_BOND_ARP_VALIDATE_ACTIVE}, + {"all", NM_BOND_ARP_VALIDATE_ALL}, + {"backup", NM_BOND_ARP_VALIDATE_BACKUP}, + {"filter", NM_BOND_ARP_VALIDATE_FILTER}, + {"filter_active", NM_BOND_ARP_VALIDATE_FILTER_ACTIVE}, + {"filter_backup", NM_BOND_ARP_VALIDATE_FILTER_BACKUP}, + {"none", NM_BOND_ARP_VALIDATE_NONE}, ); + +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_primary_reselect_from_string, + NMBondPrimaryReselect, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_PRIMARY_RESELECT_NUM <= 3); + + if (name && name[0] < '0' + _NM_BOND_PRIMARY_RESELECT_NUM && name[0] >= '0' + && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_PRIMARY_RESELECT_ALWAYS; }, + {"always", NM_BOND_PRIMARY_RESELECT_ALWAYS}, + {"better", NM_BOND_PRIMARY_RESELECT_BETTER}, + {"failure", NM_BOND_PRIMARY_RESELECT_FAILURE}, ); + +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _nm_setting_bond_xmit_hash_policy_from_string, + NMBondXmitHashPolicy, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_XMIT_HASH_POLICY_NUM <= 6); + + if (name && name[0] < '0' + _NM_BOND_XMIT_HASH_POLICY_NUM && name[0] >= '0' + && name[1] == '\0') { + return name[0] - '0'; + } + }, + { return NM_BOND_XMIT_HASH_POLICY_LAYER2; }, + {"encap2+3", NM_BOND_XMIT_HASH_POLICY_ENCAP2_3}, + {"encap3+4", NM_BOND_XMIT_HASH_POLICY_ENCAP3_4}, + {"layer2", NM_BOND_XMIT_HASH_POLICY_LAYER2}, + {"layer2+3", NM_BOND_XMIT_HASH_POLICY_LAYER2_3}, + {"layer3+4", NM_BOND_XMIT_HASH_POLICY_LAYER3_4}, + {"vlan+srcmac", NM_BOND_XMIT_HASH_POLICY_VLAN_SRCMAC}, ); + NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( _nm_setting_bond_mode_from_string, NMBondMode, @@ -378,3 +493,36 @@ _nm_connection_new_setting(NMConnection *connection, GType gtype) nm_connection_add_setting(connection, setting); return setting; } + +/*****************************************************************************/ + +NMMptcpFlags +nm_mptcp_flags_normalize(NMMptcpFlags flags) +{ + /* Certain combinations of flags are incompatible. Normalize them. + * + * This function never returns 0x0 (NONE). If the flags are neither + * disabled,enabled-on-global-iface,enabled, then we default to "enabled". */ + + if (NM_FLAGS_HAS(flags, NM_MPTCP_FLAGS_DISABLED)) { + /* If the disabled flag is set, then that's the end of it. */ + return NM_MPTCP_FLAGS_DISABLED; + } + + /* Clear all unknown flags. */ + flags &= _NM_MPTCP_FLAGS_ALL; + + /* We must either set "enabled-on-global-iface" or "enabled". The + * former takes precedence, if they are both set. + * + * If neither is set, we default to "enabled". */ + if (NM_FLAGS_HAS(flags, NM_MPTCP_FLAGS_ENABLED_ON_GLOBAL_IFACE)) + flags = NM_FLAGS_UNSET(flags, NM_MPTCP_FLAGS_ENABLED); + else + flags = NM_FLAGS_SET(flags, NM_MPTCP_FLAGS_ENABLED); + + if (NM_FLAGS_ALL(flags, NM_MPTCP_FLAGS_SIGNAL | NM_MPTCP_FLAGS_FULLMESH)) + flags = NM_FLAGS_UNSET(flags, NM_MPTCP_FLAGS_FULLMESH); + + return flags; +} diff --git a/src/libnm-core-aux-intern/nm-libnm-core-utils.h b/src/libnm-core-aux-intern/nm-libnm-core-utils.h index eb30c931..5c827c01 100644 --- a/src/libnm-core-aux-intern/nm-libnm-core-utils.h +++ b/src/libnm-core-aux-intern/nm-libnm-core-utils.h @@ -57,6 +57,102 @@ const char **nm_utils_bond_option_arp_ip_targets_split(const char *arp_ip_target void _nm_setting_bond_remove_options_miimon(NMSettingBond *s_bond); void _nm_setting_bond_remove_options_arp_interval(NMSettingBond *s_bond); +typedef enum { + NM_BOND_AD_SELECT_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_AD_SELECT_STABLE = 0, + NM_BOND_AD_SELECT_BANDWIDTH = 1, + NM_BOND_AD_SELECT_COUNT = 2, + + _NM_BOND_AD_SELECT_NUM, +} NMBondAdSelect; + +NMBondAdSelect _nm_setting_bond_ad_select_from_string(const char *str); + +typedef enum { + NM_BOND_ARP_ALL_TARGETS_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_ARP_ALL_TARGETS_ANY = 0, + NM_BOND_ARP_ALL_TARGETS_ALL = 1, + + _NM_BOND_ARP_ALL_TARGETS_NUM, +} NMBondArpAllTargets; + +NMBondArpAllTargets _nm_setting_bond_arp_all_targets_from_string(const char *str); + +typedef enum { + NM_BOND_FAIL_OVER_MAC_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_FAIL_OVER_MAC_NONE = 0, + NM_BOND_FAIL_OVER_MAC_ACTIVE = 1, + NM_BOND_FAIL_OVER_MAC_FOLLOW = 2, + + _NM_BOND_FAIL_OVER_MAC_NUM, +} NMBondFailOverMac; + +NMBondFailOverMac _nm_setting_bond_fail_over_mac_from_string(const char *str); + +typedef enum { + NM_BOND_LACP_RATE_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_LACP_RATE_SLOW = 0, + NM_BOND_LACP_RATE_FAST = 1, + + _NM_BOND_LACP_RATE_NUM, +} NMBondLacpRate; + +NMBondLacpRate _nm_setting_bond_lacp_rate_from_string(const char *str); + +typedef enum { + NM_BOND_ARP_VALIDATE_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_ARP_VALIDATE_NONE = 0, + NM_BOND_ARP_VALIDATE_ACTIVE = 1, + NM_BOND_ARP_VALIDATE_BACKUP = 2, + NM_BOND_ARP_VALIDATE_ALL = 3, + NM_BOND_ARP_VALIDATE_FILTER = 4, + NM_BOND_ARP_VALIDATE_FILTER_ACTIVE = 5, + NM_BOND_ARP_VALIDATE_FILTER_BACKUP = 6, + + _NM_BOND_ARP_VALIDATE_NUM, +} NMBondArpValidate; + +NMBondArpValidate _nm_setting_bond_arp_validate_from_string(const char *str); + +typedef enum { + NM_BOND_PRIMARY_RESELECT_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_PRIMARY_RESELECT_ALWAYS = 0, + NM_BOND_PRIMARY_RESELECT_BETTER = 1, + NM_BOND_PRIMARY_RESELECT_FAILURE = 2, + + _NM_BOND_PRIMARY_RESELECT_NUM, +} NMBondPrimaryReselect; + +NMBondPrimaryReselect _nm_setting_bond_primary_reselect_from_string(const char *str); + +typedef enum { + NM_BOND_XMIT_HASH_POLICY_UNKNOWN = -1, + + /* The numeric values correspond to kernel's numbering. */ + NM_BOND_XMIT_HASH_POLICY_LAYER2 = 0, + NM_BOND_XMIT_HASH_POLICY_LAYER3_4 = 1, + NM_BOND_XMIT_HASH_POLICY_LAYER2_3 = 2, + NM_BOND_XMIT_HASH_POLICY_ENCAP2_3 = 3, + NM_BOND_XMIT_HASH_POLICY_ENCAP3_4 = 4, + NM_BOND_XMIT_HASH_POLICY_VLAN_SRCMAC = 5, + + _NM_BOND_XMIT_HASH_POLICY_NUM, +} NMBondXmitHashPolicy; + +NMBondXmitHashPolicy _nm_setting_bond_xmit_hash_policy_from_string(const char *str); + typedef enum { NM_BOND_MODE_UNKNOWN = -1, @@ -171,4 +267,16 @@ gboolean nm_settings_connection_validate_permission_user(const char *item, gssiz gpointer _nm_connection_ensure_setting(NMConnection *connection, GType gtype); gpointer _nm_connection_new_setting(NMConnection *connection, GType gtype); +/*****************************************************************************/ + +#define _NM_MPTCP_FLAGS_ALL \ + ((NMMptcpFlags) (NM_MPTCP_FLAGS_DISABLED | NM_MPTCP_FLAGS_ENABLED_ON_GLOBAL_IFACE \ + | NM_MPTCP_FLAGS_ENABLED | NM_MPTCP_FLAGS_SIGNAL | NM_MPTCP_FLAGS_SUBFLOW \ + | NM_MPTCP_FLAGS_BACKUP | NM_MPTCP_FLAGS_FULLMESH)) + +#define _NM_MPTCP_FLAGS_DEFAULT \ + ((NMMptcpFlags) (NM_MPTCP_FLAGS_ENABLED_ON_GLOBAL_IFACE | NM_MPTCP_FLAGS_SUBFLOW)) + +NMMptcpFlags nm_mptcp_flags_normalize(NMMptcpFlags flags); + #endif /* __NM_LIBNM_SHARED_UTILS_H__ */ diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c index 27cea2cb..aed4be21 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 c599aefa..95073bcc 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 00fb8a33..6ee68b5c 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" @@ -1160,17 +1159,30 @@ ip6_addr_gen_mode_parser(KeyfileReaderInfo *info, NMSetting *setting, const char s, (int *) &addr_gen_mode, NULL)) { - read_handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid option '%s', use one of [%s]"), - s, - "eui64,stable-privacy"); - return; + if (!read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid option '%s', use one of [%s]"), + s, + "eui64,stable-privacy")) + return; + addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64; } - } else - addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64; + } else { + gs_free char *s2 = NULL; + + s2 = nm_keyfile_plugin_kf_get_string(info->keyfile, + setting_name, + NM_SETTING_IP6_CONFIG_TOKEN, + NULL); + if (s2) { + /* If a token is set, but the addr-gen-mode is not, then the default + * is eui64. Otherwise, the result would not verify. */ + addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64; + } else + addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64; + } g_object_set(G_OBJECT(setting), key, (int) addr_gen_mode, NULL); } @@ -2190,8 +2202,10 @@ ip6_addr_gen_mode_writer(KeyfileWriterInfo *info, gs_free char *str = NULL; addr_gen_mode = (NMSettingIP6ConfigAddrGenMode) g_value_get_int(value); - str = nm_utils_enum_to_str(nm_setting_ip6_config_addr_gen_mode_get_type(), addr_gen_mode); - nm_keyfile_plugin_kf_set_string(info->keyfile, nm_setting_get_name(setting), key, str); + if (addr_gen_mode != NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64) { + str = nm_utils_enum_to_str(nm_setting_ip6_config_addr_gen_mode_get_type(), addr_gen_mode); + nm_keyfile_plugin_kf_set_string(info->keyfile, nm_setting_get_name(setting), key, str); + } } static void @@ -4062,7 +4076,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 +4389,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-8021x.c b/src/libnm-core-impl/nm-setting-8021x.c index 41feae57..fd9a0961 100644 --- a/src/libnm-core-impl/nm-setting-8021x.c +++ b/src/libnm-core-impl/nm-setting-8021x.c @@ -2980,8 +2980,6 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) error)) return FALSE; - /* normalizable warnings from here on. */ - #define _check_strempty_and_return(priv, prop_name, field, error) \ G_STMT_START \ { \ @@ -2999,6 +2997,8 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) } \ G_STMT_END + /* normalizable warnings from here on. */ + _check_strempty_and_return(priv, NM_SETTING_802_1X_IDENTITY, identity, error); _check_strempty_and_return(priv, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, diff --git a/src/libnm-core-impl/nm-setting-bond.c b/src/libnm-core-impl/nm-setting-bond.c index ae2fe051..cdfc7641 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) { @@ -773,6 +764,39 @@ _nm_setting_bond_get_option_type(NMSettingBond *setting, const char *name) return option_meta->opt_type; } +guint32 +_nm_setting_bond_opt_value_as_u32(NMSettingBond *s_bond, const char *opt) +{ + nm_assert(_get_option_meta(opt)->opt_type == NM_BOND_OPTION_TYPE_INT); + return _nm_utils_ascii_str_to_uint64(nm_setting_bond_get_option_normalized(s_bond, opt), + 10, + 0, + G_MAXUINT32, + 0); +} + +guint16 +_nm_setting_bond_opt_value_as_u16(NMSettingBond *s_bond, const char *opt) +{ + nm_assert(_get_option_meta(opt)->opt_type == NM_BOND_OPTION_TYPE_INT); + return _nm_utils_ascii_str_to_uint64(nm_setting_bond_get_option_normalized(s_bond, opt), + 10, + 0, + G_MAXUINT16, + 0); +} + +guint8 +_nm_setting_bond_opt_value_as_u8(NMSettingBond *s_bond, const char *opt) +{ + nm_assert(_get_option_meta(opt)->opt_type == NM_BOND_OPTION_TYPE_INT); + return _nm_utils_ascii_str_to_uint64(nm_setting_bond_get_option_normalized(s_bond, opt), + 10, + 0, + G_MAXUINT8, + 0); +} + /*****************************************************************************/ static gboolean diff --git a/src/libnm-core-impl/nm-setting-bridge.c b/src/libnm-core-impl/nm-setting-bridge.c index 41cd6632..39a3fb60 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-connection.c b/src/libnm-core-impl/nm-setting-connection.c index 0d7d7cd5..0d307be3 100644 --- a/src/libnm-core-impl/nm-setting-connection.c +++ b/src/libnm-core-impl/nm-setting-connection.c @@ -65,10 +65,12 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingConnection, PROP_MDNS, PROP_LLMNR, PROP_DNS_OVER_TLS, + PROP_MPTCP_FLAGS, PROP_STABLE_ID, PROP_AUTH_RETRIES, PROP_WAIT_DEVICE_TIMEOUT, - PROP_MUD_URL, ); + PROP_MUD_URL, + PROP_WAIT_ACTIVATION_DELAY, ); typedef struct { GArray *permissions; @@ -94,6 +96,8 @@ typedef struct { gint32 dns_over_tls; gint32 wait_device_timeout; gint32 lldp; + gint32 wait_activation_delay; + guint32 mptcp_flags; guint32 gateway_ping_timeout; bool autoconnect; bool read_only; @@ -734,6 +738,23 @@ nm_setting_connection_get_wait_device_timeout(NMSettingConnection *setting) return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->wait_device_timeout; } +/** + * nm_setting_connection_get_wait_activation_delay: + * @setting: the #NMSettingConnection + * + * Returns: the %NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY property with + * the delay in milliseconds. -1 is the default. + * + * Since: 1.40 + */ +gint32 +nm_setting_connection_get_wait_activation_delay(NMSettingConnection *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), -1); + + return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->wait_activation_delay; +} + /** * nm_setting_connection_get_autoconnect_slaves: * @setting: the #NMSettingConnection @@ -996,6 +1017,22 @@ nm_setting_connection_get_dns_over_tls(NMSettingConnection *setting) return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->dns_over_tls; } +/** + * nm_setting_connection_get_mptcp_flags: + * @setting: the #NMSettingConnection + * + * Returns: the #NMSettingConnection:mptcp-flags property of the setting. + * + * Since: 1.40 + **/ +NMMptcpFlags +nm_setting_connection_get_mptcp_flags(NMSettingConnection *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_CONNECTION(setting), NM_MPTCP_FLAGS_NONE); + + return NM_SETTING_CONNECTION_GET_PRIVATE(setting)->mptcp_flags; +} + static void _set_error_missing_base_setting(GError **error, const char *type) { @@ -1348,6 +1385,64 @@ after_interface_name: return FALSE; } + if (priv->mptcp_flags != 0) { + if (NM_FLAGS_HAS(priv->mptcp_flags, NM_MPTCP_FLAGS_DISABLED)) { + if (priv->mptcp_flags != NM_MPTCP_FLAGS_DISABLED) { + g_set_error_literal( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("\"disabled\" flag cannot be combined with other MPTCP flags")); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_MPTCP_FLAGS); + return FALSE; + } + } else { + guint32 f; + + if (NM_FLAGS_ALL(priv->mptcp_flags, + NM_MPTCP_FLAGS_ENABLED_ON_GLOBAL_IFACE | NM_MPTCP_FLAGS_ENABLED)) { + g_set_error_literal( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("\"enabled\" and \"enabled-on-global-iface\" flag cannot be set together")); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_MPTCP_FLAGS); + return FALSE; + } + if (NM_FLAGS_ALL(priv->mptcp_flags, NM_MPTCP_FLAGS_SIGNAL | NM_MPTCP_FLAGS_FULLMESH)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("cannot set both \"signal\" and \"fullmesh\" MPTCP flags")); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_MPTCP_FLAGS); + return FALSE; + } + f = NM_FLAGS_UNSET(priv->mptcp_flags, NM_MPTCP_FLAGS_ENABLED_ON_GLOBAL_IFACE) + | ((guint32) NM_MPTCP_FLAGS_ENABLED); + if (f != nm_mptcp_flags_normalize(f)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("value %u is not a valid combination of MPTCP flags"), + priv->mptcp_flags); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_MPTCP_FLAGS); + return FALSE; + } + } + } + if (!NM_IN_SET(priv->multi_connect, (int) NM_CONNECTION_MULTI_CONNECT_DEFAULT, (int) NM_CONNECTION_MULTI_CONNECT_SINGLE, @@ -2464,6 +2559,101 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass) NMSettingConnectionPrivate, dns_over_tls); + /* Notes about "mptcp-flags": + * + * It is a bit odd that NMMptcpFlags mixes flags with different purposes: + * + * - "disabled", "disabled-on-local-iface", "enable": whether MPTCP handling + * is enabled. The flag "disabled-on-local-iface" enables it based on whether + * the interface has a default route. + * - "signal", "subflow", "backup", "fullmesh": the endpoint flags + * that are used. + * + * The reason is, that it is useful to have one "connection.mptcp-flags" + * property, that can express various aspects at once. The alternatives + * would be multiple properties like "connection.mptcp-enabled", + * "connection.mptcp-addr-flags" and "connection.mptcp-notify-flags". + * More properties does not necessarily make the API simpler. In particular + * for something like MPTCP, which should just work by default and only + * in special cases require special configuration. + * + * The entire idea is to only have one "connection.mptcp-flags" property (for now). + * That one can encode multiple aspects about MPTCP, whether it's enabled at all, + * which address flags to use when configuring endpoints, and opt-in addresses + * that otherwise would not be configured as endpoints. + * + * "connection.mptcp-flags" applies to all addresses on the interface (minus the ones + * that are not included by default). The idea is that in the future we could have + * more properties like "ipv4.dhcp-mptcp-flags=subflow", "ipv6.link-local-mptcp-flags=disabled", + * "ipv4.addresses='192.168.1.5/24 mptcp-flags=signal,backup'", which can overwrite the + * flags on a per-address basis. + * + * But for that future extension, we now need a global "connection.mptcp-flags" property + * in the API that is the basis and applies to all addresses. + */ + + /** + * NMSettingConnection:mptcp-flags: + * + * Whether to configure MPTCP endpoints and the address flags. + * If MPTCP is enabled in NetworkManager, it will configure the + * addresses of the interface as MPTCP endpoints. Note that + * IPv4 loopback addresses (127.0.0.0/8), IPv4 link local + * addresses (169.254.0.0/16), the IPv6 loopback address (::1), + * IPv6 link local addresses (fe80::/10), IPv6 unique + * local addresses (ULA, fc00::/7) and IPv6 privacy extension addresses + * (rfc3041, ipv6.ip6-privacy) will be excluded from being + * configured as endpoints. + * + * If "disabled" (0x1), MPTCP handling for the interface is disabled and + * no endpoints are registered. + * + * The flag "enabled-on-global-iface" (0x2) means that MPTCP handling is enabled + * if the interface configures a default route in the main routing table. + * This choice is per-address family, for example if there is an IPv4 default route + * 0.0.0.0/0, IPv4 endpoints are configured. + * + * The "enabled" (0x4) flag means that MPTCP handling is explicitly enabled. + * This flag can also be implied from the presence of other flags. + * + * If MPTCP handling is enabled, then endpoints will be configured + * with the specified address flags "signal" (0x10), "subflow" (0x20), "backup" (0x40), + * "fullmesh" (0x80). See ip-mptcp(8) manual for additional information about the flags. + * + * If the flags are zero, the global connection default from NetworkManager.conf is + * honored. If still unspecified, the fallback is either "disabled" or + * "enabled-on-global-iface,subflow" depending on "/proc/sys/net/mptcp/enabled". + * + * NetworkManager does not change the MPTCP limits nor enable MPTCP via + * "/proc/sys/net/mptcp/enabled". That is a host configuration which the + * admin can change via sysctl and ip-mptcp. + * + * Strict reverse path filtering (rp_filter) breaks many MPTCP use cases, so when + * MPTCP handling for IPv4 addresses on the interface is enabled, NetworkManager would + * loosen the strict reverse path filtering (1) to the loose setting (2). + * + * Since: 1.40 + **/ + /* ---ifcfg-rh--- + * property: mptcp-flags + * variable: MPTCP_FLAGS(+) + * default: missing variable means global default + * description: The MPTCP flags that indicate whether MPTCP is enabled + * and which flags to use for the address endpoints. + * example: MPTCP_FLAGS="signal,subflow" + * ---end--- + */ + _nm_setting_property_define_direct_uint32(properties_override, + obj_properties, + NM_SETTING_CONNECTION_MPTCP_FLAGS, + PROP_MPTCP_FLAGS, + 0, + G_MAXUINT32, + NM_MPTCP_FLAGS_NONE, + NM_SETTING_PARAM_NONE, + NMSettingConnectionPrivate, + mptcp_flags); + /** * NMSettingConnection:wait-device-timeout: * @@ -2530,6 +2720,37 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass) NMSettingConnectionPrivate, mud_url); + /** + * NMSettingConnection:wait-activation-delay: + * + * Time in milliseconds to wait for connection to be considered activated. + * The wait will start after the pre-up dispatcher event. + * + * The value 0 means no wait time. The default value is -1, which + * currently has the same meaning as no wait time. + * + * Since: 1.40 + **/ + /* ---ifcfg-rh--- + * property: wait-activation-delay + * variable: WAIT_ACTIVATION_DELAY(+) + * values: delay in milliseconds. + * description: Time in milliseconds to wait for connection to be considered activated. + * The wait will start after the pre-up dispatcher event. + * example: WAIT_ACTIVATION_DELAY=5000 + * ---end--- + */ + _nm_setting_property_define_direct_int32(properties_override, + obj_properties, + NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY, + PROP_WAIT_ACTIVATION_DELAY, + -1, + G_MAXINT32, + -1, + NM_SETTING_PARAM_NONE, + NMSettingConnectionPrivate, + wait_activation_delay); + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); _nm_setting_class_commit(setting_class, diff --git a/src/libnm-core-impl/nm-setting-ethtool.c b/src/libnm-core-impl/nm-setting-ethtool.c index 49c0d780..71179efd 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 cffd5b19..ab760c4e 100644 --- a/src/libnm-core-impl/nm-setting-ip-config.c +++ b/src/libnm-core-impl/nm-setting-ip-config.c @@ -1197,6 +1197,10 @@ nm_ip_route_set_attribute(NMIPRoute *route, const char *name, GVariant *value) } static const NMVariantAttributeSpec *const ip_route_attribute_spec[] = { + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_ADVMSS, + G_VARIANT_TYPE_UINT32, + .v4 = TRUE, + .v6 = TRUE, ), NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_CWND, G_VARIANT_TYPE_UINT32, .v4 = TRUE, @@ -1213,6 +1217,10 @@ static const NMVariantAttributeSpec *const ip_route_attribute_spec[] = { G_VARIANT_TYPE_UINT32, .v4 = TRUE, .v6 = TRUE, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_LOCK_ADVMSS, + G_VARIANT_TYPE_BOOLEAN, + .v4 = TRUE, + .v6 = TRUE, ), NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, @@ -1241,6 +1249,14 @@ static const NMVariantAttributeSpec *const ip_route_attribute_spec[] = { G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_QUICKACK, + G_VARIANT_TYPE_BOOLEAN, + .v4 = TRUE, + .v6 = TRUE, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_RTO_MIN, + G_VARIANT_TYPE_UINT32, + .v4 = TRUE, + .v6 = TRUE, ), NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(NM_IP_ROUTE_ATTRIBUTE_SCOPE, G_VARIANT_TYPE_BYTE, .v4 = TRUE, @@ -2481,10 +2497,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 +2525,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 +3830,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, ' '), @@ -6149,7 +6165,7 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass) /** * NMSettingIPConfig:dns-search: * - * Array of DNS search domains. Domains starting with a tilde ('~') + * List of DNS search domains. Domains starting with a tilde ('~') * are considered 'routing' domains and are used only to decide the * interface over which a query must be forwarded; they are not used * to complete unqualified host names. @@ -6158,6 +6174,12 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass) * Split DNS, then the search domains specify which name servers to * query. This makes the behavior different from running with plain * /etc/resolv.conf. For more information see also the dns-priority setting. + * + * When set on a profile that also enabled DHCP, the DNS search list + * received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) + * gets merged with the manual list. This can be prevented by setting + * "ignore-auto-dns". Note that if no DNS searches are configured, the + * fallback will be derived from the domain from DHCP (option 15). **/ obj_properties[PROP_DNS_SEARCH] = g_param_spec_boxed(NM_SETTING_IP_CONFIG_DNS_SEARCH, diff --git a/src/libnm-core-impl/nm-setting-ip4-config.c b/src/libnm-core-impl/nm-setting-ip4-config.c index bf555168..ff56834e 100644 --- a/src/libnm-core-impl/nm-setting-ip4-config.c +++ b/src/libnm-core-impl/nm-setting-ip4-config.c @@ -38,14 +38,16 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_DHCP_CLIENT_ID, PROP_DHCP_FQDN, - PROP_DHCP_VENDOR_CLASS_IDENTIFIER, ); + PROP_DHCP_VENDOR_CLASS_IDENTIFIER, + PROP_LINK_LOCAL, ); typedef struct { NMSettingIPConfigPrivate parent; - char *dhcp_client_id; - char *dhcp_fqdn; - char *dhcp_vendor_class_identifier; + char *dhcp_client_id; + char *dhcp_fqdn; + char *dhcp_vendor_class_identifier; + gint32 link_local; } NMSettingIP4ConfigPrivate; /** @@ -127,6 +129,25 @@ nm_setting_ip4_config_get_dhcp_vendor_class_identifier(NMSettingIP4Config *setti return NM_SETTING_IP4_CONFIG_GET_PRIVATE(setting)->dhcp_vendor_class_identifier; } +/** + * nm_setting_ip4_config_get_link_local: + * @setting: the #NMSettingIP4Config + * + * Returns the value contained in the #NMSettingIP4Config:link_local + * property. + * + * Returns: the link-local configuration + * + * Since: 1.40 + **/ +NMSettingIP4LinkLocal +nm_setting_ip4_config_get_link_local(NMSettingIP4Config *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_IP4_CONFIG(setting), NM_SETTING_IP4_LL_DEFAULT); + + return NM_SETTING_IP4_CONFIG_GET_PRIVATE(setting)->link_local; +} + static gboolean verify(NMSetting *setting, NMConnection *connection, GError **error) { @@ -218,6 +239,46 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + if (!NM_IN_SET(priv->link_local, + NM_SETTING_IP4_LL_AUTO, + NM_SETTING_IP4_LL_DEFAULT, + NM_SETTING_IP4_LL_DISABLED, + NM_SETTING_IP4_LL_ENABLED)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("property is invalid")); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_LINK_LOCAL); + return FALSE; + } + if (priv->link_local == NM_SETTING_IP4_LL_ENABLED + && nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("cannot enable ipv4.link-local with ipv4.method=disabled")); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_LINK_LOCAL); + return FALSE; + } + if (priv->link_local == NM_SETTING_IP4_LL_DISABLED + && nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("cannot disable ipv4.link-local with ipv4.method=link-local")); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP4_CONFIG_LINK_LOCAL); + return FALSE; + } + if (priv->dhcp_client_id && !priv->dhcp_client_id[0]) { g_set_error_literal(error, NM_CONNECTION_ERROR, @@ -854,6 +915,39 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass) NMSettingIP4ConfigPrivate, dhcp_vendor_class_identifier); + /** + * NMSettingIP4Config:link-local: + * + * Enable and disable the IPv4 link-local configuration independently of the + * ipv4.method configuration. This allows a link-local address (169.254.x.y/16) + * to be obtained in addition to other addresses, such as those manually + * configured or obtained from a DHCP server. + * + * When set to "auto", the value is dependent on "ipv4.method". + * When set to "default", it honors the global connection default, before + * falling back to "auto". Note that if "ipv4.method" is "disabled", then + * link local addressing is always disabled too. The default is "default". + * + * Since 1.40 + */ + /* ---ifcfg-rh--- + * property: link-local + * variable: IPV4_LINK_LOCAL(+) + * description: Configure link-local IP address in interaction with method + * example: IPV4_LINK_LOCAL=auto + * ---end--- + */ + _nm_setting_property_define_direct_int32(properties_override, + obj_properties, + NM_SETTING_IP4_CONFIG_LINK_LOCAL, + PROP_LINK_LOCAL, + G_MININT32, + G_MAXINT32, + NM_SETTING_IP4_LL_DEFAULT, + NM_SETTING_PARAM_NONE, + NMSettingIP4ConfigPrivate, + link_local); + /* IP4-specific property overrides */ /* ---dbus--- @@ -963,6 +1057,9 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass) * Various attributes are supported: * * + * "advmss" - an unsigned 32 bit integer. + * + * * "cwnd" - an unsigned 32 bit integer. * * @@ -972,6 +1069,9 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass) * "initrwnd" - an unsigned 32 bit integer. * * + * "lock-advmss" - a boolean value. + * + * * "lock-cwnd" - a boolean value. * * @@ -993,6 +1093,13 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass) * "onlink" - a boolean value. * * + * "quickack" - a boolean value. + * + * + * "rto_min" - an unsigned 32 bit integer. + * The value is in milliseconds. + * + * * "scope" - an unsigned 8 bit integer. IPv4 only. * * diff --git a/src/libnm-core-impl/nm-setting-ip6-config.c b/src/libnm-core-impl/nm-setting-ip6-config.c index f75c14ce..8b593b97 100644 --- a/src/libnm-core-impl/nm-setting-ip6-config.c +++ b/src/libnm-core-impl/nm-setting-ip6-config.c @@ -43,16 +43,18 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_IP6_PRIVACY, PROP_ADDR_GEN_MODE, PROP_TOKEN, PROP_DHCP_DUID, - PROP_RA_TIMEOUT, ); + PROP_RA_TIMEOUT, + PROP_MTU, ); typedef struct { NMSettingIPConfigPrivate parent; - char *token; - char *dhcp_duid; - int ip6_privacy; - gint32 addr_gen_mode; - gint32 ra_timeout; + char *token; + char *dhcp_duid; + int ip6_privacy; + gint32 addr_gen_mode; + gint32 ra_timeout; + guint32 mtu; } NMSettingIP6ConfigPrivate; /** @@ -110,7 +112,7 @@ NMSettingIP6ConfigAddrGenMode nm_setting_ip6_config_get_addr_gen_mode(NMSettingIP6Config *setting) { g_return_val_if_fail(NM_IS_SETTING_IP6_CONFIG(setting), - NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY); + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT); return NM_SETTING_IP6_CONFIG_GET_PRIVATE(setting)->addr_gen_mode; } @@ -171,6 +173,23 @@ nm_setting_ip6_config_get_ra_timeout(NMSettingIP6Config *setting) return NM_SETTING_IP6_CONFIG_GET_PRIVATE(setting)->ra_timeout; } +/** + * nm_setting_ip6_config_get_mtu: + * @setting: the #NMSettingIP6Config + * + * Returns: The configured %NM_SETTING_IP6_CONFIG_MTU value for the maximum + * transmission unit. + * + * Since: 1.40 + **/ +guint32 +nm_setting_ip6_config_get_mtu(NMSettingIP6Config *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_IP6_CONFIG(setting), 0); + + return NM_SETTING_IP6_CONFIG_GET_PRIVATE(setting)->mtu; +} + static gboolean verify(NMSetting *setting, NMConnection *connection, GError **error) { @@ -269,7 +288,9 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) if (!NM_IN_SET(priv->addr_gen_mode, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, - NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY)) { + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT)) { g_set_error_literal(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -757,8 +778,10 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass) * * Configure method for creating the address for use with RFC4862 IPv6 * Stateless Address Autoconfiguration. The permitted values are: - * %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 or + * %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, * %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY. + * %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64 + * or %NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT. * * If the property is set to EUI64, the addresses will be generated * using the interface tokens derived from hardware address. This makes @@ -773,9 +796,16 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass) * and makes the address stable when the network interface hardware is * replaced. * - * On D-Bus, the absence of an addr-gen-mode setting equals enabling - * stable-privacy. For keyfile plugin, the absence of the setting - * on disk means EUI64 so that the property doesn't change on upgrade + * The special values "default" and "default-or-eui64" will fallback to the global + * connection default in as documented in NetworkManager.conf(5) manual. If the + * global default is not specified, the fallback value is "stable-privacy" + * or "eui64", respectively. + * + * For libnm, the property defaults to "default" since 1.40. + * Previously it defaulted to "stable-privacy". + * On D-Bus, the absence of an addr-gen-mode setting equals + * "default". For keyfile plugin, the absence of the setting + * on disk means "default-or-eui64" so that the property doesn't change on upgrade * from older versions. * * Note that this setting is distinct from the Privacy Extensions as @@ -787,8 +817,8 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass) /* ---ifcfg-rh--- * property: addr-gen-mode * variable: IPV6_ADDR_GEN_MODE - * values: IPV6_ADDR_GEN_MODE: eui64, stable-privacy - * default: eui64 + * values: IPV6_ADDR_GEN_MODE: default, default-or-eui64, eui64, stable-privacy + * default: "default-or-eui64" * description: Configure IPv6 Stable Privacy addressing for SLAAC (RFC7217). * example: IPV6_ADDR_GEN_MODE=stable-privacy * ---end--- @@ -799,10 +829,11 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass) PROP_ADDR_GEN_MODE, G_MININT32, G_MAXINT32, - NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT, NM_SETTING_PARAM_NONE, NMSettingIP6ConfigPrivate, - addr_gen_mode); + addr_gen_mode, + .to_dbus_including_default = TRUE); /** * NMSettingIP6Config:token: @@ -856,6 +887,27 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass) NMSettingIP6ConfigPrivate, ra_timeout); + /** + * NMSettingIP6Config:mtu: + * + * Maximum transmission unit size, in bytes. If zero (the default), the MTU + * is set automatically from router advertisements or is left equal to the + * link-layer MTU. If greater than the link-layer MTU, or greater than zero + * but less than the minimum IPv6 MTU of 1280, this value has no effect. + * + * Since: 1.40 + **/ + _nm_setting_property_define_direct_uint32(properties_override, + obj_properties, + NM_SETTING_IP6_CONFIG_MTU, + PROP_MTU, + 0, + G_MAXUINT32, + 0, + NM_SETTING_PARAM_FUZZY_IGNORE, + NMSettingIP6ConfigPrivate, + mtu); + /** * NMSettingIP6Config:dhcp-duid: * @@ -936,7 +988,7 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass) * 'address-data' and 'gateway'. * * Array of IPv6 address structures. Each IPv6 address structure is - * composed of an IPv6 address, a prefix length (1 - 128), and an IPv6 + * composed of an IPv6 address, a prefix length (0 - 128), and an IPv6 * gateway address. The gateway may be zeroed out if no gateway exists for * that subnet. * ---end--- @@ -984,7 +1036,7 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass) * you send this property the daemon will ignore 'route-data'. * * Array of IPv6 route structures. Each IPv6 route structure is - * composed of an IPv6 address, a prefix length (1 - 128), an IPv6 + * composed of an IPv6 address, a prefix length (0 - 128), an IPv6 * next hop address (which may be zeroed out if there is no next hop), * and a metric. If the metric is 0, NM will choose an appropriate * default metric for the device. @@ -1003,6 +1055,9 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass) * Various attributes are supported: * * + * "advmss" - an unsigned 32 bit integer. + * + * * "cwnd" - an unsigned 32 bit integer. * * @@ -1015,6 +1070,9 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass) * "initrwnd" - an unsigned 32 bit integer. * * + * "lock-advmss" - a boolean value. + * + * * "lock-cwnd" - a boolean value. * * @@ -1036,6 +1094,13 @@ nm_setting_ip6_config_class_init(NMSettingIP6ConfigClass *klass) * "onlink" - a boolean value. * * + * "quickack" - a boolean value. + * + * + * "rto_min" - an unsigned 32 bit integer. + * The value is in milliseconds. + * + * * "src" - an IPv6 address. * * diff --git a/src/libnm-core-impl/nm-setting-wireguard.c b/src/libnm-core-impl/nm-setting-wireguard.c index d713b6a5..ad0f01d5 100644 --- a/src/libnm-core-impl/nm-setting-wireguard.c +++ b/src/libnm-core-impl/nm-setting-wireguard.c @@ -2488,7 +2488,10 @@ nm_setting_wireguard_class_init(NMSettingWireGuardClass *klass) * * Leaving this at the default will enable this option automatically * if ipv4.never-default is not set and there are any peers that use - * a default-route as allowed-ips. + * a default-route as allowed-ips. Since this automatism only makes + * sense if you also have a peer with an /0 allowed-ips, it is usually + * not necessary to enable this explicitly. However, you can disable + * it if you want to configure your own routing and rules. * * Since: 1.20 **/ diff --git a/src/libnm-core-impl/nm-setting-wireless.c b/src/libnm-core-impl/nm-setting-wireless.c index 68cc0e13..cf391598 100644 --- a/src/libnm-core-impl/nm-setting-wireless.c +++ b/src/libnm-core-impl/nm-setting-wireless.c @@ -825,10 +825,10 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) { NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting); const char *valid_modes[] = {NM_SETTING_WIRELESS_MODE_INFRA, - NM_SETTING_WIRELESS_MODE_ADHOC, - NM_SETTING_WIRELESS_MODE_AP, - NM_SETTING_WIRELESS_MODE_MESH, - NULL}; + NM_SETTING_WIRELESS_MODE_ADHOC, + NM_SETTING_WIRELESS_MODE_AP, + NM_SETTING_WIRELESS_MODE_MESH, + NULL}; const char *valid_bands[] = {"a", "bg", NULL}; guint i; gsize length; @@ -1409,6 +1409,10 @@ nm_setting_wireless_class_init(NMSettingWirelessClass *klass) * point. This capability is highly driver dependent and not supported by * all devices. Note: this property does not control the BSSID used when * creating an Ad-Hoc network and is unlikely to in the future. + * + * Locking a client profile to a certain BSSID will prevent roaming and also + * disable background scanning. That can be useful, if there is only one access + * point for the SSID. **/ /* ---ifcfg-rh--- * property: bssid diff --git a/src/libnm-core-impl/nm-team-utils.c b/src/libnm-core-impl/nm-team-utils.c index 2f62f6c6..6d87f50b 100644 --- a/src/libnm-core-impl/nm-team-utils.c +++ b/src/libnm-core-impl/nm-team-utils.c @@ -2148,11 +2148,11 @@ nm_team_setting_config_set(NMTeamSetting *self, const char *js_str) else { gboolean unrecognized_content = FALSE; bool has_lst[_NM_TEAM_ATTRIBUTE_NUM] = { - FALSE, + FALSE, }; NMValueTypUnion val_lst[_NM_TEAM_ATTRIBUTE_NUM]; nm_json_t *found_keys[_NM_TEAM_ATTRIBUTE_NUM] = { - NULL, + NULL, }; gs_unref_ptrarray GPtrArray *ptr_array_master_runner_tx_hash_free = NULL; gs_unref_ptrarray GPtrArray *ptr_array_link_watchers_free = NULL; diff --git a/src/libnm-core-impl/nm-utils.c b/src/libnm-core-impl/nm-utils.c index d5d884f2..3c4cbc65 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" @@ -1559,29 +1558,33 @@ nm_utils_ip4_routes_from_variant(GVariant *value) /** * nm_utils_ip4_netmask_to_prefix: - * @netmask: an IPv4 netmask in network byte order + * @netmask: an IPv4 netmask in network byte order. + * Usually the netmask has all leading bits up to the prefix + * set so that the netmask is identical to having the first + * prefix bits of the address set. + * If that is not the case and there are "holes" in the + * mask, the prefix is determined based on the lowest bit + * set. * * Returns: the CIDR prefix represented by the netmask **/ guint32 nm_utils_ip4_netmask_to_prefix(guint32 netmask) { - G_STATIC_ASSERT_EXPR(__SIZEOF_INT__ == 4); - G_STATIC_ASSERT_EXPR(sizeof(int) == 4); - G_STATIC_ASSERT_EXPR(sizeof(netmask) == 4); - - return ((netmask != 0u) ? (guint32) (32 - __builtin_ctz(ntohl(netmask))) : 0u); + return _nm_utils_ip4_netmask_to_prefix(netmask); } /** * nm_utils_ip4_prefix_to_netmask: - * @prefix: a CIDR prefix + * @prefix: a CIDR prefix, must be not larger than 32. * * Returns: the netmask represented by the prefix, in network byte order **/ guint32 nm_utils_ip4_prefix_to_netmask(guint32 prefix) { + g_return_val_if_fail(prefix <= 32, 0xffffffffu); + return _nm_utils_ip4_prefix_to_netmask(prefix); } @@ -5356,7 +5359,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-impl/tests/test-general.c b/src/libnm-core-impl/tests/test-general.c index 1856f6ad..3c8cd3ba 100644 --- a/src/libnm-core-impl/tests/test-general.c +++ b/src/libnm-core-impl/tests/test-general.c @@ -1338,6 +1338,7 @@ typedef struct { static int _c_list_sort_cmp(const CList *lst_a, const CList *lst_b, const void *user_data) { + const int MODFIER = user_data ? GPOINTER_TO_INT(user_data) : 0; const CListSort *a, *b; g_assert(lst_a); @@ -1351,9 +1352,36 @@ _c_list_sort_cmp(const CList *lst_a, const CList *lst_b, const void *user_data) return -1; if (a->val > b->val) return 1; + + switch (MODFIER) { + case 0: + break; + case 1: + NM_CMP_DIRECT_PTR(a, b); + g_assert_not_reached(); + break; + case 2: + NM_CMP_DIRECT_PTR(b, a); + g_assert_not_reached(); + break; + default: + g_assert_not_reached(); + break; + } + return 0; } +static int +_c_list_sort_cmp_inverse(const CList *lst_a, const CList *lst_b, const void *user_data) +{ + int c; + + c = _c_list_sort_cmp(lst_b, lst_a, user_data); + g_assert(NM_IN_SET(c, -1, 0, 1)); + return c; +} + static void _do_test_c_list_sort(CListSort *elements, guint n_list, gboolean headless) { @@ -1411,8 +1439,9 @@ static void test_c_list_sort(void) { const guint N_ELEMENTS = 10000; - guint n_list, repeat; - gs_free CListSort *elements = NULL; + gs_free CListSort *elements = NULL; + guint n_list; + guint repeat; { CList head; @@ -1441,6 +1470,97 @@ test_c_list_sort(void) /*****************************************************************************/ +static void +_do_test_c_list_insert_sorted(CListSort *elements, guint n_list, bool append_equal) +{ + CList head; + guint i; + const CListSort *el_prev; + CListSort *el; + + c_list_init(&head); + for (i = 0; i < n_list; i++) { + el = &elements[i]; + el->val = nmtst_get_rand_uint32() % (2 * n_list); + + if (nmtst_get_rand_bool()) { + c_list_insert_sorted(&head, &el->lst, TRUE, append_equal, _c_list_sort_cmp, NULL); + } else { + c_list_insert_sorted(&head, + &el->lst, + FALSE, + append_equal, + _c_list_sort_cmp_inverse, + NULL); + } + + if (nmtst_get_rand_one_case_in(20)) { + nm_assert(c_list_is_sorted(&head, TRUE, _c_list_sort_cmp, NULL)); + if (append_equal) { + nm_assert(c_list_is_sorted(&head, TRUE, _c_list_sort_cmp, GINT_TO_POINTER(1))); + } else { + nm_assert(c_list_is_sorted(&head, TRUE, _c_list_sort_cmp, GINT_TO_POINTER(2))); + } + nm_assert(c_list_is_sorted(&head, FALSE, _c_list_sort_cmp_inverse, NULL)); + if (append_equal) { + nm_assert( + c_list_is_sorted(&head, FALSE, _c_list_sort_cmp_inverse, GINT_TO_POINTER(1))); + } else { + nm_assert( + c_list_is_sorted(&head, FALSE, _c_list_sort_cmp_inverse, GINT_TO_POINTER(2))); + } + } + } + + g_assert_cmpint(c_list_length(&head), ==, n_list); + g_assert(!c_list_length_is(&head, n_list - 1)); + g_assert(c_list_length_is(&head, n_list)); + g_assert(!c_list_length_is(&head, n_list + 1)); + + el_prev = NULL; + c_list_for_each_entry (el, &head, lst) { + if (el_prev) { + int c; + + c = _c_list_sort_cmp(&el_prev->lst, &el->lst, NULL); + g_assert_cmpint(c, <=, 0); + if (c == 0) { + if (append_equal) + g_assert(&el_prev->lst < &el->lst); + else + g_assert(&el_prev->lst > &el->lst); + } + } + el_prev = el; + } +} + +static void +test_c_list_insert_sorted(void) +{ + const guint N_ELEMENTS = 1000; + gs_free CListSort *elements = NULL; + guint n_list; + guint repeat; + + elements = g_new0(CListSort, N_ELEMENTS); + for (n_list = 1; n_list < N_ELEMENTS; n_list++) { + if (n_list > 150) { + n_list += nmtst_get_rand_uint32() % n_list; + if (n_list >= N_ELEMENTS) + break; + } + { + const guint N_REPEAT = n_list > 50 ? 1 : 5; + + for (repeat = 0; repeat < N_REPEAT; repeat++) + _do_test_c_list_insert_sorted(elements, n_list, nmtst_get_rand_bool()); + } + } +} + +/*****************************************************************************/ + typedef struct { NMDedupMultiObj parent; guint val; @@ -2381,12 +2501,18 @@ test_setting_ip_route_attributes(void) TEST_ATTR("tos", byte, 127, AF_INET, TRUE, TRUE); TEST_ATTR("tos", string, "0x28", AF_INET, FALSE, TRUE); + TEST_ATTR("advmss", uint32, 1400, AF_INET, TRUE, TRUE); + TEST_ATTR("advmss", string, "1400", AF_INET, FALSE, TRUE); + TEST_ATTR("cwnd", uint32, 10, AF_INET, TRUE, TRUE); TEST_ATTR("cwnd", string, "11", AF_INET, FALSE, TRUE); TEST_ATTR("lock-mtu", boolean, TRUE, AF_INET, TRUE, TRUE); TEST_ATTR("lock-mtu", uint32, 1, AF_INET, FALSE, TRUE); + TEST_ATTR("lock-advmss", boolean, TRUE, AF_INET, TRUE, TRUE); + TEST_ATTR("lock-advmss", boolean, TRUE, AF_INET6, TRUE, TRUE); + TEST_ATTR("from", string, "fd01::1", AF_INET6, TRUE, TRUE); TEST_ATTR("from", string, "fd01::1/64", AF_INET6, TRUE, TRUE); TEST_ATTR("from", string, "fd01::1/128", AF_INET6, TRUE, TRUE); @@ -2396,6 +2522,12 @@ test_setting_ip_route_attributes(void) TEST_ATTR("from", string, "1.2.3.4", AF_INET, FALSE, TRUE); TEST_ATTR("from", string, "1.2.3.4", AF_INET6, FALSE, TRUE); + TEST_ATTR("quickack", boolean, TRUE, AF_INET, TRUE, TRUE); + TEST_ATTR("quickack", boolean, TRUE, AF_INET6, TRUE, TRUE); + + TEST_ATTR("rto_min", uint32, 1000, AF_INET, TRUE, TRUE); + TEST_ATTR("rto_min", uint32, 1000, AF_INET6, TRUE, TRUE); + TEST_ATTR("src", string, "1.2.3.4", AF_INET, TRUE, TRUE); TEST_ATTR("src", string, "1.2.3.4", AF_INET6, FALSE, TRUE); TEST_ATTR("src", string, "1.2.3.0/24", AF_INET, FALSE, TRUE); @@ -3822,8 +3954,10 @@ test_connection_diff_a_only(void) {NM_SETTING_CONNECTION_MDNS, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_CONNECTION_LLMNR, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_CONNECTION_DNS_OVER_TLS, NM_SETTING_DIFF_RESULT_IN_A}, + {NM_SETTING_CONNECTION_MPTCP_FLAGS, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_CONNECTION_MUD_URL, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A}, + {NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY, NM_SETTING_DIFF_RESULT_IN_A}, {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN}}}, {NM_SETTING_WIRED_SETTING_NAME, { @@ -3872,6 +4006,7 @@ test_connection_diff_a_only(void) {NM_SETTING_IP_CONFIG_DHCP_IAID, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER, NM_SETTING_DIFF_RESULT_IN_A}, {NM_SETTING_IP_CONFIG_DHCP_REJECT_SERVERS, NM_SETTING_DIFF_RESULT_IN_A}, + {NM_SETTING_IP4_CONFIG_LINK_LOCAL, NM_SETTING_DIFF_RESULT_IN_A}, {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN}, }}, }; @@ -3914,11 +4049,11 @@ test_connection_diff_different(void) NMSettingIPConfig *s_ip4; gboolean same; const DiffSetting settings[] = { - {NM_SETTING_IP4_CONFIG_SETTING_NAME, - { - {NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_DIFF_RESULT_IN_A | NM_SETTING_DIFF_RESULT_IN_B}, - {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN}, + {NM_SETTING_IP4_CONFIG_SETTING_NAME, + { + {NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_DIFF_RESULT_IN_A | NM_SETTING_DIFF_RESULT_IN_B}, + {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN}, }}, }; @@ -3999,10 +4134,10 @@ test_connection_diff_inferrable(void) NMSettingIPConfig *s_ip4; char *uuid; const DiffSetting settings[] = { - {NM_SETTING_CONNECTION_SETTING_NAME, - { - {NM_SETTING_CONNECTION_INTERFACE_NAME, NM_SETTING_DIFF_RESULT_IN_A}, - {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN}, + {NM_SETTING_CONNECTION_SETTING_NAME, + { + {NM_SETTING_CONNECTION_INTERFACE_NAME, NM_SETTING_DIFF_RESULT_IN_A}, + {NULL, NM_SETTING_DIFF_RESULT_UNKNOWN}, }}, }; @@ -4923,7 +5058,7 @@ _netmask_to_prefix(guint32 netmask) /* we re-implemented the netmask-to-prefix code differently. Check * that they agree. */ - g_assert_cmpint(prefix, ==, nm_utils_ip4_netmask_to_prefix(netmask)); + g_assert_cmpint(prefix, ==, _nm_utils_ip4_netmask_to_prefix(netmask)); return prefix; } @@ -6722,53 +6857,53 @@ test_setting_ip6_gateway(void) GVariant *gateway_var; GVariantBuilder addrs_builder; guint8 addr_bytes_0[] = {0xab, - 0xcd, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x0a}; + 0xcd, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x0a}; guint8 addr_bytes_1[] = {0xab, - 0xcd, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x0b}; + 0xcd, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x0b}; guint8 gateway_bytes_1[] = {0xab, - 0xcd, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x01}; + 0xcd, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01}; GError *error = NULL; /* When serializing on the daemon side, ipv6.gateway is copied to the first @@ -10824,6 +10959,7 @@ main(int argc, char **argv) g_test_add_func("/core/general/test_nm_hash", test_nm_hash); g_test_add_func("/core/general/test_nm_g_slice_free_fcn", test_nm_g_slice_free_fcn); g_test_add_func("/core/general/test_c_list_sort", test_c_list_sort); + g_test_add_func("/core/general/test_c_list_insert_sorted", test_c_list_insert_sorted); g_test_add_func("/core/general/test_dedup_multi", test_dedup_multi); g_test_add_func("/core/general/test_utils_str_utf8safe", test_utils_str_utf8safe); g_test_add_func("/core/general/test_nm_strsplit_set", test_nm_strsplit_set); diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index 788f218d..5bdae716 100644 --- a/src/libnm-core-impl/tests/test-setting.c +++ b/src/libnm-core-impl/tests/test-setting.c @@ -3596,7 +3596,7 @@ test_roundtrip_conversion(gconstpointer test_data) "method=auto\n" "\n" "[ipv6]\n" - "addr-gen-mode=stable-privacy\n" + "addr-gen-mode=default\n" "method=auto\n" "\n" "[proxy]\n" @@ -3623,7 +3623,7 @@ test_roundtrip_conversion(gconstpointer test_data) "method=auto\n" "\n" "[ipv6]\n" - "addr-gen-mode=stable-privacy\n" + "addr-gen-mode=default\n" "method=auto\n" "", ID, @@ -3660,7 +3660,7 @@ test_roundtrip_conversion(gconstpointer test_data) "method=disabled\n" "\n" "[ipv6]\n" - "addr-gen-mode=stable-privacy\n" + "addr-gen-mode=default\n" "method=disabled\n" "\n" "[proxy]\n" @@ -3714,7 +3714,7 @@ test_roundtrip_conversion(gconstpointer test_data) "method=disabled\n" "\n" "[ipv6]\n" - "addr-gen-mode=stable-privacy\n" + "addr-gen-mode=default\n" "method=disabled\n" "\n" "[proxy]\n" @@ -3795,7 +3795,7 @@ test_roundtrip_conversion(gconstpointer test_data) "routing-rule3=priority 3 from 192.168.2.0/26 table 1002\n" "\n" "[ipv6]\n" - "addr-gen-mode=stable-privacy\n" + "addr-gen-mode=default\n" "method=auto\n" "routing-rule1=priority 1 from ::/0 table 1000\n" "routing-rule2=priority 2 from 1:2:3:b::/65 table 1001\n" diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index 032f6a9a..ee4cc25b 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" /*****************************************************************************/ @@ -519,6 +517,10 @@ NMConnectionMultiConnect _nm_connection_get_multi_connect(NMConnection *connecti gboolean _nm_setting_bond_option_supported(const char *option, NMBondMode mode); +guint32 _nm_setting_bond_opt_value_as_u32(NMSettingBond *s_bond, const char *opt); +guint16 _nm_setting_bond_opt_value_as_u16(NMSettingBond *s_bond, const char *opt); +guint8 _nm_setting_bond_opt_value_as_u8(NMSettingBond *s_bond, const char *opt); + /*****************************************************************************/ GPtrArray *_nm_setting_bridge_get_vlans(NMSettingBridge *setting); diff --git a/src/libnm-core-intern/nm-keyfile-utils.h b/src/libnm-core-intern/nm-keyfile-utils.h index f79f020f..08f169ac 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-dbus-interface.h b/src/libnm-core-public/nm-dbus-interface.h index 94622793..a980f5aa 100644 --- a/src/libnm-core-public/nm-dbus-interface.h +++ b/src/libnm-core-public/nm-dbus-interface.h @@ -1315,4 +1315,49 @@ typedef enum /*< flags >*/ { NM_RADIO_FLAG_WWAN_AVAILABLE = 0x2, } NMRadioFlags; +/** + * NMMptcpFlags: + * @NM_MPTCP_FLAGS_NONE: The default, meaning that no MPTCP flags are set. + * @NM_MPTCP_FLAGS_DISABLED: don't configure MPTCP endpoints on the device. + * @NM_MPTCP_FLAGS_ENABLED_ON_GLOBAL_IFACE: MPTCP handling is enabled + * or disabled depending on whether a /0 default route (either IPv4 or IPv6) is + * configured in the main routing table. + * @NM_MPTCP_FLAGS_ENABLED: MPTCP is enabled and endpoints will be configured. + * This flag is implied if any of the other flags indicate that + * MPTCP is enabled and therefore in most cases unnecessary. + * @NM_MPTCP_FLAGS_SIGNAL: Flag for the MPTCP endpoint. The endpoint will be + * announced/signaled to each peer via an MPTCP ADD_ADDR sub-option. + * @NM_MPTCP_FLAGS_SUBFLOW: Flag for the MPTCP endpoint. If additional subflow creation + * is allowed by the MPTCP limits, the MPTCP path manager will try to create an + * additional subflow using this endpoint as the source address after the MPTCP connection + * is established. + * @NM_MPTCP_FLAGS_BACKUP: Flag for the MPTCP endpoint. If this is a subflow endpoint, the + * subflows created using this endpoint will have the backup flag set during the connection + * process. This flag instructs the peer to only send data on a given subflow when all + * non-backup subflows are unavailable. This does not affect outgoing data, + * where subflow priority is determined by the backup/non-backup flag received + * from the peer + * @NM_MPTCP_FLAGS_FULLMESH: Flag for the MPTCP endpoint. If this is a subflow endpoint and additional + * subflow creation is allowed by the MPTCP limits, the MPTCP path manager will try to create an + * additional subflow for each known peer address, using this endpoint as the source address. + * This will occur after the MPTCP connection is established. If the peer did not announce + * any additional addresses using the MPTCP ADD_ADDR sub-option, this will behave the same + * as a plain subflow endpoint. When the peer does announce addresses, each received ADD_ADDR + * sub-option will trigger creation of an additional subflow to generate a full mesh topology. + * + * Since: 1.40 + */ +typedef enum /*< flags >*/ { + NM_MPTCP_FLAGS_NONE = 0, + + NM_MPTCP_FLAGS_DISABLED = 0x1, + NM_MPTCP_FLAGS_ENABLED_ON_GLOBAL_IFACE = 0x2, + NM_MPTCP_FLAGS_ENABLED = 0x4, + + NM_MPTCP_FLAGS_SIGNAL = 0x10, + NM_MPTCP_FLAGS_SUBFLOW = 0x20, + NM_MPTCP_FLAGS_BACKUP = 0x40, + NM_MPTCP_FLAGS_FULLMESH = 0x80, +} NMMptcpFlags; + #endif /* __NM_DBUS_INTERFACE_H__ */ diff --git a/src/libnm-core-public/nm-dbus-types.xml b/src/libnm-core-public/nm-dbus-types.xml index f28ac4cc..0c8425ef 100644 --- a/src/libnm-core-public/nm-dbus-types.xml +++ b/src/libnm-core-public/nm-dbus-types.xml @@ -2223,4 +2223,64 @@ + + enum NMMptcpFlags + + NMMptcpFlags + + Since: 1.40 + + Values + + + + + + + + NM_MPTCP_FLAGS_NONE + = 0 + The default, meaning that no MPTCP flags are set. + + + NM_MPTCP_FLAGS_DISABLED + = 0x1 + don't configure MPTCP endpoints on the device. + + + NM_MPTCP_FLAGS_ENABLED_ON_GLOBAL_IFACE + = 0x2 + MPTCP handling is enabled or disabled depending on whether a /0 default route (either IPv4 or IPv6) is configured in the main routing table. + + + NM_MPTCP_FLAGS_ENABLED + = 0x4 + MPTCP is enabled and endpoints will be configured. This flag is implied if any of the other flags indicate that MPTCP is enabled and therefore in most cases unnecessary. + + + NM_MPTCP_FLAGS_SIGNAL + = 0x10 + Flag for the MPTCP endpoint. The endpoint will be announced/signaled to each peer via an MPTCP ADD_ADDR sub-option. + + + NM_MPTCP_FLAGS_SUBFLOW + = 0x20 + Flag for the MPTCP endpoint. If additional subflow creation is allowed by the MPTCP limits, the MPTCP path manager will try to create an additional subflow using this endpoint as the source address after the MPTCP connection is established. + + + NM_MPTCP_FLAGS_BACKUP + = 0x40 + Flag for the MPTCP endpoint. If this is a subflow endpoint, the subflows created using this endpoint will have the backup flag set during the connection process. This flag instructs the peer to only send data on a given subflow when all non-backup subflows are unavailable. This does not affect outgoing data, where subflow priority is determined by the backup/non-backup flag received from the peer + + + NM_MPTCP_FLAGS_FULLMESH + = 0x80 + Flag for the MPTCP endpoint. If this is a subflow endpoint and additional subflow creation is allowed by the MPTCP limits, the MPTCP path manager will try to create an additional subflow for each known peer address, using this endpoint as the source address. This will occur after the MPTCP connection is established. If the peer did not announce any additional addresses using the MPTCP ADD_ADDR sub-option, this will behave the same as a plain subflow endpoint. When the peer does announce addresses, each received ADD_ADDR sub-option will trigger creation of an additional subflow to generate a full mesh topology. + + + + + + + diff --git a/src/libnm-core-public/nm-setting-connection.h b/src/libnm-core-public/nm-setting-connection.h index 83b5fd34..4b6ce17c 100644 --- a/src/libnm-core-public/nm-setting-connection.h +++ b/src/libnm-core-public/nm-setting-connection.h @@ -33,32 +33,34 @@ G_BEGIN_DECLS #define NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MAX 999 #define NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_DEFAULT 0 -#define NM_SETTING_CONNECTION_ID "id" -#define NM_SETTING_CONNECTION_UUID "uuid" -#define NM_SETTING_CONNECTION_STABLE_ID "stable-id" -#define NM_SETTING_CONNECTION_INTERFACE_NAME "interface-name" -#define NM_SETTING_CONNECTION_TYPE "type" -#define NM_SETTING_CONNECTION_AUTOCONNECT "autoconnect" -#define NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY "autoconnect-priority" -#define NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES "autoconnect-retries" -#define NM_SETTING_CONNECTION_MULTI_CONNECT "multi-connect" -#define NM_SETTING_CONNECTION_TIMESTAMP "timestamp" -#define NM_SETTING_CONNECTION_READ_ONLY "read-only" -#define NM_SETTING_CONNECTION_PERMISSIONS "permissions" -#define NM_SETTING_CONNECTION_ZONE "zone" -#define NM_SETTING_CONNECTION_MASTER "master" -#define NM_SETTING_CONNECTION_SLAVE_TYPE "slave-type" -#define NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES "autoconnect-slaves" -#define NM_SETTING_CONNECTION_SECONDARIES "secondaries" -#define NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT "gateway-ping-timeout" -#define NM_SETTING_CONNECTION_METERED "metered" -#define NM_SETTING_CONNECTION_LLDP "lldp" -#define NM_SETTING_CONNECTION_AUTH_RETRIES "auth-retries" -#define NM_SETTING_CONNECTION_MDNS "mdns" -#define NM_SETTING_CONNECTION_LLMNR "llmnr" -#define NM_SETTING_CONNECTION_DNS_OVER_TLS "dns-over-tls" -#define NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT "wait-device-timeout" -#define NM_SETTING_CONNECTION_MUD_URL "mud-url" +#define NM_SETTING_CONNECTION_ID "id" +#define NM_SETTING_CONNECTION_UUID "uuid" +#define NM_SETTING_CONNECTION_STABLE_ID "stable-id" +#define NM_SETTING_CONNECTION_INTERFACE_NAME "interface-name" +#define NM_SETTING_CONNECTION_TYPE "type" +#define NM_SETTING_CONNECTION_AUTOCONNECT "autoconnect" +#define NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY "autoconnect-priority" +#define NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES "autoconnect-retries" +#define NM_SETTING_CONNECTION_MULTI_CONNECT "multi-connect" +#define NM_SETTING_CONNECTION_TIMESTAMP "timestamp" +#define NM_SETTING_CONNECTION_READ_ONLY "read-only" +#define NM_SETTING_CONNECTION_PERMISSIONS "permissions" +#define NM_SETTING_CONNECTION_ZONE "zone" +#define NM_SETTING_CONNECTION_MASTER "master" +#define NM_SETTING_CONNECTION_SLAVE_TYPE "slave-type" +#define NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES "autoconnect-slaves" +#define NM_SETTING_CONNECTION_SECONDARIES "secondaries" +#define NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT "gateway-ping-timeout" +#define NM_SETTING_CONNECTION_METERED "metered" +#define NM_SETTING_CONNECTION_LLDP "lldp" +#define NM_SETTING_CONNECTION_AUTH_RETRIES "auth-retries" +#define NM_SETTING_CONNECTION_MDNS "mdns" +#define NM_SETTING_CONNECTION_LLMNR "llmnr" +#define NM_SETTING_CONNECTION_DNS_OVER_TLS "dns-over-tls" +#define NM_SETTING_CONNECTION_MPTCP_FLAGS "mptcp-flags" +#define NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT "wait-device-timeout" +#define NM_SETTING_CONNECTION_MUD_URL "mud-url" +#define NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY "wait-activation-delay" /* Types for property values */ /** @@ -215,9 +217,15 @@ NMSettingConnectionLlmnr nm_setting_connection_get_llmnr(NMSettingConnection *se NM_AVAILABLE_IN_1_34 NMSettingConnectionDnsOverTls nm_setting_connection_get_dns_over_tls(NMSettingConnection *setting); +NM_AVAILABLE_IN_1_40 +NMMptcpFlags nm_setting_connection_get_mptcp_flags(NMSettingConnection *setting); + NM_AVAILABLE_IN_1_20 gint32 nm_setting_connection_get_wait_device_timeout(NMSettingConnection *setting); +NM_AVAILABLE_IN_1_40 +gint32 nm_setting_connection_get_wait_activation_delay(NMSettingConnection *setting); + NM_AVAILABLE_IN_1_26 const char *nm_setting_connection_get_mud_url(NMSettingConnection *setting); diff --git a/src/libnm-core-public/nm-setting-ip-config.h b/src/libnm-core-public/nm-setting-ip-config.h index 257a687a..6283ecc9 100644 --- a/src/libnm-core-public/nm-setting-ip-config.h +++ b/src/libnm-core-public/nm-setting-ip-config.h @@ -123,10 +123,12 @@ gboolean nm_ip_route_attribute_validate(const char *name, gboolean *known, GError **error); +#define NM_IP_ROUTE_ATTRIBUTE_ADVMSS "advmss" #define NM_IP_ROUTE_ATTRIBUTE_CWND "cwnd" #define NM_IP_ROUTE_ATTRIBUTE_FROM "from" #define NM_IP_ROUTE_ATTRIBUTE_INITCWND "initcwnd" #define NM_IP_ROUTE_ATTRIBUTE_INITRWND "initrwnd" +#define NM_IP_ROUTE_ATTRIBUTE_LOCK_ADVMSS "lock-advmss" #define NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND "lock-cwnd" #define NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND "lock-initcwnd" #define NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND "lock-initrwnd" @@ -134,6 +136,8 @@ gboolean nm_ip_route_attribute_validate(const char *name, #define NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW "lock-window" #define NM_IP_ROUTE_ATTRIBUTE_MTU "mtu" #define NM_IP_ROUTE_ATTRIBUTE_ONLINK "onlink" +#define NM_IP_ROUTE_ATTRIBUTE_QUICKACK "quickack" +#define NM_IP_ROUTE_ATTRIBUTE_RTO_MIN "rto_min" #define NM_IP_ROUTE_ATTRIBUTE_SCOPE "scope" #define NM_IP_ROUTE_ATTRIBUTE_SRC "src" #define NM_IP_ROUTE_ATTRIBUTE_TABLE "table" diff --git a/src/libnm-core-public/nm-setting-ip4-config.h b/src/libnm-core-public/nm-setting-ip4-config.h index d0bd836d..7991d682 100644 --- a/src/libnm-core-public/nm-setting-ip4-config.h +++ b/src/libnm-core-public/nm-setting-ip4-config.h @@ -32,6 +32,7 @@ G_BEGIN_DECLS #define NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID "dhcp-client-id" #define NM_SETTING_IP4_CONFIG_DHCP_FQDN "dhcp-fqdn" #define NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER "dhcp-vendor-class-identifier" +#define NM_SETTING_IP4_CONFIG_LINK_LOCAL "link-local" /** * NM_SETTING_IP4_CONFIG_METHOD_AUTO: @@ -77,6 +78,28 @@ G_BEGIN_DECLS */ #define NM_SETTING_IP4_CONFIG_METHOD_DISABLED "disabled" +/** + * NMSettingIP4LinkLocal: + * @NM_SETTING_IP4_LL_DEFAULT: Allow fallback to a globally configured default. If unspecified, + * fallback to "auto". Note that if "ipv4.method" is "disabled", this always implies link-local + * addresses disabled too. + * @NM_SETTING_IP4_LL_AUTO: Special value which enables LL if "ipv4.method" is set to + * "link-local". + * @NM_SETTING_IP4_LL_DISABLED: Disable IPv4 link-local protocol. + * @NM_SETTING_IP4_LL_ENABLED: Enable the IPv4 link-local protocol regardless what other protocols + * such as DHCP or manually assigned IP addresses might be active. + * + * #NMSettingIP4LinkLocal values indicate whether IPv4 link-local address protocol should be enabled. + * + * Since: 1.40 + */ +typedef enum { + NM_SETTING_IP4_LL_DEFAULT = 0, + NM_SETTING_IP4_LL_AUTO = 1, + NM_SETTING_IP4_LL_DISABLED = 2, + NM_SETTING_IP4_LL_ENABLED = 3, +} NMSettingIP4LinkLocal; + typedef struct _NMSettingIP4ConfigClass NMSettingIP4ConfigClass; GType nm_setting_ip4_config_get_type(void); @@ -90,6 +113,9 @@ const char *nm_setting_ip4_config_get_dhcp_fqdn(NMSettingIP4Config *setting); NM_AVAILABLE_IN_1_28 const char *nm_setting_ip4_config_get_dhcp_vendor_class_identifier(NMSettingIP4Config *setting); +NM_AVAILABLE_IN_1_40 +NMSettingIP4LinkLocal nm_setting_ip4_config_get_link_local(NMSettingIP4Config *setting); + G_END_DECLS #endif /* __NM_SETTING_IP4_CONFIG_H__ */ diff --git a/src/libnm-core-public/nm-setting-ip6-config.h b/src/libnm-core-public/nm-setting-ip6-config.h index c51a7438..5abc173d 100644 --- a/src/libnm-core-public/nm-setting-ip6-config.h +++ b/src/libnm-core-public/nm-setting-ip6-config.h @@ -38,6 +38,8 @@ G_BEGIN_DECLS #define NM_SETTING_IP6_CONFIG_RA_TIMEOUT "ra-timeout" +#define NM_SETTING_IP6_CONFIG_MTU "mtu" + /** * NM_SETTING_IP6_CONFIG_METHOD_IGNORE: * @@ -128,6 +130,10 @@ typedef enum { * is created by using a cryptographically secure hash of a secret host-specific * key along with the connection identification and the network address as * specified by RFC7217. + * @NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64: Fallback to the global + * default, and if unspecified use "eui64". Since: 1.40. + * @NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT: Fallback to the global + * default, and if unspecified use "stable-privacy". Since: 1.40. * * #NMSettingIP6ConfigAddrGenMode controls how the Interface Identifier for * RFC4862 Stateless Address Autoconfiguration is created. @@ -135,8 +141,10 @@ typedef enum { * Since: 1.2 */ typedef enum { - NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 = 0, - NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY = 1, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 = 0, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY = 1, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64 = 2, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT = 3, } NMSettingIP6ConfigAddrGenMode; typedef struct _NMSettingIP6ConfigClass NMSettingIP6ConfigClass; @@ -154,6 +162,8 @@ NM_AVAILABLE_IN_1_12 const char *nm_setting_ip6_config_get_dhcp_duid(NMSettingIP6Config *setting); NM_AVAILABLE_IN_1_24 gint32 nm_setting_ip6_config_get_ra_timeout(NMSettingIP6Config *setting); +NM_AVAILABLE_IN_1_40 +guint32 nm_setting_ip6_config_get_mtu(NMSettingIP6Config *setting); G_END_DECLS diff --git a/src/libnm-core-public/nm-version-macros.h b/src/libnm-core-public/nm-version-macros.h index dc226441..f61f68b7 100644 --- a/src/libnm-core-public/nm-version-macros.h +++ b/src/libnm-core-public/nm-version-macros.h @@ -22,7 +22,7 @@ * Evaluates to the minor version number of NetworkManager which this source * is compiled against. */ -#define NM_MINOR_VERSION (38) +#define NM_MINOR_VERSION (39) /** * NM_MICRO_VERSION: @@ -30,7 +30,7 @@ * Evaluates to the micro version number of NetworkManager which this source * compiled against. */ -#define NM_MICRO_VERSION (4) +#define NM_MICRO_VERSION (90) /** * NM_CHECK_VERSION: @@ -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-macros.h.in b/src/libnm-core-public/nm-version-macros.h.in index 516aded5..07e79899 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 ac98f868..9f6e3e78 100644 --- a/src/libnm-core-public/nm-version.h +++ b/src/libnm-core-public/nm-version.h @@ -327,9 +327,23 @@ #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 + * https://networkmanager.dev/docs/libnm/latest/usage.html#sync-api * * Note that "deprecated" here does not really mean that the API is going * to be removed. We don't break API. Just comment that it is awkward and diff --git a/src/libnm-core-public/nm-vpn-dbus-interface.h b/src/libnm-core-public/nm-vpn-dbus-interface.h index 518999dd..423a9212 100644 --- a/src/libnm-core-public/nm-vpn-dbus-interface.h +++ b/src/libnm-core-public/nm-vpn-dbus-interface.h @@ -273,7 +273,7 @@ typedef enum { */ #define NM_VPN_PLUGIN_IP6_CONFIG_PTP "ptp" -/* uint32: prefix length of the VPN interface; 1 - 128 inclusive */ +/* uint32: prefix length of the VPN interface; 0 - 128 inclusive */ #define NM_VPN_PLUGIN_IP6_CONFIG_PREFIX "prefix" /* array of array of uint8: IP addresses of DNS servers for the VPN (network byte order) */ diff --git a/src/libnm-glib-aux/nm-default-glib.h b/src/libnm-glib-aux/nm-default-glib.h index 9d04ddc4..f39e16cc 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 3b9b7e8d..b7f7a3f6 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-errno.c b/src/libnm-glib-aux/nm-errno.c index 14d93d64..b76386a6 100644 --- a/src/libnm-glib-aux/nm-errno.c +++ b/src/libnm-glib-aux/nm-errno.c @@ -28,6 +28,7 @@ static NM_UTILS_LOOKUP_STR_DEFINE( NM_UTILS_LOOKUP_STR_ITEM(NME_NL_ATTRSIZE, "NME_NL_ATTRSIZE"), NM_UTILS_LOOKUP_STR_ITEM(NME_NL_BAD_SOCK, "NME_NL_BAD_SOCK"), NM_UTILS_LOOKUP_STR_ITEM(NME_NL_DUMP_INTR, "NME_NL_DUMP_INTR"), + NM_UTILS_LOOKUP_STR_ITEM(NME_NL_MSG_INVAL, "NME_NL_MSG_INVAL"), NM_UTILS_LOOKUP_STR_ITEM(NME_NL_MSG_OVERFLOW, "NME_NL_MSG_OVERFLOW"), NM_UTILS_LOOKUP_STR_ITEM(NME_NL_MSG_TOOSHORT, "NME_NL_MSG_TOOSHORT"), NM_UTILS_LOOKUP_STR_ITEM(NME_NL_MSG_TRUNC, "NME_NL_MSG_TRUNC"), diff --git a/src/libnm-glib-aux/nm-errno.h b/src/libnm-glib-aux/nm-errno.h index 62c8379f..f893a528 100644 --- a/src/libnm-glib-aux/nm-errno.h +++ b/src/libnm-glib-aux/nm-errno.h @@ -39,6 +39,7 @@ enum _NMErrno { /* netlink errors. */ NME_NL_SEQ_MISMATCH, + NME_NL_MSG_INVAL, NME_NL_MSG_TRUNC, NME_NL_MSG_TOOSHORT, NME_NL_DUMP_INTR, diff --git a/src/libnm-glib-aux/nm-glib.h b/src/libnm-glib-aux/nm-glib.h index f3be3b32..2dc86d7b 100644 --- a/src/libnm-glib-aux/nm-glib.h +++ b/src/libnm-glib-aux/nm-glib.h @@ -307,6 +307,33 @@ _nm_g_ptr_array_insert(GPtrArray *array, int index_, gpointer data) /*****************************************************************************/ +#if !GLIB_CHECK_VERSION(2, 54, 0) +static inline gboolean +g_ptr_array_find(GPtrArray *haystack, gconstpointer needle, guint *index_) +{ + guint i; + g_return_val_if_fail(haystack, FALSE); + + for (i = 0; i < haystack->len; i++) { + if (haystack->pdata[i] == needle) { + if (index_) + *index_ = i; + return TRUE; + } + } + return FALSE; +} +#else +#define g_ptr_array_find(haystack, needle, index_) \ + ({ \ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS \ + g_ptr_array_find(haystack, needle, index_); \ + G_GNUC_END_IGNORE_DEPRECATIONS \ + }) +#endif + +/*****************************************************************************/ + #if !GLIB_CHECK_VERSION(2, 40, 0) static inline gboolean _g_key_file_save_to_file(GKeyFile *key_file, const char *filename, GError **error) diff --git a/src/libnm-glib-aux/nm-hash-utils.h b/src/libnm-glib-aux/nm-hash-utils.h index b7ee4dd1..dffa828b 100644 --- a/src/libnm-glib-aux/nm-hash-utils.h +++ b/src/libnm-glib-aux/nm-hash-utils.h @@ -122,26 +122,26 @@ nm_hash_update_bool(NMHashState *state, bool val) nm_hash_update(state, &val, sizeof(val)); } -#define _NM_HASH_COMBINE_BOOLS_OP(x, n) ((x) ? NM_BIT((n)) : 0u) +#define _NM_HASH_COMBINE_BOOLS_OP(x, n, op_arg) ((x) ? NM_BIT((n)) : 0ull) -#define NM_HASH_COMBINE_BOOLS(type, ...) \ - ((type) (NM_STATIC_ASSERT_EXPR_1(NM_NARG(__VA_ARGS__) <= 8 * sizeof(type)) \ - ? (NM_VA_ARGS_FOREACH(, , |, _NM_HASH_COMBINE_BOOLS_OP, __VA_ARGS__)) \ - : 0)) +#define NM_HASH_COMBINE_BOOLS(type, ...) \ + ((type) (NM_STATIC_ASSERT_EXPR_1(NM_NARG(__VA_ARGS__) <= 8 * sizeof(type)) \ + ? (NM_VA_ARGS_FOREACH(, , |, _NM_HASH_COMBINE_BOOLS_OP, , __VA_ARGS__)) \ + : 0ull)) #define nm_hash_update_bools(state, ...) \ nm_hash_update_val(state, NM_HASH_COMBINE_BOOLS(guint8, __VA_ARGS__)) -#define _NM_HASH_COMBINE_VALS_TYPE_OP(x, idx) typeof(x) _v##idx; -#define _NM_HASH_COMBINE_VALS_INIT_OP(x, idx) ._v##idx = (x), +#define _NM_HASH_COMBINE_VALS_TYPE_OP(x, idx, op_arg) typeof(x) _v##idx; +#define _NM_HASH_COMBINE_VALS_INIT_OP(x, idx, op_arg) ._v##idx = (x), /* NM_HASH_COMBINE_VALS() is faster then nm_hash_update_val() as it combines multiple * calls to nm_hash_update() using a packed structure. */ -#define NM_HASH_COMBINE_VALS(var, ...) \ - const struct _nm_packed { \ - NM_VA_ARGS_FOREACH(, , , _NM_HASH_COMBINE_VALS_TYPE_OP, __VA_ARGS__) \ - } var _nm_alignas(guint64) = { \ - NM_VA_ARGS_FOREACH(, , , _NM_HASH_COMBINE_VALS_INIT_OP, __VA_ARGS__)} +#define NM_HASH_COMBINE_VALS(var, ...) \ + const struct _nm_packed { \ + NM_VA_ARGS_FOREACH(, , , _NM_HASH_COMBINE_VALS_TYPE_OP, , __VA_ARGS__) \ + } var _nm_alignas(max_align_t) = { \ + NM_VA_ARGS_FOREACH(, , , _NM_HASH_COMBINE_VALS_INIT_OP, , __VA_ARGS__)} /* nm_hash_update_vals() is faster then nm_hash_update_val() as it combines multiple * calls to nm_hash_update() using a packed structure. */ diff --git a/src/libnm-glib-aux/nm-io-utils.c b/src/libnm-glib-aux/nm-io-utils.c index 503f044f..0823a16c 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 a8503986..ef015153 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-logging-fwd.h b/src/libnm-glib-aux/nm-logging-fwd.h index 0e715c50..72e5723c 100644 --- a/src/libnm-glib-aux/nm-logging-fwd.h +++ b/src/libnm-glib-aux/nm-logging-fwd.h @@ -59,7 +59,16 @@ typedef enum { LOGD_IP = LOGD_IP4 | LOGD_IP6, #define LOGD_DHCPX(is_ipv4) ((is_ipv4) ? LOGD_DHCP4 : LOGD_DHCP6) -#define LOGD_IPX(is_ipv4) ((is_ipv4) ? LOGD_IP4 : LOGD_IP6) + +#define LOGD_DHCP_af(addr_family) \ + ({ \ + const int _addr_family_1 = (addr_family); \ + \ + (_addr_family_1 == AF_UNSPEC ? LOGD_DHCP \ + : (NM_IS_IPv4(_addr_family_1) ? LOGD_DHCP4 : LOGD_DHCP6)); \ + }) + +#define LOGD_IPX(is_ipv4) ((is_ipv4) ? LOGD_IP4 : LOGD_IP6) } NMLogDomain; diff --git a/src/libnm-glib-aux/nm-macros-internal.h b/src/libnm-glib-aux/nm-macros-internal.h index 7cc8ac97..f2a4461e 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); \ @@ -1177,7 +1195,7 @@ _NM_IN_STRSET_EVAL_op_streq_ascii_case(const char *x1, const char *x) return x && g_ascii_strcasecmp(x1, x) == 0; } -#define _NM_IN_STRSET_EVAL_OP_STREQ_ASCII_CASE(x, idx) \ +#define _NM_IN_STRSET_EVAL_OP_STREQ_ASCII_CASE(x, idx, op_arg) \ _NM_IN_STRSET_EVAL_op_streq_ascii_case(_x1, x) #define NM_IN_STRSET_ASCII_CASE(x1, ...) \ _NM_IN_STRSET_EVAL(||, _NM_IN_STRSET_EVAL_OP_STREQ_ASCII_CASE, x1, __VA_ARGS__) diff --git a/src/libnm-glib-aux/nm-ref-string.h b/src/libnm-glib-aux/nm-ref-string.h index 3363bce0..eb3c38de 100644 --- a/src/libnm-glib-aux/nm-ref-string.h +++ b/src/libnm-glib-aux/nm-ref-string.h @@ -119,7 +119,7 @@ nm_ref_string_cmp(NMRefString *a, NMRefString *b) NM_CMP_SELF(a, b); /* It would be cheaper to first compare by length. But this - * way we get a nicer, ASCIIbethical sort order. */ + * way we get a nicer, ASCIIbetical sort order. */ NM_CMP_DIRECT_MEMCMP(a->str, b->str, NM_MIN(a->len, b->len)); NM_CMP_DIRECT(a->len, b->len); return nm_assert_unreachable_val(0); diff --git a/src/libnm-glib-aux/nm-shared-utils.c b/src/libnm-glib-aux/nm-shared-utils.c index f770b96d..624f9a3e 100644 --- a/src/libnm-glib-aux/nm-shared-utils.c +++ b/src/libnm-glib-aux/nm-shared-utils.c @@ -44,6 +44,15 @@ G_STATIC_ASSERT(_nm_alignof(struct in_addr) <= _nm_alignof(NMIPAddr)); G_STATIC_ASSERT(_nm_alignof(struct in6_addr) <= _nm_alignof(NMIPAddr)); G_STATIC_ASSERT(_nm_alignof(NMEtherAddr) <= _nm_alignof(NMIPAddr)); +int +nm_ip_addr_cmp_for_sort(gconstpointer a, gconstpointer b, gpointer user_data) +{ + /* This is a compare function that can be used for sorting IP addresses. + * Essentially, it calls memcmp(). @user_data must be GINT_TO_POINTER(addr_family). + * @a and @b must be either pointers to in_addr_t, struct in6_addr or NMIPAddr. */ + return nm_ip_addr_cmp(GPOINTER_TO_INT(user_data), a, b); +} + /* 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 @@ -137,6 +146,18 @@ G_STATIC_ASSERT(ETH_ALEN == sizeof(NMEtherAddr)); G_STATIC_ASSERT(_nm_alignof(struct ether_addr) <= _nm_alignof(NMEtherAddr)); +NMEtherAddr * +nm_ether_addr_from_string(NMEtherAddr *addr, const char *str) +{ + nm_assert(addr); + + if (!str || !_nm_utils_hwaddr_aton_exact(str, addr, ETH_ALEN)) { + *addr = NM_ETHER_ADDR_INIT(0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + return NULL; + } + + return addr; +} /*****************************************************************************/ /** @@ -994,12 +1015,22 @@ nm_utils_ip_is_site_local(int addr_family, const void *address) return (addr4 & 0xff000000) == 0x0a000000 || (addr4 & 0xfff00000) == 0xac100000 || (addr4 & 0xffff0000) == 0xc0a80000; case AF_INET6: + /* IN6_IS_ADDR_SITELOCAL() is for deprecated fec0::/10 addresses (see rfc3879, 4.). + * Note that for unique local IPv6 addresses (ULA, fc00::/7) this returns false, + * which may or may not be a bug. */ return IN6_IS_ADDR_SITELOCAL(address); default: g_return_val_if_reached(FALSE); } } +gboolean +nm_utils_ip6_is_ula(const struct in6_addr *address) +{ + /* Unique local IPv6 address (ULA) fc00::/7 */ + return (address->s6_addr32[0] & htonl(0xfe000000u)) == htonl(0xfc000000u); +} + /*****************************************************************************/ static gboolean @@ -2288,9 +2319,11 @@ nm_utils_escaped_tokens_options_split(char *str, const char **out_key, const cha char ** nm_utils_strsplit_quoted(const char *str) { - gs_unref_ptrarray GPtrArray *arr = NULL; - gs_free char *str_out = NULL; - CharLookupTable ch_lookup; + char **arr = NULL; + gsize arr_len = 0; + gsize arr_alloc = 0; + gs_free char *str_out = NULL; + CharLookupTable ch_lookup; nm_assert(str); @@ -2347,19 +2380,32 @@ nm_utils_strsplit_quoted(const char *str) str++; } - if (!arr) - arr = g_ptr_array_new(); - g_ptr_array_add(arr, g_strndup(str_out, j)); + if (arr_len >= arr_alloc) { + if (arr_alloc == 0) + arr_alloc = 4; + else + arr_alloc *= 2; + arr = g_realloc(arr, sizeof(char *) * arr_alloc); + } + + arr[arr_len++] = g_strndup(str_out, j); } if (!arr) return g_new0(char *, 1); - g_ptr_array_add(arr, NULL); - /* We want to return an optimally sized strv array, with no excess * memory allocated. Hence, clone once more. */ - return nm_memdup(arr->pdata, sizeof(char *) * arr->len); + + if (arr_len + 1u != arr_alloc) { + gs_free char **arr_old = arr; + + arr = g_new(char *, arr_len + 1u); + memcpy(arr, arr_old, sizeof(char *) * arr_len); + } + + arr[arr_len] = NULL; + return arr; } /*****************************************************************************/ @@ -3008,7 +3054,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; @@ -3175,7 +3221,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 { @@ -3451,51 +3497,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, @@ -3645,6 +3646,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; +} + /*****************************************************************************/ /** @@ -5859,17 +5906,29 @@ _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; } void -nm_str_buf_append_printf(NMStrBuf *strbuf, const char *format, ...) +nm_str_buf_append_printfv(NMStrBuf *strbuf, const char *format, va_list args) { - va_list args; + va_list args_copy; gsize available; int l; @@ -5879,12 +5938,12 @@ nm_str_buf_append_printf(NMStrBuf *strbuf, const char *format, ...) nm_assert(available < G_MAXULONG); - va_start(args, format); + va_copy(args_copy, args); l = g_vsnprintf(strbuf->_priv_allocated > 0 ? &strbuf->_priv_str[strbuf->_priv_len] : NULL, available, format, - args); - va_end(args); + args_copy); + va_end(args_copy); nm_assert(l >= 0); nm_assert(l < G_MAXINT); @@ -5899,9 +5958,9 @@ nm_str_buf_append_printf(NMStrBuf *strbuf, const char *format, ...) nm_str_buf_maybe_expand(strbuf, l2, FALSE); - va_start(args, format); - l = g_vsnprintf(&strbuf->_priv_str[strbuf->_priv_len], l2, format, args); - va_end(args); + va_copy(args_copy, args); + l = g_vsnprintf(&strbuf->_priv_str[strbuf->_priv_len], l2, format, args_copy); + va_end(args_copy); nm_assert(l >= 0); nm_assert((gsize) l == l2 - 1u); @@ -6603,7 +6662,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); } /*****************************************************************************/ @@ -6732,3 +6791,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 0589eeac..3d8eaced 100644 --- a/src/libnm-glib-aux/nm-shared-utils.h +++ b/src/libnm-glib-aux/nm-shared-utils.h @@ -243,11 +243,16 @@ extern const NMIPAddr nm_ip_addr_zero; static inline int nm_ip_addr_cmp(int addr_family, gconstpointer a, gconstpointer b) { + /* Note that @a and @b are not required to be full NMIPAddr unions. + * Depending on @addr_family, they can also be only in_addr_t or + * struct in6_addr. */ NM_CMP_SELF(a, b); NM_CMP_DIRECT_MEMCMP(a, b, nm_utils_addr_family_to_size(addr_family)); return 0; } +int nm_ip_addr_cmp_for_sort(gconstpointer a, gconstpointer b, gpointer user_data); + static inline gboolean nm_ip_addr_equal(int addr_family, gconstpointer a, gconstpointer b) { @@ -277,8 +282,15 @@ nm_ip_addr_set(int addr_family, gpointer dst, gconstpointer src) nm_assert(dst); nm_assert(src); - /* this MUST use memcpy() (or similar means) to support unaligned src/dst pointers. */ + /* this MUST use memcpy() to support unaligned src/dst pointers. */ memcpy(dst, src, nm_utils_addr_family_to_size(addr_family)); + + /* Note that @dst is not necessarily a NMIPAddr, it could also be just + * an in_addr_t/struct in6_addr. We thus can only set the bytes that + * we know are present based on the address family. + * + * Using this function to initialize an NMIPAddr union (for IPv4) leaves + * uninitalized bytes. Avoid that by using nm_ip_addr_init() instead. */ } static inline NMIPAddr @@ -291,6 +303,8 @@ nm_ip_addr_init(int addr_family, gconstpointer src) G_STATIC_ASSERT_EXPR(sizeof(NMIPAddr) == sizeof(struct in6_addr)); + /* this MUST use memcpy() to support unaligned src/dst pointers. */ + if (NM_IS_IPv4(addr_family)) { memcpy(&a, src, sizeof(in_addr_t)); @@ -312,12 +326,6 @@ gboolean nm_ip_addr_set_from_untrusted(int addr_family, gboolean nm_ip_addr_set_from_variant(int addr_family, gpointer dst, GVariant *variant, int *out_addr_family); -static inline gboolean -nm_ip4_addr_is_localhost(in_addr_t addr4) -{ - return (addr4 & htonl(0xFF000000u)) == htonl(0x7F000000u); -} - static inline gconstpointer nm_ip_addr_from_packed_array(int addr_family, gconstpointer ipaddr_arr, gsize idx) { @@ -389,6 +397,17 @@ gboolean nm_utils_get_ipv6_interface_identifier(NMLinkType link_type, /*****************************************************************************/ +static inline guint32 +_nm_utils_ip4_netmask_to_prefix(in_addr_t subnetmask) +{ + G_STATIC_ASSERT_EXPR(__SIZEOF_INT__ == 4); + G_STATIC_ASSERT_EXPR(sizeof(int) == 4); + G_STATIC_ASSERT_EXPR(sizeof(guint) == 4); + G_STATIC_ASSERT_EXPR(sizeof(subnetmask) == 4); + + return ((subnetmask != 0u) ? (guint32) (32 - __builtin_ctz(ntohl(subnetmask))) : 0u); +} + /** * _nm_utils_ip4_prefix_to_netmask: * @prefix: a CIDR prefix @@ -485,11 +504,20 @@ nm_utils_ip_address_same_prefix(int addr_family, /*****************************************************************************/ gboolean nm_utils_ip_is_site_local(int addr_family, const void *address); +gboolean nm_utils_ip6_is_ula(const struct in6_addr *address); /*****************************************************************************/ -#define NM_IPV4LL_NETWORK ((in_addr_t) (htonl(0xA9FE0000lu))) -#define NM_IPV4LL_NETMASK ((in_addr_t) (htonl(0xFFFF0000lu))) +#define NM_IPV4LL_NETWORK ((in_addr_t) htonl(0xA9FE0000lu)) +#define NM_IPV4LL_NETMASK ((in_addr_t) htonl(0xFFFF0000lu)) + +static inline gboolean +nm_utils_ip4_address_is_loopback(in_addr_t addr) +{ + /* There is also IN_LOOPBACK() in , but there the + * argument is in host order not `in_addr_t`. */ + return (addr & htonl(0xFF000000u)) == htonl(0x7F000000u); +} static inline gboolean nm_utils_ip4_address_is_link_local(in_addr_t addr) @@ -1987,6 +2015,7 @@ typedef struct { NMUtilsNamedEntry named_entry; const char *name; char *name_mutable; + gpointer name_ptr; }; union { const char *value_str; @@ -2000,14 +2029,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), \ @@ -2048,6 +2091,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) { @@ -2156,38 +2222,57 @@ nm_g_array_unref(GArray *arr) g_array_unref(arr); } -#define nm_g_array_first(arr, type) \ - ({ \ - GArray *const _arr = (arr); \ - guint _len; \ - \ - nm_assert(_arr); \ - _len = _arr->len; \ - nm_assert(_len > 0); \ - &g_array_index(arr, type, 0); \ +#define nm_g_array_first(arr, Type) \ + ({ \ + GArray *const _arr = (arr); \ + \ + nm_assert(_arr); \ + nm_assert(sizeof(Type) == g_array_get_element_size(_arr)); \ + nm_assert(_arr->len > 0); \ + \ + &g_array_index(arr, Type, 0); \ }) -#define nm_g_array_last(arr, type) \ - ({ \ - GArray *const _arr = (arr); \ - guint _len; \ - \ - nm_assert(_arr); \ - _len = _arr->len; \ - nm_assert(_len > 0); \ - &g_array_index(arr, type, _len - 1u); \ +#define nm_g_array_last(arr, Type) \ + ({ \ + GArray *const _arr = (arr); \ + \ + nm_assert(_arr); \ + nm_assert(sizeof(Type) == g_array_get_element_size(_arr)); \ + nm_assert(_arr->len > 0); \ + \ + &g_array_index(arr, Type, _arr->len - 1u); \ + }) + +/* Similar to g_array_index(). The differences are + * - this does nm_assert() checks that the arguments are valid. + * - returns a pointer to the element. */ +#define nm_g_array_index_p(arr, Type, idx) \ + ({ \ + GArray *const _arr_55 = (arr); \ + const guint _idx_55 = (idx); \ + \ + nm_assert(_arr_55); \ + nm_assert(sizeof(Type) == g_array_get_element_size(_arr_55)); \ + nm_assert(_idx_55 < _arr_55->len); \ + \ + &g_array_index(_arr_55, Type, _idx_55); \ }) -#define nm_g_array_append_new(arr, type) \ - ({ \ - GArray *const _arr = (arr); \ - guint _len; \ - \ - nm_assert(_arr); \ - _len = _arr->len; \ - nm_assert(_len < G_MAXUINT); \ - g_array_set_size(_arr, _len + 1u); \ - &g_array_index(arr, type, _len); \ +#define nm_g_array_append_new(arr, Type) \ + ({ \ + GArray *const _arr = (arr); \ + guint _len; \ + \ + nm_assert(_arr); \ + nm_assert(sizeof(Type) == g_array_get_element_size(_arr)); \ + \ + _len = _arr->len; \ + \ + nm_assert(_len < G_MAXUINT); \ + \ + g_array_set_size(_arr, _len + 1u); \ + &g_array_index(arr, Type, _len); \ }) /*****************************************************************************/ @@ -2794,6 +2879,8 @@ nm_ether_addr_to_string(const NMEtherAddr *ether_addr, char sbuf[static(sizeof(N #define nm_ether_addr_to_string_a(ether_addr) \ nm_ether_addr_to_string((ether_addr), g_alloca(sizeof(NMEtherAddr) * 3)) +NMEtherAddr *nm_ether_addr_from_string(NMEtherAddr *addr, const char *str); + guint8 *nm_utils_hexstr2bin_full(const char *hexstr, gboolean allow_0x_prefix, gboolean delimiter_required, @@ -3083,10 +3170,14 @@ gboolean nm_utils_ifname_valid(const char *name, NMUtilsIfaceType type, GError * static inline GArray * nm_strvarray_ensure(GArray **p) { + nm_assert(p); + if (!*p) { *p = g_array_new(TRUE, FALSE, sizeof(char *)); g_array_set_clear_func(*p, nm_indirect_g_free); - } + } else + nm_assert(g_array_get_element_size(*p) == sizeof(char *)); + return *p; } @@ -3095,6 +3186,9 @@ nm_strvarray_add(GArray *array, const char *str) { char *s; + nm_assert(array); + nm_assert(g_array_get_element_size(array) == sizeof(char *)); + s = g_strdup(str); g_array_append_val(array, s); } @@ -3102,15 +3196,14 @@ nm_strvarray_add(GArray *array, const char *str) static inline const char * nm_strvarray_get_idx(GArray *array, guint idx) { - nm_assert(array); - nm_assert(idx < array->len); - - return g_array_index(array, const char *, idx); + return *nm_g_array_index_p(array, const char *, idx); } static inline const char *const * nm_strvarray_get_strv_non_empty(GArray *arr, guint *length) { + nm_assert(!arr || g_array_get_element_size(arr) == sizeof(char *)); + if (!arr || arr->len == 0) { NM_SET_OUT(length, 0); return NULL; @@ -3125,6 +3218,8 @@ nm_strvarray_get_strv_non_empty_dup(GArray *arr, guint *length) { const char *const *strv; + nm_assert(!arr || g_array_get_element_size(arr) == sizeof(char *)); + if (!arr || arr->len == 0) { NM_SET_OUT(length, 0); return NULL; @@ -3143,6 +3238,8 @@ nm_strvarray_get_strv(GArray **arr, guint *length) return (const char *const *) arr; } + nm_assert(g_array_get_element_size(*arr) == sizeof(char *)); + NM_SET_OUT(length, (*arr)->len); return &g_array_index(*arr, const char *, 0); } @@ -3154,6 +3251,8 @@ nm_strvarray_set_strv(GArray **array, const char *const *strv) array_old = g_steal_pointer(array); + nm_assert(!array_old || g_array_get_element_size(array_old) == sizeof(char *)); + if (!strv || !strv[0]) return; @@ -3170,6 +3269,7 @@ nm_strvarray_find_first(GArray *strv, const char *needle) nm_assert(needle); if (strv) { + nm_assert(g_array_get_element_size(strv) == sizeof(char *)); for (i = 0; i < strv->len; i++) { if (nm_streq(needle, g_array_index(strv, const char *, i))) return i; @@ -3253,6 +3353,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); @@ -3305,4 +3411,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 47d1f055..652bc96b 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 @@ -263,7 +291,27 @@ nm_str_buf_append0(NMStrBuf *strbuf, const char *str) return nm_str_buf_append_len0(strbuf, str, strlen(str)); } -void nm_str_buf_append_printf(NMStrBuf *strbuf, const char *format, ...) _nm_printf(2, 3); +void nm_str_buf_append_printfv(NMStrBuf *strbuf, const char *format, va_list args) _nm_printf(2, 0); + +/* Warning, this is not a function-like macro. That is, you must + * evaluate it in a place where you would otherwise call va_start(). */ +#define nm_str_buf_append_printfv_eval(strbuf, format, va_start_last) \ + ({ \ + NMStrBuf *const _strbuf = (strbuf); \ + va_list _ap; \ + \ + va_start(_ap, (va_start_last)); \ + nm_str_buf_append_printfv(_strbuf, (format), _ap); \ + va_end(_ap); \ + \ + _strbuf; \ + }) + +static inline void _nm_printf(2, 3) + nm_str_buf_append_printf(NMStrBuf *strbuf, const char *format, ...) +{ + nm_str_buf_append_printfv_eval(strbuf, format, format); +} static inline void nm_str_buf_ensure_trailing_c(NMStrBuf *strbuf, char ch) @@ -359,10 +407,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 +447,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 +511,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 +526,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 +567,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 +577,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 2dfe9e32..83702070 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/nm-uuid.c b/src/libnm-glib-aux/nm-uuid.c index 464bbf58..53e8b78c 100644 --- a/src/libnm-glib-aux/nm-uuid.c +++ b/src/libnm-glib-aux/nm-uuid.c @@ -202,28 +202,25 @@ nm_uuid_is_valid_nm(const char *str, /* @out_normalized_str is only set, if normalization was necessary * and possible. The caller cannot request @out_normalized_str, without - * also getting @out_normalized. */ + * also requesting @out_normalized. Otherwise, they couldn't know whether + * a normalized string was returned. */ nm_assert(!out_normalized_str || out_normalized); if (!str) return FALSE; if (nm_uuid_parse_full(str, &uuid, &is_normalized)) { - /* Note that: - * @is_normalized means that "str" contains a normalized UUID - * @out_normalized: indicates whether str requires normalization - * and whether @out_normalized_str was set to contain the normalized - * UUID. - * With this, we get the slightly odd assignment: */ - NM_SET_OUT(out_normalized, !is_normalized); - - if (!is_normalized && out_normalized_str) { - /* we need to normalize the UUID */ - nm_uuid_unparse(&uuid, out_normalized_str); + if (is_normalized) { + /* @str is already normalized. No need to normalize again, so + * @out_normalized is FALSE. */ + NM_SET_OUT(out_normalized, FALSE); + } else { + NM_SET_OUT(out_normalized, TRUE); + if (out_normalized_str) { + /* we need to normalize the UUID */ + nm_uuid_unparse(&uuid, out_normalized_str); + } } - - /* regardless whether normalization was necessary, the UUID is - * essentially valid. */ return TRUE; } @@ -235,24 +232,23 @@ nm_uuid_is_valid_nm(const char *str, * are made lower case first. */ NM_SET_OUT(out_normalized, TRUE); if (out_normalized_str) { - char str_lower[40 + 1]; + char str_lower[40]; int i; - nm_assert(strlen(str) < G_N_ELEMENTS(str_lower)); + nm_assert(strlen(str) <= G_N_ELEMENTS(str_lower)); /* normalize first to lower-case. */ for (i = 0; str[i]; i++) { nm_assert(i < G_N_ELEMENTS(str_lower)); str_lower[i] = g_ascii_tolower(str[i]); } - nm_assert(i < G_N_ELEMENTS(str_lower)); - str_lower[i] = '\0'; + nm_assert(i <= G_N_ELEMENTS(str_lower)); /* The namespace UUID is chosen randomly. */ nm_uuid_generate_from_string( &uuid, str_lower, - -1, + i, NM_UUID_TYPE_VERSION5, &NM_UUID_INIT(4e, 72, f7, 09, ca, 95, 44, 05, 90, 53, 1f, 43, 29, 4a, 61, 8c)); nm_uuid_unparse(&uuid, out_normalized_str); diff --git a/src/libnm-glib-aux/tests/test-shared-general.c b/src/libnm-glib-aux/tests/test-shared-general.c index 9acd535d..7d36d64a 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" @@ -116,8 +117,8 @@ test_make_strv(void) const char *const *v2a = NM_MAKE_STRV("a", "b"); const char *const *v2b = NM_MAKE_STRV("a", "b", ); const char *const v3[] = { - "a", - "b", + "a", + "b", }; const char *const *v4b = NM_MAKE_STRV("a", _make_strv_foo(), ); @@ -250,14 +251,14 @@ test_nm_strndup_a(void) /*****************************************************************************/ static void -test_nm_ip4_addr_is_localhost(void) +test_nm_utils_ip4_address_is_loopback(void) { - g_assert(nm_ip4_addr_is_localhost(nmtst_inet4_from_string("127.0.0.0"))); - g_assert(nm_ip4_addr_is_localhost(nmtst_inet4_from_string("127.0.0.1"))); - g_assert(nm_ip4_addr_is_localhost(nmtst_inet4_from_string("127.5.0.1"))); - g_assert(!nm_ip4_addr_is_localhost(nmtst_inet4_from_string("126.5.0.1"))); - g_assert(!nm_ip4_addr_is_localhost(nmtst_inet4_from_string("128.5.0.1"))); - g_assert(!nm_ip4_addr_is_localhost(nmtst_inet4_from_string("129.5.0.1"))); + g_assert(nm_utils_ip4_address_is_loopback(nmtst_inet4_from_string("127.0.0.0"))); + g_assert(nm_utils_ip4_address_is_loopback(nmtst_inet4_from_string("127.0.0.1"))); + g_assert(nm_utils_ip4_address_is_loopback(nmtst_inet4_from_string("127.5.0.1"))); + g_assert(!nm_utils_ip4_address_is_loopback(nmtst_inet4_from_string("126.5.0.1"))); + g_assert(!nm_utils_ip4_address_is_loopback(nmtst_inet4_from_string("128.5.0.1"))); + g_assert(!nm_utils_ip4_address_is_loopback(nmtst_inet4_from_string("129.5.0.1"))); } /*****************************************************************************/ @@ -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 @@ -1431,7 +2215,8 @@ main(int argc, char **argv) g_test_add_func("/general/test_nm_make_strv", test_make_strv); g_test_add_func("/general/test_nm_strdup_int", test_nm_strdup_int); g_test_add_func("/general/test_nm_strndup_a", test_nm_strndup_a); - g_test_add_func("/general/test_nm_ip4_addr_is_localhost", test_nm_ip4_addr_is_localhost); + g_test_add_func("/general/test_nm_utils_ip4_address_is_loopback", + test_nm_utils_ip4_address_is_loopback); g_test_add_func("/general/test_nm_utils_ip4_prefix_to_netmask", test_nm_utils_ip4_prefix_to_netmask); g_test_add_func("/general/test_unaligned", test_unaligned); @@ -1450,6 +2235,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 f464ef29..5cce508d 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/meson.build b/src/libnm-platform/meson.build index d0a7c6c2..e273046f 100644 --- a/src/libnm-platform/meson.build +++ b/src/libnm-platform/meson.build @@ -7,9 +7,9 @@ libnm_platform = static_library( 'nm-netlink.c', 'nm-platform-utils.c', 'nm-platform.c', + 'nmp-global-tracker.c', 'nmp-netns.c', 'nmp-object.c', - 'nmp-route-manager.c', 'wifi/nm-wifi-utils-nl80211.c', 'wifi/nm-wifi-utils.c', 'wpan/nm-wpan-utils.c', diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c index 40cb4396..cd685fe2 100644 --- a/src/libnm-platform/nm-linux-platform.c +++ b/src/libnm-platform/nm-linux-platform.c @@ -7,12 +7,13 @@ #include "nm-linux-platform.h" +#include "libnm-std-aux/nm-linux-compat.h" + #include #include #include #include #include -#include #include #include #include @@ -50,6 +51,14 @@ /*****************************************************************************/ +G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_SIGNAL == MPTCP_PM_ADDR_FLAG_SIGNAL); +G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_SUBFLOW == MPTCP_PM_ADDR_FLAG_SUBFLOW); +G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_BACKUP == MPTCP_PM_ADDR_FLAG_BACKUP); +G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_FULLMESH == MPTCP_PM_ADDR_FLAG_FULLMESH); +G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_IMPLICIT == MPTCP_PM_ADDR_FLAG_IMPLICIT); + +/*****************************************************************************/ + /* re-implement to build against kernel * headers that lack this. */ @@ -79,6 +88,25 @@ enum { TCA_DEF_UNSPEC, TCA_DEF_TM, TCA_DEF_PARMS, TCA_DEF_DATA, TCA_DEF_PAD, __T /*****************************************************************************/ +typedef enum _nm_packed { + _NMP_NETLINK_FIRST = 0, + NMP_NETLINK_GENERIC = 0, + NMP_NETLINK_ROUTE, + _NMP_NETLINK_NUM, + _NMP_NETLINK_NONE = _NMP_NETLINK_NUM, +} NMPNetlinkProtocol; + +#define nmp_netlink_protocol_check(netlink_protocol) \ + ({ \ + const NMPNetlinkProtocol _netlink_protocol_2 = (netlink_protocol); \ + \ + nm_assert(NM_IN_SET(_netlink_protocol_2, NMP_NETLINK_ROUTE, NMP_NETLINK_GENERIC)); \ + \ + _netlink_protocol_2; \ + }) + +/*****************************************************************************/ + #ifndef IFLA_PROMISCUITY #define IFLA_PROMISCUITY 30 #endif @@ -149,6 +177,12 @@ G_STATIC_ASSERT(RTA_MAX == (__RTA_MAX - 1)); /*****************************************************************************/ +#define IFLA_BOND_PEER_NOTIF_DELAY 28 + +#undef IFLA_BOND_MAX + +/*****************************************************************************/ + /* Appeared in the kernel prior to 3.13 dated 19 January, 2014 */ #ifndef ARPHRD_6LOWPAN #define ARPHRD_6LOWPAN 825 @@ -279,6 +313,12 @@ struct _ifla_vf_vlan_info { /*****************************************************************************/ +typedef struct { + guint16 family_id; +} GenlFamilyData; + +/*****************************************************************************/ + typedef enum { INFINIBAND_ACTION_CREATE_CHILD, INFINIBAND_ACTION_DELETE_CHILD, @@ -302,15 +342,17 @@ typedef struct { typedef enum { _REFRESH_ALL_TYPE_FIRST = 0, - REFRESH_ALL_TYPE_LINKS = 0, - REFRESH_ALL_TYPE_IP4_ADDRESSES = 1, - REFRESH_ALL_TYPE_IP6_ADDRESSES = 2, - REFRESH_ALL_TYPE_IP4_ROUTES = 3, - REFRESH_ALL_TYPE_IP6_ROUTES = 4, - REFRESH_ALL_TYPE_ROUTING_RULES_IP4 = 5, - REFRESH_ALL_TYPE_ROUTING_RULES_IP6 = 6, - REFRESH_ALL_TYPE_QDISCS = 7, - REFRESH_ALL_TYPE_TFILTERS = 8, + REFRESH_ALL_TYPE_RTNL_LINKS = 0, + REFRESH_ALL_TYPE_RTNL_IP4_ADDRESSES = 1, + REFRESH_ALL_TYPE_RTNL_IP6_ADDRESSES = 2, + REFRESH_ALL_TYPE_RTNL_IP4_ROUTES = 3, + REFRESH_ALL_TYPE_RTNL_IP6_ROUTES = 4, + REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4 = 5, + REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6 = 6, + REFRESH_ALL_TYPE_RTNL_QDISCS = 7, + REFRESH_ALL_TYPE_RTNL_TFILTERS = 8, + + REFRESH_ALL_TYPE_GENL_FAMILIES = 9, _REFRESH_ALL_TYPE_NUM, } RefreshAllType; @@ -318,66 +360,79 @@ typedef enum { typedef struct { NMPObjectType obj_type; - /* for NLM_F_DUMP, which address family to request. */ - int addr_family; + NMPNetlinkProtocol protocol; + + /* For NLM_F_DUMP, which address family to request. + * Either AF_UNSPEC, AF_INET or AF_INET6. */ + gint8 addr_family_for_dump; } RefreshAllInfo; -typedef enum { +typedef enum _nm_packed { DELAYED_ACTION_TYPE_NONE = 0, #define F(val, name) ((sizeof(char[(((val)) == (name)) ? 1 : -1]) * 0) + (val)) - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = 1 << F(0, REFRESH_ALL_TYPE_LINKS), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = 1 << F(1, REFRESH_ALL_TYPE_IP4_ADDRESSES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = 1 << F(2, REFRESH_ALL_TYPE_IP6_ADDRESSES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = 1 << F(3, REFRESH_ALL_TYPE_IP4_ROUTES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = 1 << F(4, REFRESH_ALL_TYPE_IP6_ROUTES), - DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 = 1 - << F(5, REFRESH_ALL_TYPE_ROUTING_RULES_IP4), - DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6 = 1 - << F(6, REFRESH_ALL_TYPE_ROUTING_RULES_IP6), - DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS = 1 << F(7, REFRESH_ALL_TYPE_QDISCS), - DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS = 1 << F(8, REFRESH_ALL_TYPE_TFILTERS), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_LINKS = 1 << F(0, REFRESH_ALL_TYPE_RTNL_LINKS), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ADDRESSES = + 1 << F(1, REFRESH_ALL_TYPE_RTNL_IP4_ADDRESSES), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ADDRESSES = + 1 << F(2, REFRESH_ALL_TYPE_RTNL_IP6_ADDRESSES), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES = 1 << F(3, REFRESH_ALL_TYPE_RTNL_IP4_ROUTES), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES = 1 << F(4, REFRESH_ALL_TYPE_RTNL_IP6_ROUTES), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP4 = + 1 << F(5, REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP6 = + 1 << F(6, REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS = 1 << F(7, REFRESH_ALL_TYPE_RTNL_QDISCS), + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS = 1 << F(8, REFRESH_ALL_TYPE_RTNL_TFILTERS), + + DELAYED_ACTION_TYPE_REFRESH_ALL_GENL_FAMILIES = 1 << F(9, REFRESH_ALL_TYPE_GENL_FAMILIES), #undef F - DELAYED_ACTION_TYPE_REFRESH_LINK = 1 << 9, - DELAYED_ACTION_TYPE_MASTER_CONNECTED = 1 << 10, - DELAYED_ACTION_TYPE_READ_NETLINK = 1 << 11, - DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = 1 << 12, + DELAYED_ACTION_TYPE_READ_RTNL = 1 << 10, + DELAYED_ACTION_TYPE_READ_GENL = 1 << 11, + DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL = 1 << 12, + DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_GENL = 1 << 13, + DELAYED_ACTION_TYPE_REFRESH_LINK = 1 << 14, + DELAYED_ACTION_TYPE_MASTER_CONNECTED = 1 << 15, __DELAYED_ACTION_TYPE_MAX, - DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL = - DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL = + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP4 + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP6, + + DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_LINKS + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS, - DELAYED_ACTION_TYPE_REFRESH_ALL = - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS - | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, + DELAYED_ACTION_TYPE_REFRESH_GENL_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_GENL_FAMILIES, DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX - 1, } DelayedActionType; -#define FOR_EACH_DELAYED_ACTION(iflags, flags_all) \ - for ((iflags) = (DelayedActionType) 0x1LL; ({ \ - gboolean _good = FALSE; \ - \ - nm_assert(nm_utils_is_power_of_two(iflags)); \ - \ - while ((iflags) <= DELAYED_ACTION_TYPE_MAX) { \ - if (NM_FLAGS_ANY((flags_all), (iflags))) { \ - _good = TRUE; \ - break; \ - } \ - (iflags) <<= 1; \ - } \ - _good; \ - }); \ +#define FOR_EACH_DELAYED_ACTION(iflags, flags_all) \ + for ((iflags) = (DelayedActionType) 0x1LL; ({ \ + gboolean _good = FALSE; \ + \ + nm_assert((iflags) == 0 || nm_utils_is_power_of_two(iflags)); \ + \ + while ((iflags) != 0 && (iflags) <= DELAYED_ACTION_TYPE_MAX) { \ + if (NM_FLAGS_ANY((flags_all), (iflags))) { \ + _good = TRUE; \ + break; \ + } \ + (iflags) <<= 1; \ + } \ + _good; \ + }); \ (iflags) <<= 1) -typedef enum { +typedef enum _nm_packed { /* Negative values are errors from kernel. Add dummy member to * make enum signed. */ _WAIT_FOR_NL_RESPONSE_RESULT_SYSTEM_ERROR = G_MININT, @@ -392,40 +447,57 @@ typedef enum { WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS, } WaitForNlResponseResult; -typedef enum { +typedef enum _nm_packed { DELAYED_ACTION_RESPONSE_TYPE_VOID = 0, DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS = 1, DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET = 2, } DelayedActionWaitForNlResponseType; typedef struct { - guint32 seq_number; - WaitForNlResponseResult seq_result; - DelayedActionWaitForNlResponseType response_type; - gint64 timeout_abs_nsec; - WaitForNlResponseResult *out_seq_result; - char **out_errmsg; + WaitForNlResponseResult *out_seq_result; + char **out_errmsg; union { int *out_refresh_all_in_progress; NMPObject **out_route_get; gpointer out_data; } response; + gint64 timeout_abs_nsec; + guint32 seq_number; + WaitForNlResponseResult seq_result; + DelayedActionWaitForNlResponseType response_type; } DelayedActionWaitForNlResponseData; /*****************************************************************************/ typedef struct { - struct nl_sock *genl; - - struct nl_sock *nlh; - - GSource *event_source; - guint32 nlh_seq_next; + guint32 nlh_seq_last_seen; #if NM_MORE_LOGGING guint32 nlh_seq_last_handled; #endif - guint32 nlh_seq_last_seen; +} NetlinkProtocolPrivData; + +typedef struct { + struct nl_sock *sk_genl_sync; + + union { + struct { + struct nl_sock *sk_genl; + struct nl_sock *sk_rtnl; + }; + struct nl_sock *sk_x[_NMP_NETLINK_NUM]; + }; + + GSource *event_source_genl; + GSource *event_source_rtnl; + + union { + struct { + NetlinkProtocolPrivData proto_data_genl; + NetlinkProtocolPrivData proto_data_rtnl; + }; + NetlinkProtocolPrivData proto_data_x[_NMP_NETLINK_NUM]; + }; guint32 pruning[_REFRESH_ALL_TYPE_NUM]; @@ -446,7 +518,13 @@ typedef struct { GPtrArray *list_master_connected; GPtrArray *list_refresh_link; - GArray *list_wait_for_nl_response; + union { + struct { + GArray *list_wait_for_response_genl; + GArray *list_wait_for_response_rtnl; + }; + GArray *list_wait_for_response_x[_NMP_NETLINK_NUM]; + }; int is_handling; } delayed_action; @@ -462,6 +540,8 @@ typedef struct { gsize len; } netlink_recv_buf; + GenlFamilyData genl_family_data[_NMP_GENL_FAMILY_TYPE_NUM]; + } NMLinuxPlatformPrivate; struct _NMLinuxPlatform { @@ -562,7 +642,7 @@ NM_LINUX_PLATFORM_FROM_PRIVATE(NMLinuxPlatformPrivate *priv) static void delayed_action_schedule(NMPlatform *platform, DelayedActionType action_type, gpointer user_data); -static gboolean delayed_action_handle_all(NMPlatform *platform, gboolean read_netlink); +static gboolean delayed_action_handle_all(NMPlatform *platform); static void do_request_link_no_delayed_actions(NMPlatform *platform, int ifindex, const char *name); static void do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action_type); static void cache_on_change(NMPlatform *platform, @@ -570,8 +650,36 @@ static void cache_on_change(NMPlatform *platform, const NMPObject *obj_old, const NMPObject *obj_new); static void cache_prune_all(NMPlatform *platform); -static gboolean event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks); -static struct nl_sock *_genl_sock(NMLinuxPlatform *platform); +static gboolean event_handler_read_netlink(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + gboolean wait_for_acks); + +/*****************************************************************************/ + +static const struct { + gint8 netlink_protocol; + DelayedActionType delayed_action_type_read; + DelayedActionType delayed_action_type_wait_for_response; + const char name[5]; +} _nmp_netlink_protocol_infos[_NMP_NETLINK_NUM] = { + [NMP_NETLINK_ROUTE] = + { + .netlink_protocol = NETLINK_ROUTE, + .name = "rtnl", + .delayed_action_type_read = DELAYED_ACTION_TYPE_READ_RTNL, + .delayed_action_type_wait_for_response = DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL, + }, + [NMP_NETLINK_GENERIC] = + { + .netlink_protocol = NETLINK_GENERIC, + .name = "genl", + .delayed_action_type_read = DELAYED_ACTION_TYPE_READ_GENL, + .delayed_action_type_wait_for_response = DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_GENL, + }, +}; + +#define nmp_netlink_protocol_info(netlink_protocol) \ + (&_nmp_netlink_protocol_infos[nmp_netlink_protocol_check((netlink_protocol))]) /*****************************************************************************/ @@ -1433,6 +1541,152 @@ _parse_lnk_bridge(const char *kind, struct nlattr *info_data) /***********************************************************************************/ +static NMPObject * +_parse_lnk_bond(const char *kind, struct nlattr *info_data) +{ + static const struct nla_policy policy[] = { + [IFLA_BOND_MODE] = {.type = NLA_U8}, + [IFLA_BOND_ACTIVE_SLAVE] = {.type = NLA_U32}, + [IFLA_BOND_MIIMON] = {.type = NLA_U32}, + [IFLA_BOND_UPDELAY] = {.type = NLA_U32}, + [IFLA_BOND_DOWNDELAY] = {.type = NLA_U32}, + [IFLA_BOND_USE_CARRIER] = {.type = NLA_U8}, + [IFLA_BOND_ARP_INTERVAL] = {.type = NLA_U32}, + [IFLA_BOND_ARP_IP_TARGET] = {.type = NLA_NESTED}, + [IFLA_BOND_ARP_VALIDATE] = {.type = NLA_U32}, + [IFLA_BOND_ARP_ALL_TARGETS] = {.type = NLA_U32}, + [IFLA_BOND_PRIMARY] = {.type = NLA_U32}, + [IFLA_BOND_PRIMARY_RESELECT] = {.type = NLA_U8}, + [IFLA_BOND_FAIL_OVER_MAC] = {.type = NLA_U8}, + [IFLA_BOND_XMIT_HASH_POLICY] = {.type = NLA_U8}, + [IFLA_BOND_RESEND_IGMP] = {.type = NLA_U32}, + [IFLA_BOND_NUM_PEER_NOTIF] = {.type = NLA_U8}, + [IFLA_BOND_ALL_SLAVES_ACTIVE] = {.type = NLA_U8}, + [IFLA_BOND_MIN_LINKS] = {.type = NLA_U32}, + [IFLA_BOND_LP_INTERVAL] = {.type = NLA_U32}, + [IFLA_BOND_PACKETS_PER_SLAVE] = {.type = NLA_U32}, + [IFLA_BOND_AD_LACP_RATE] = {.type = NLA_U8}, + [IFLA_BOND_AD_SELECT] = {.type = NLA_U8}, + [IFLA_BOND_AD_ACTOR_SYS_PRIO] = {.type = NLA_U16}, + [IFLA_BOND_AD_USER_PORT_KEY] = {.type = NLA_U16}, + [IFLA_BOND_AD_ACTOR_SYSTEM] = {.minlen = sizeof(NMEtherAddr)}, + [IFLA_BOND_TLB_DYNAMIC_LB] = {.type = NLA_U8}, + [IFLA_BOND_PEER_NOTIF_DELAY] = {.type = NLA_U32}, + }; + NMPlatformLnkBond *props; + struct nlattr *tb[G_N_ELEMENTS(policy)]; + NMPObject *obj = NULL; + + if (!info_data || !nm_streq0(kind, "bond")) + return NULL; + + if (nla_parse_nested_arr(tb, info_data, policy) < 0) + return NULL; + + obj = nmp_object_new(NMP_OBJECT_TYPE_LNK_BOND, NULL); + + props = &obj->lnk_bond; + + if (tb[IFLA_BOND_MODE]) + props->mode = nla_get_u8(tb[IFLA_BOND_MODE]); + if (tb[IFLA_BOND_PRIMARY]) { + props->primary = nla_get_u32(tb[IFLA_BOND_PRIMARY]); + } else if (tb[IFLA_BOND_ACTIVE_SLAVE]) { + props->primary = nla_get_u32(tb[IFLA_BOND_ACTIVE_SLAVE]); + } + if (tb[IFLA_BOND_MIIMON]) { + props->miimon = nla_get_u32(tb[IFLA_BOND_MIIMON]); + props->miimon_has = TRUE; + } else { + props->miimon_has = FALSE; + } + if (tb[IFLA_BOND_UPDELAY]) { + props->updelay = nla_get_u32(tb[IFLA_BOND_UPDELAY]); + props->updelay_has = TRUE; + } else { + props->updelay_has = FALSE; + } + if (tb[IFLA_BOND_DOWNDELAY]) { + props->downdelay = nla_get_u32(tb[IFLA_BOND_DOWNDELAY]); + props->downdelay_has = TRUE; + } else { + props->downdelay_has = FALSE; + } + if (tb[IFLA_BOND_USE_CARRIER]) + props->use_carrier = nla_get_u8(tb[IFLA_BOND_USE_CARRIER]); + if (tb[IFLA_BOND_ARP_INTERVAL]) + props->arp_interval = nla_get_u32(tb[IFLA_BOND_ARP_INTERVAL]); + if (tb[IFLA_BOND_ARP_IP_TARGET]) { + struct nlattr *attr; + int rem; + + nla_for_each_nested (attr, tb[IFLA_BOND_ARP_IP_TARGET], rem) { + if (props->arp_ip_targets_num > NM_BOND_MAX_ARP_TARGETS - 1) + break; + if (nla_len(attr) < sizeof(in_addr_t)) + break; + + props->arp_ip_target[props->arp_ip_targets_num++] = nla_get_u32(attr); + } + } + if (tb[IFLA_BOND_ARP_VALIDATE]) + props->arp_validate = nla_get_u32(tb[IFLA_BOND_ARP_VALIDATE]); + if (tb[IFLA_BOND_ARP_ALL_TARGETS]) { + props->arp_all_targets = nla_get_u32(tb[IFLA_BOND_ARP_ALL_TARGETS]); + props->arp_all_targets_has = TRUE; + } else { + props->arp_all_targets_has = FALSE; + } + if (tb[IFLA_BOND_PRIMARY_RESELECT]) + props->primary_reselect = nla_get_u8(tb[IFLA_BOND_PRIMARY_RESELECT]); + if (tb[IFLA_BOND_FAIL_OVER_MAC]) + props->fail_over_mac = nla_get_u8(tb[IFLA_BOND_FAIL_OVER_MAC]); + if (tb[IFLA_BOND_XMIT_HASH_POLICY]) + props->xmit_hash_policy = nla_get_u8(tb[IFLA_BOND_XMIT_HASH_POLICY]); + if (tb[IFLA_BOND_RESEND_IGMP]) { + props->resend_igmp = nla_get_u32(tb[IFLA_BOND_RESEND_IGMP]); + props->resend_igmp_has = TRUE; + } else { + props->resend_igmp_has = FALSE; + } + if (tb[IFLA_BOND_NUM_PEER_NOTIF]) + props->num_grat_arp = nla_get_u8(tb[IFLA_BOND_NUM_PEER_NOTIF]); + if (tb[IFLA_BOND_ALL_SLAVES_ACTIVE]) + props->all_ports_active = nla_get_u8(tb[IFLA_BOND_ALL_SLAVES_ACTIVE]); + if (tb[IFLA_BOND_MIN_LINKS]) + props->min_links = nla_get_u32(tb[IFLA_BOND_MIN_LINKS]); + if (tb[IFLA_BOND_LP_INTERVAL]) + props->lp_interval = nla_get_u32(tb[IFLA_BOND_LP_INTERVAL]); + if (tb[IFLA_BOND_PACKETS_PER_SLAVE]) + props->packets_per_port = nla_get_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE]); + if (tb[IFLA_BOND_AD_LACP_RATE]) + props->lacp_rate = nla_get_u8(tb[IFLA_BOND_AD_LACP_RATE]); + if (tb[IFLA_BOND_AD_SELECT]) + props->ad_select = nla_get_u8(tb[IFLA_BOND_AD_SELECT]); + if (tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]) + props->ad_actor_sys_prio = nla_get_u16(tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]); + if (tb[IFLA_BOND_AD_USER_PORT_KEY]) + props->ad_user_port_key = nla_get_u16(tb[IFLA_BOND_AD_USER_PORT_KEY]); + if (tb[IFLA_BOND_AD_ACTOR_SYSTEM]) + props->ad_actor_system = *nla_data_as(NMEtherAddr, tb[IFLA_BOND_AD_ACTOR_SYSTEM]); + if (tb[IFLA_BOND_TLB_DYNAMIC_LB]) { + props->tlb_dynamic_lb = nla_get_u8(tb[IFLA_BOND_TLB_DYNAMIC_LB]); + props->tlb_dynamic_lb_has = TRUE; + } else { + props->tlb_dynamic_lb_has = FALSE; + } + if (tb[IFLA_BOND_PEER_NOTIF_DELAY]) { + props->peer_notif_delay = nla_get_u32(tb[IFLA_BOND_PEER_NOTIF_DELAY]); + props->peer_notif_delay_has = TRUE; + } else { + props->peer_notif_delay_has = FALSE; + } + + return obj; +} + +/***********************************************************************************/ + static NMPObject * _parse_lnk_gre(const char *kind, struct nlattr *info_data) { @@ -2322,7 +2576,7 @@ typedef struct { } WireGuardParseData; static int -_wireguard_get_device_cb(struct nl_msg *msg, void *arg) +_wireguard_get_device_cb(const struct nl_msg *msg, void *arg) { static const struct nla_policy policy[] = { [WGDEVICE_A_IFINDEX] = {.type = NLA_U32}, @@ -2400,7 +2654,7 @@ _wireguard_get_device_cb(struct nl_msg *msg, void *arg) static const NMPObject * _wireguard_read_info(NMPlatform *platform /* used only as logging context */, struct nl_sock *genl, - int wireguard_family_id, + guint16 wireguard_family_id, int ifindex) { nm_auto_nlmsg struct nl_msg *msg = NULL; @@ -2414,10 +2668,12 @@ _wireguard_read_info(NMPlatform *platform /* used only as logging context */ guint i; nm_assert(genl); - nm_assert(wireguard_family_id >= 0); nm_assert(ifindex > 0); - _LOGT("wireguard: fetching information for ifindex %d (genl-id %d)...", + if (wireguard_family_id == 0) + return NULL; + + _LOGT("wireguard: fetching information for ifindex %d (genl-id 0x%x)...", ifindex, wireguard_family_id); @@ -2530,25 +2786,8 @@ nla_put_failure: g_return_val_if_reached(NULL); } -static int -_wireguard_get_family_id(NMPlatform *platform, int ifindex_try) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - int wireguard_family_id = -1; - - if (ifindex_try > 0) { - const NMPlatformLink *plink; - - if (nm_platform_link_get_lnk_wireguard(platform, ifindex_try, &plink)) - wireguard_family_id = NMP_OBJECT_UP_CAST(plink)->_link.wireguard_family_id; - } - if (wireguard_family_id < 0) - wireguard_family_id = genl_ctrl_resolve(priv->genl, "wireguard"); - return wireguard_family_id; -} - static const NMPObject * -_wireguard_refresh_link(NMPlatform *platform, int wireguard_family_id, int ifindex) +_wireguard_refresh_link(NMPlatform *platform, guint16 wireguard_family_id, int ifindex) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); nm_auto_nmpobj const NMPObject *obj_old = NULL; @@ -2558,7 +2797,7 @@ _wireguard_refresh_link(NMPlatform *platform, int wireguard_family_id, int ifind const NMPObject *plink = NULL; nm_auto_nmpobj NMPObject *obj = NULL; - nm_assert(wireguard_family_id >= 0); + nm_assert(wireguard_family_id > 0); nm_assert(ifindex > 0); nm_platform_process_events(platform); @@ -2573,7 +2812,7 @@ _wireguard_refresh_link(NMPlatform *platform, int wireguard_family_id, int ifind if (NMP_OBJECT_GET_TYPE(plink->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD) lnk_new = nmp_object_ref(plink->_link.netlink.lnk); } else { - lnk_new = _wireguard_read_info(platform, priv->genl, wireguard_family_id, ifindex); + lnk_new = _wireguard_read_info(platform, priv->sk_genl_sync, wireguard_family_id, ifindex); if (!lnk_new) { if (NMP_OBJECT_GET_TYPE(plink->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD) lnk_new = nmp_object_ref(plink->_link.netlink.lnk); @@ -2583,15 +2822,13 @@ _wireguard_refresh_link(NMPlatform *platform, int wireguard_family_id, int ifind } } - if (plink->_link.wireguard_family_id == wireguard_family_id - && plink->_link.netlink.lnk == lnk_new) + if (plink->_link.netlink.lnk == lnk_new) return plink; /* we use nmp_cache_update_netlink() to re-inject the new object into the cache. * For that, we need to clone it, and tweak it so that it's suitable. It's a bit * of a hack, in particular that we need to clear driver and udev-device. */ - obj = nmp_object_clone(plink, FALSE); - obj->_link.wireguard_family_id = wireguard_family_id; + obj = nmp_object_clone(plink, FALSE); nmp_object_unref(obj->_link.netlink.lnk); obj->_link.netlink.lnk = g_steal_pointer(&lnk_new); obj->link.driver = NULL; @@ -2617,7 +2854,7 @@ _wireguard_refresh_link(NMPlatform *platform, int wireguard_family_id, int ifind static int _wireguard_create_change_nlmsgs(NMPlatform *platform, int ifindex, - int wireguard_family_id, + guint16 wireguard_family_id, const NMPlatformLnkWireGuard *lnk_wireguard, const NMPWireGuardPeer *peers, const NMPlatformWireGuardChangePeerFlags *peer_flags, @@ -2636,14 +2873,6 @@ _wireguard_create_change_nlmsgs(NMPlatform *platfo struct nlattr *nest_curr_allowed_ip; NMPlatformWireGuardChangePeerFlags p_flags = NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_DEFAULT; -#define _nla_nest_end(msg, nest_start) \ - G_STMT_START \ - { \ - if (nla_nest_end((msg), (nest_start)) < 0) \ - g_return_val_if_reached(-NME_BUG); \ - } \ - G_STMT_END - /* Adapted from LGPL-2.1+ code [1]. * * [1] https://git.zx2c4.com/WireGuard/tree/contrib/examples/embeddable-wg-library/wireguard.c?id=5e99a6d43fe2351adf36c786f5ea2086a8fe7ab8#n1073 */ @@ -2799,36 +3028,36 @@ again: if (nla_put_uint8(msg, WGALLOWEDIP_A_CIDR_MASK, aip->mask) < 0) goto toobig_allowedips; - _nla_nest_end(msg, nest_curr_allowed_ip); + NLA_NEST_END(msg, nest_curr_allowed_ip); nest_curr_allowed_ip = NULL; } idx_allowed_ips_curr = IDX_NIL; - _nla_nest_end(msg, nest_allowed_ips); + NLA_NEST_END(msg, nest_allowed_ips); nest_allowed_ips = NULL; } } - _nla_nest_end(msg, nest_curr_peer); + NLA_NEST_END(msg, nest_curr_peer); nest_curr_peer = NULL; } - _nla_nest_end(msg, nest_peers); + NLA_NEST_END(msg, nest_peers); goto send; toobig_allowedips: if (nest_curr_allowed_ip) nla_nest_cancel(msg, nest_curr_allowed_ip); if (nest_allowed_ips) - _nla_nest_end(msg, nest_allowed_ips); - _nla_nest_end(msg, nest_curr_peer); - _nla_nest_end(msg, nest_peers); + NLA_NEST_END(msg, nest_allowed_ips); + NLA_NEST_END(msg, nest_curr_peer); + NLA_NEST_END(msg, nest_peers); goto send; toobig_peers: if (nest_curr_peer) nla_nest_cancel(msg, nest_curr_peer); - _nla_nest_end(msg, nest_peers); + NLA_NEST_END(msg, nest_peers); goto send; send: @@ -2844,8 +3073,6 @@ send: nla_put_failure: g_return_val_if_reached(-NME_BUG); - -#undef _nla_nest_end } static int @@ -2859,12 +3086,12 @@ link_wireguard_change(NMPlatform *platform, { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); gs_unref_ptrarray GPtrArray *msgs = NULL; - int wireguard_family_id; + guint16 wireguard_family_id; guint i; int r; - wireguard_family_id = _wireguard_get_family_id(platform, ifindex); - if (wireguard_family_id < 0) + wireguard_family_id = nm_platform_genl_get_family_id(platform, NMP_GENL_FAMILY_TYPE_WIREGUARD); + if (wireguard_family_id == 0) return -NME_PL_NO_FIRMWARE; r = _wireguard_create_change_nlmsgs(platform, @@ -2882,14 +3109,14 @@ link_wireguard_change(NMPlatform *platform, } for (i = 0; i < msgs->len; i++) { - r = nl_send_auto(priv->genl, msgs->pdata[i]); + r = nl_send_auto(priv->sk_genl_sync, msgs->pdata[i]); if (r < 0) { _LOGW("wireguard: set-device, send netlink message #%u failed: %s", i, nm_strerror(r)); return r; } do { - r = nl_recvmsgs(priv->genl, NULL); + r = nl_recvmsgs(priv->sk_genl_sync, NULL); } while (r == -EAGAIN); if (r < 0) { _LOGW("wireguard: set-device, message #%u was rejected: %s", i, nm_strerror(r)); @@ -2925,10 +3152,10 @@ _nmp_link_address_set(NMPLinkAddress *dst, const struct nlattr *nla) /* Copied and heavily modified from libnl3's link_msg_parser(). */ static NMPObject * -_new_from_nl_link(NMPlatform *platform, - const NMPCache *cache, - struct nlmsghdr *nlh, - gboolean id_only) +_new_from_nl_link(NMPlatform *platform, + const NMPCache *cache, + const struct nlmsghdr *nlh, + gboolean id_only) { static const struct nla_policy policy[] = { [IFLA_IFNAME] = {.type = NLA_STRING, .maxlen = IFNAMSIZ}, @@ -3117,6 +3344,9 @@ _new_from_nl_link(NMPlatform *platform, case NM_LINK_TYPE_BRIDGE: lnk_data = _parse_lnk_bridge(nl_info_kind, nl_info_data); break; + case NM_LINK_TYPE_BOND: + lnk_data = _parse_lnk_bond(nl_info_kind, nl_info_data); + break; case NM_LINK_TYPE_GRE: case NM_LINK_TYPE_GRETAP: lnk_data = _parse_lnk_gre(nl_info_kind, nl_info_data); @@ -3220,16 +3450,18 @@ _new_from_nl_link(NMPlatform *platform, switch (obj->link.type) { case NM_LINK_TYPE_WIFI: case NM_LINK_TYPE_OLPC_MESH: - obj->_link.ext_data = - (GObject *) nm_wifi_utils_new(ifi->ifi_index, - _genl_sock(NM_LINUX_PLATFORM(platform)), - TRUE); + obj->_link.ext_data = (GObject *) nm_wifi_utils_new( + NM_LINUX_PLATFORM_GET_PRIVATE(platform)->sk_genl_sync, + nm_platform_genl_get_family_id(platform, NMP_GENL_FAMILY_TYPE_NL80211), + ifi->ifi_index, + TRUE); break; case NM_LINK_TYPE_WPAN: - obj->_link.ext_data = - (GObject *) nm_wpan_utils_new(ifi->ifi_index, - _genl_sock(NM_LINUX_PLATFORM(platform)), - TRUE); + obj->_link.ext_data = (GObject *) nm_wpan_utils_new( + NM_LINUX_PLATFORM_GET_PRIVATE(platform)->sk_genl_sync, + nm_platform_genl_get_family_id(platform, NMP_GENL_FAMILY_TYPE_NL802154), + ifi->ifi_index, + TRUE); break; default: g_assert_not_reached(); @@ -3238,28 +3470,17 @@ _new_from_nl_link(NMPlatform *platform, if (obj->link.type == NM_LINK_TYPE_WIREGUARD) { const NMPObject *lnk_data_new = NULL; - struct nl_sock *genl = NM_LINUX_PLATFORM_GET_PRIVATE(platform)->genl; + struct nl_sock *genl = NM_LINUX_PLATFORM_GET_PRIVATE(platform)->sk_genl_sync; /* The WireGuard kernel module does not yet send link update * notifications, so we don't actually update the cache. For * now, always refetch link data here. */ - _lookup_cached_link(cache, obj->link.ifindex, completed_from_cache, &link_cached); - if (link_cached && link_cached->_link.netlink.is_in_netlink - && link_cached->link.type == NM_LINK_TYPE_WIREGUARD) - obj->_link.wireguard_family_id = link_cached->_link.wireguard_family_id; - else - obj->_link.wireguard_family_id = -1; - - if (obj->_link.wireguard_family_id < 0) - obj->_link.wireguard_family_id = genl_ctrl_resolve(genl, "wireguard"); - - if (obj->_link.wireguard_family_id >= 0) { - lnk_data_new = _wireguard_read_info(platform, - genl, - obj->_link.wireguard_family_id, - obj->link.ifindex); - } + lnk_data_new = _wireguard_read_info( + platform, + genl, + nm_platform_genl_get_family_id(platform, NMP_GENL_FAMILY_TYPE_WIREGUARD), + obj->link.ifindex); if (lnk_data_new && obj->_link.netlink.lnk && nmp_object_equal(obj->_link.netlink.lnk, lnk_data_new)) @@ -3276,7 +3497,7 @@ _new_from_nl_link(NMPlatform *platform, /* Copied and heavily modified from libnl3's addr_msg_parser(). */ static NMPObject * -_new_from_nl_addr(struct nlmsghdr *nlh, gboolean id_only) +_new_from_nl_addr(const struct nlmsghdr *nlh, gboolean id_only) { static const struct nla_policy policy[] = { [IFA_LABEL] = {.type = NLA_STRING, .maxlen = IFNAMSIZ}, @@ -3391,7 +3612,7 @@ _new_from_nl_addr(struct nlmsghdr *nlh, gboolean id_only) /* Copied and heavily modified from libnl3's rtnl_route_parse() and parse_multipath(). */ static NMPObject * -_new_from_nl_route(struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter *parse_nlmsg_iter) +_new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter *parse_nlmsg_iter) { static const struct nla_policy policy[] = { [RTA_TABLE] = {.type = NLA_U32}, @@ -3420,13 +3641,15 @@ _new_from_nl_route(struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter *parse .found = FALSE, .has_more = FALSE, }; - guint32 mss; - guint32 window = 0; - guint32 cwnd = 0; - guint32 initcwnd = 0; - guint32 initrwnd = 0; - guint32 mtu = 0; - guint32 lock = 0; + guint32 mss; + guint32 window = 0; + guint32 cwnd = 0; + guint32 initcwnd = 0; + guint32 initrwnd = 0; + guint32 mtu = 0; + guint32 rto_min = 0; + guint32 lock = 0; + gboolean quickack = FALSE; nm_assert((parse_nlmsg_iter->iter_more && parse_nlmsg_iter->ip6_route.next_multihop > 0) || (!parse_nlmsg_iter->iter_more && parse_nlmsg_iter->ip6_route.next_multihop == 0)); @@ -3604,6 +3827,8 @@ rta_multipath_done: [RTAX_INITCWND] = {.type = NLA_U32}, [RTAX_INITRWND] = {.type = NLA_U32}, [RTAX_MTU] = {.type = NLA_U32}, + [RTAX_QUICKACK] = {.type = NLA_U32}, + [RTAX_RTO_MIN] = {.type = NLA_U32}, }; struct nlattr *mtb[G_N_ELEMENTS(rtax_policy)]; @@ -3624,6 +3849,10 @@ rta_multipath_done: initrwnd = nla_get_u32(mtb[RTAX_INITRWND]); if (mtb[RTAX_MTU]) mtu = nla_get_u32(mtb[RTAX_MTU]); + if (mtb[RTAX_RTO_MIN]) + rto_min = nla_get_u32(mtb[RTAX_RTO_MIN]); + if (mtb[RTAX_QUICKACK]) + quickack = !!nla_get_u32(mtb[RTAX_QUICKACK]); } /*****************************************************************/ @@ -3674,12 +3903,15 @@ rta_multipath_done: obj->ip_route.cwnd = cwnd; obj->ip_route.initcwnd = initcwnd; obj->ip_route.initrwnd = initrwnd; + obj->ip_route.rto_min = rto_min; + obj->ip_route.quickack = quickack; obj->ip_route.mtu = mtu; obj->ip_route.lock_window = NM_FLAGS_HAS(lock, 1 << RTAX_WINDOW); obj->ip_route.lock_cwnd = NM_FLAGS_HAS(lock, 1 << RTAX_CWND); obj->ip_route.lock_initcwnd = NM_FLAGS_HAS(lock, 1 << RTAX_INITCWND); obj->ip_route.lock_initrwnd = NM_FLAGS_HAS(lock, 1 << RTAX_INITRWND); obj->ip_route.lock_mtu = NM_FLAGS_HAS(lock, 1 << RTAX_MTU); + obj->ip_route.lock_mss = NM_FLAGS_HAS(lock, 1 << RTAX_ADVMSS); if (!IS_IPv4) { if (tb[RTA_PREF]) @@ -3699,7 +3931,7 @@ rta_multipath_done: } static NMPObject * -_new_from_nl_routing_rule(struct nlmsghdr *nlh, gboolean id_only) +_new_from_nl_routing_rule(const struct nlmsghdr *nlh, gboolean id_only) { static const struct nla_policy policy[] = { [FRA_UNSPEC] = {}, @@ -3975,7 +4207,7 @@ psched_tick_to_time(NMPlatform *platform, guint32 tick) } static NMPObject * -_new_from_nl_qdisc(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_only) +_new_from_nl_qdisc(NMPlatform *platform, const struct nlmsghdr *nlh, gboolean id_only) { static const struct nla_policy policy[] = { [TCA_KIND] = {.type = NLA_STRING}, @@ -4088,7 +4320,7 @@ _new_from_nl_qdisc(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_only) } static NMPObject * -_new_from_nl_tfilter(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_only) +_new_from_nl_tfilter(NMPlatform *platform, const struct nlmsghdr *nlh, gboolean id_only) { static const struct nla_policy policy[] = { [TCA_KIND] = {.type = NLA_STRING}, @@ -4133,18 +4365,17 @@ _new_from_nl_tfilter(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_onl * Returns: %NULL or a newly created NMPObject instance. **/ static NMPObject * -nmp_object_new_from_nl(NMPlatform *platform, - const NMPCache *cache, - struct nl_msg *msg, - gboolean id_only, - ParseNlmsgIter *parse_nlmsg_iter) +nmp_object_new_from_nl(NMPlatform *platform, + const NMPCache *cache, + const struct nl_msg_lite *msg, + gboolean id_only, + ParseNlmsgIter *parse_nlmsg_iter) { - struct nlmsghdr *msghdr; + const struct nlmsghdr *msghdr; - if (nlmsg_get_proto(msg) != NETLINK_ROUTE) - return NULL; + nm_assert(msg->nm_protocol == NETLINK_ROUTE); - msghdr = nlmsg_hdr(msg); + msghdr = msg->nm_nlh; switch (msghdr->nlmsg_type) { case RTM_NEWLINK: @@ -4268,6 +4499,86 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo NLA_PUT_U64(msg, IFLA_BR_MCAST_STARTUP_QUERY_INTVL, props->mcast_startup_query_interval); break; } + case NM_LINK_TYPE_BOND: + { + const NMPlatformLnkBond *props = extra_data; + struct nlattr *targets; + int i = 0; + + nm_assert(extra_data); + + if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->arp_ip_targets_num > 0) { + targets = nla_nest_start(msg, IFLA_BOND_ARP_IP_TARGET); + if (!targets) + goto nla_put_failure; + + for (i = 0; i < props->arp_ip_targets_num; i++) + NLA_PUT_U32(msg, i, props->arp_ip_target[i]); + + nla_nest_end(msg, targets); + } + + if (props->arp_all_targets_has) + NLA_PUT_U32(msg, IFLA_BOND_ARP_ALL_TARGETS, props->arp_all_targets); + if (props->arp_interval) + NLA_PUT_U32(msg, IFLA_BOND_ARP_INTERVAL, props->arp_interval); + if (props->arp_validate) + NLA_PUT_U32(msg, IFLA_BOND_ARP_VALIDATE, props->arp_validate); + if (props->downdelay_has) + NLA_PUT_U32(msg, IFLA_BOND_DOWNDELAY, props->downdelay); + if (props->lp_interval_has) + NLA_PUT_U32(msg, IFLA_BOND_LP_INTERVAL, props->lp_interval); + if (props->miimon_has) + NLA_PUT_U32(msg, IFLA_BOND_MIIMON, props->miimon); + if (props->min_links) + NLA_PUT_U32(msg, IFLA_BOND_MIN_LINKS, props->min_links); + if (props->packets_per_port) + NLA_PUT_U32(msg, IFLA_BOND_PACKETS_PER_SLAVE, props->packets_per_port); + if (props->peer_notif_delay_has) + NLA_PUT_U32(msg, IFLA_BOND_PEER_NOTIF_DELAY, props->peer_notif_delay); + if (props->primary) + NLA_PUT_U32(msg, IFLA_BOND_PRIMARY, props->primary); + if (props->resend_igmp_has) + NLA_PUT_U32(msg, IFLA_BOND_RESEND_IGMP, props->resend_igmp); + if (props->updelay_has) + NLA_PUT_U32(msg, IFLA_BOND_UPDELAY, props->updelay); + if (props->ad_actor_sys_prio) + NLA_PUT_U16(msg, IFLA_BOND_AD_ACTOR_SYS_PRIO, props->ad_actor_sys_prio); + if (props->ad_user_port_key) + NLA_PUT_U16(msg, IFLA_BOND_AD_USER_PORT_KEY, props->ad_user_port_key); + if (!nm_ether_addr_equal(&props->ad_actor_system, &nm_ether_addr_zero)) + NLA_PUT(msg, + IFLA_BOND_AD_ACTOR_SYSTEM, + sizeof(props->ad_actor_system), + &props->ad_actor_system); + if (props->ad_select) + NLA_PUT_U8(msg, IFLA_BOND_AD_SELECT, props->ad_select); + + NLA_PUT_U8(msg, IFLA_BOND_ALL_SLAVES_ACTIVE, props->all_ports_active); + + if (props->fail_over_mac) + NLA_PUT_U8(msg, IFLA_BOND_FAIL_OVER_MAC, props->fail_over_mac); + if (props->lacp_rate) + NLA_PUT_U8(msg, IFLA_BOND_AD_LACP_RATE, props->lacp_rate); + if (props->num_grat_arp) + NLA_PUT_U8(msg, IFLA_BOND_NUM_PEER_NOTIF, props->num_grat_arp); + + NLA_PUT_U8(msg, IFLA_BOND_MODE, props->mode); + + if (props->primary_reselect) + NLA_PUT_U8(msg, IFLA_BOND_PRIMARY_RESELECT, props->primary_reselect); + if (props->xmit_hash_policy) + NLA_PUT_U8(msg, IFLA_BOND_XMIT_HASH_POLICY, props->xmit_hash_policy); + if (props->tlb_dynamic_lb_has) + NLA_PUT_U8(msg, IFLA_BOND_TLB_DYNAMIC_LB, !!props->tlb_dynamic_lb); + + NLA_PUT_U8(msg, IFLA_BOND_USE_CARRIER, !!props->use_carrier); + + break; + } case NM_LINK_TYPE_VLAN: { const NMPlatformLnkVlan *props = extra_data; @@ -4655,8 +4966,8 @@ nla_put_failure: } static struct nl_msg * -_nl_msg_new_link_full(int nlmsg_type, - int nlmsg_flags, +_nl_msg_new_link_full(uint16_t nlmsg_type, + uint16_t nlmsg_flags, int ifindex, const char *ifname, guint8 family, @@ -4688,22 +4999,22 @@ nla_put_failure: } static struct nl_msg * -_nl_msg_new_link(int nlmsg_type, int nlmsg_flags, int ifindex, const char *ifname) +_nl_msg_new_link(uint16_t nlmsg_type, uint16_t nlmsg_flags, int ifindex, const char *ifname) { return _nl_msg_new_link_full(nlmsg_type, nlmsg_flags, ifindex, ifname, AF_UNSPEC, 0, 0); } /* Copied and modified from libnl3's build_addr_msg(). */ static struct nl_msg * -_nl_msg_new_address(int nlmsg_type, - int nlmsg_flags, +_nl_msg_new_address(uint16_t nlmsg_type, + uint16_t nlmsg_flags, int family, int ifindex, gconstpointer address, guint8 plen, gconstpointer peer_address, guint32 flags, - int scope, + guint8 scope, guint32 lifetime, guint32 preferred, in_addr_t ip4_broadcast_address, @@ -4715,6 +5026,7 @@ _nl_msg_new_address(int nlmsg_type, .ifa_index = ifindex, .ifa_prefixlen = plen, .ifa_flags = flags, + .ifa_scope = scope, }; gsize addr_len; @@ -4723,15 +5035,6 @@ _nl_msg_new_address(int nlmsg_type, msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags); - if (scope == -1) { - /* Allow having scope unset, and detect the scope (including IPv4 compatibility hack). */ - if (family == AF_INET && address && *((char *) address) == 127) - scope = RT_SCOPE_HOST; - else - scope = RT_SCOPE_UNIVERSE; - } - am.ifa_scope = scope, - addr_len = family == AF_INET ? sizeof(in_addr_t) : sizeof(struct in6_addr); if (nlmsg_append_struct(msg, &am) < 0) @@ -4783,7 +5086,8 @@ ip_route_get_lock_flag(const NMPlatformIPRoute *route) | (((guint32) route->lock_cwnd) << RTAX_CWND) | (((guint32) route->lock_initcwnd) << RTAX_INITCWND) | (((guint32) route->lock_initrwnd) << RTAX_INITRWND) - | (((guint32) route->lock_mtu) << RTAX_MTU); + | (((guint32) route->lock_mtu) << RTAX_MTU) + | (((guint32) route->lock_mss) << RTAX_ADVMSS); } static gboolean @@ -4809,7 +5113,7 @@ ip_route_ignored_protocol(const NMPlatformIPRoute *route) /* Copied and modified from libnl3's build_route_msg() and rtnl_route_build_msg(). */ static struct nl_msg * -_nl_msg_new_route(int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj) +_nl_msg_new_route(uint16_t nlmsg_type, uint16_t nlmsg_flags, const NMPObject *obj) { nm_auto_nlmsg struct nl_msg *msg = NULL; const NMPClass *klass = NMP_OBJECT_GET_CLASS(obj); @@ -4836,7 +5140,7 @@ _nl_msg_new_route(int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj) NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); nm_assert(NM_IN_SET(nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE)); - msg = nlmsg_alloc_simple(nlmsg_type, (int) nlmsgflags); + msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags); if (nlmsg_append_struct(msg, &rtmsg) < 0) goto nla_put_failure; @@ -4871,7 +5175,8 @@ _nl_msg_new_route(int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj) } if (obj->ip_route.mss || obj->ip_route.window || obj->ip_route.cwnd || obj->ip_route.initcwnd - || obj->ip_route.initrwnd || obj->ip_route.mtu || lock) { + || obj->ip_route.initrwnd || obj->ip_route.mtu || obj->ip_route.quickack + || obj->ip_route.rto_min || lock) { struct nlattr *metrics; metrics = nla_nest_start(msg, RTA_METRICS); @@ -4890,6 +5195,10 @@ _nl_msg_new_route(int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj) NLA_PUT_U32(msg, RTAX_INITRWND, obj->ip_route.initrwnd); if (obj->ip_route.mtu) NLA_PUT_U32(msg, RTAX_MTU, obj->ip_route.mtu); + if (obj->ip_route.rto_min) + NLA_PUT_U32(msg, RTAX_RTO_MIN, obj->ip_route.rto_min); + if (obj->ip_route.quickack) + NLA_PUT_U32(msg, RTAX_QUICKACK, obj->ip_route.quickack); if (lock) NLA_PUT_U32(msg, RTAX_LOCK, lock); @@ -4915,7 +5224,9 @@ nla_put_failure: } static struct nl_msg * -_nl_msg_new_routing_rule(int nlmsg_type, int nlmsg_flags, const NMPlatformRoutingRule *routing_rule) +_nl_msg_new_routing_rule(uint16_t nlmsg_type, + uint16_t nlmsg_flags, + const NMPlatformRoutingRule *routing_rule) { nm_auto_nlmsg struct nl_msg *msg = NULL; const guint8 addr_size = nm_utils_addr_family_to_size(routing_rule->addr_family); @@ -5028,7 +5339,7 @@ nla_put_failure: } static struct nl_msg * -_nl_msg_new_qdisc(int nlmsg_type, int nlmsg_flags, const NMPlatformQdisc *qdisc) +_nl_msg_new_qdisc(uint16_t nlmsg_type, uint16_t nlmsg_flags, const NMPlatformQdisc *qdisc) { nm_auto_nlmsg struct nl_msg *msg = NULL; struct nlattr *tc_options; @@ -5115,7 +5426,7 @@ nla_put_failure: } static struct nl_msg * -_nl_msg_new_tfilter(int nlmsg_type, int nlmsg_flags, const NMPlatformTfilter *tfilter) +_nl_msg_new_tfilter(uint16_t nlmsg_type, uint16_t nlmsg_flags, const NMPlatformTfilter *tfilter) { nm_auto_nlmsg struct nl_msg *msg = NULL; struct nlattr *tc_options; @@ -5154,7 +5465,7 @@ _nl_msg_new_tfilter(int nlmsg_type, int nlmsg_flags, const NMPlatformTfilter *tf if (nm_streq(action->kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) { const NMPlatformActionSimple *simple = &action->simple; struct tc_defact sel = { - 0, + 0, }; if (!(act_options = nla_nest_start(msg, TCA_ACT_OPTIONS))) @@ -5168,7 +5479,7 @@ _nl_msg_new_tfilter(int nlmsg_type, int nlmsg_flags, const NMPlatformTfilter *tf } else if (nm_streq(action->kind, NM_PLATFORM_ACTION_KIND_MIRRED)) { const NMPlatformActionMirred *mirred = &action->mirred; struct tc_mirred sel = { - 0, + 0, }; if (!(act_options = nla_nest_start(msg, TCA_ACT_OPTIONS))) @@ -5204,14 +5515,6 @@ nla_put_failure: /*****************************************************************************/ -static struct nl_sock * -_genl_sock(NMLinuxPlatform *platform) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - - return priv->genl; -} - #define ASSERT_SYSCTL_ARGS(pathid, dirfd, path) \ G_STMT_START \ { \ @@ -5781,7 +6084,10 @@ sysctl_get(NMPlatform *platform, const char *pathid, int dirfd, const char *path static void process_events(NMPlatform *platform) { - delayed_action_handle_all(platform, TRUE); + delayed_action_schedule(platform, + DELAYED_ACTION_TYPE_READ_RTNL | DELAYED_ACTION_TYPE_READ_GENL, + NULL); + delayed_action_handle_all(platform); } /*****************************************************************************/ @@ -5789,27 +6095,34 @@ process_events(NMPlatform *platform) static const RefreshAllInfo * refresh_all_type_get_info(RefreshAllType refresh_all_type) { +#define R(_protocol, _refresh_all_type, _obj_type, _addr_family) \ + [_refresh_all_type] = { \ + .protocol = _protocol, \ + .obj_type = _obj_type, \ + .addr_family_for_dump = _addr_family, \ + } +#define R_ROUTE(...) R(NMP_NETLINK_ROUTE, __VA_ARGS__) +#define R_GENERIC(...) R(NMP_NETLINK_GENERIC, __VA_ARGS__) static const RefreshAllInfo infos[] = { -#define R(_refresh_all_type, _obj_type, _addr_family) \ - [_refresh_all_type] = { \ - .obj_type = _obj_type, \ - .addr_family = _addr_family, \ - } - R(REFRESH_ALL_TYPE_LINKS, NMP_OBJECT_TYPE_LINK, AF_UNSPEC), - R(REFRESH_ALL_TYPE_IP4_ADDRESSES, NMP_OBJECT_TYPE_IP4_ADDRESS, AF_UNSPEC), - R(REFRESH_ALL_TYPE_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS, AF_UNSPEC), - R(REFRESH_ALL_TYPE_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE, AF_UNSPEC), - R(REFRESH_ALL_TYPE_IP6_ROUTES, NMP_OBJECT_TYPE_IP6_ROUTE, AF_UNSPEC), - R(REFRESH_ALL_TYPE_ROUTING_RULES_IP4, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET), - R(REFRESH_ALL_TYPE_ROUTING_RULES_IP6, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET6), - R(REFRESH_ALL_TYPE_QDISCS, NMP_OBJECT_TYPE_QDISC, AF_UNSPEC), - R(REFRESH_ALL_TYPE_TFILTERS, NMP_OBJECT_TYPE_TFILTER, AF_UNSPEC), -#undef R + R_ROUTE(REFRESH_ALL_TYPE_RTNL_LINKS, NMP_OBJECT_TYPE_LINK, AF_UNSPEC), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_IP4_ADDRESSES, NMP_OBJECT_TYPE_IP4_ADDRESS, AF_UNSPEC), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS, AF_UNSPEC), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE, AF_UNSPEC), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_IP6_ROUTES, NMP_OBJECT_TYPE_IP6_ROUTE, AF_UNSPEC), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET6), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_QDISCS, NMP_OBJECT_TYPE_QDISC, AF_UNSPEC), + R_ROUTE(REFRESH_ALL_TYPE_RTNL_TFILTERS, NMP_OBJECT_TYPE_TFILTER, AF_UNSPEC), + R_GENERIC(REFRESH_ALL_TYPE_GENL_FAMILIES, NMP_OBJECT_TYPE_UNKNOWN, AF_UNSPEC), }; +#undef R_GENERIC +#undef R_ROUTE +#undef R nm_assert(_NM_INT_NOT_NEGATIVE(refresh_all_type)); nm_assert(refresh_all_type < G_N_ELEMENTS(infos)); - nm_assert(nmp_class_from_type(infos[refresh_all_type].obj_type)); + nm_assert(refresh_all_type == REFRESH_ALL_TYPE_GENL_FAMILIES + || nmp_class_from_type(infos[refresh_all_type].obj_type)); return &infos[refresh_all_type]; } @@ -5819,19 +6132,24 @@ static NM_UTILS_LOOKUP_DEFINE( DelayedActionType, RefreshAllType, NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT(0), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, REFRESH_ALL_TYPE_LINKS), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, - REFRESH_ALL_TYPE_IP4_ADDRESSES), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, - REFRESH_ALL_TYPE_IP6_ADDRESSES), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, REFRESH_ALL_TYPE_IP4_ROUTES), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, REFRESH_ALL_TYPE_IP6_ROUTES), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4, - REFRESH_ALL_TYPE_ROUTING_RULES_IP4), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, - REFRESH_ALL_TYPE_ROUTING_RULES_IP6), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, REFRESH_ALL_TYPE_QDISCS), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, REFRESH_ALL_TYPE_TFILTERS), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_LINKS, REFRESH_ALL_TYPE_RTNL_LINKS), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ADDRESSES, + REFRESH_ALL_TYPE_RTNL_IP4_ADDRESSES), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ADDRESSES, + REFRESH_ALL_TYPE_RTNL_IP6_ADDRESSES), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES, + REFRESH_ALL_TYPE_RTNL_IP4_ROUTES), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES, + REFRESH_ALL_TYPE_RTNL_IP6_ROUTES), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP4, + REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP6, + REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS, REFRESH_ALL_TYPE_RTNL_QDISCS), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS, + REFRESH_ALL_TYPE_RTNL_TFILTERS), + NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_GENL_FAMILIES, + REFRESH_ALL_TYPE_GENL_FAMILIES), NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER(), ); static DelayedActionType @@ -5853,25 +6171,25 @@ refresh_all_type_from_needle_object(const NMPObject *obj_needle) { switch (NMP_OBJECT_GET_TYPE(obj_needle)) { case NMP_OBJECT_TYPE_LINK: - return REFRESH_ALL_TYPE_LINKS; + return REFRESH_ALL_TYPE_RTNL_LINKS; case NMP_OBJECT_TYPE_IP4_ADDRESS: - return REFRESH_ALL_TYPE_IP4_ADDRESSES; + return REFRESH_ALL_TYPE_RTNL_IP4_ADDRESSES; case NMP_OBJECT_TYPE_IP6_ADDRESS: - return REFRESH_ALL_TYPE_IP6_ADDRESSES; + return REFRESH_ALL_TYPE_RTNL_IP6_ADDRESSES; case NMP_OBJECT_TYPE_IP4_ROUTE: - return REFRESH_ALL_TYPE_IP4_ROUTES; + return REFRESH_ALL_TYPE_RTNL_IP4_ROUTES; case NMP_OBJECT_TYPE_IP6_ROUTE: - return REFRESH_ALL_TYPE_IP6_ROUTES; + return REFRESH_ALL_TYPE_RTNL_IP6_ROUTES; case NMP_OBJECT_TYPE_QDISC: - return REFRESH_ALL_TYPE_QDISCS; + return REFRESH_ALL_TYPE_RTNL_QDISCS; case NMP_OBJECT_TYPE_TFILTER: - return REFRESH_ALL_TYPE_TFILTERS; + return REFRESH_ALL_TYPE_RTNL_TFILTERS; case NMP_OBJECT_TYPE_ROUTING_RULE: switch (NMP_OBJECT_CAST_ROUTING_RULE(obj_needle)->addr_family) { case AF_INET: - return REFRESH_ALL_TYPE_ROUTING_RULES_IP4; + return REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4; case AF_INET6: - return REFRESH_ALL_TYPE_ROUTING_RULES_IP6; + return REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6; } nm_assert_not_reached(); return 0; @@ -5895,11 +6213,11 @@ refresh_all_type_init_lookup(RefreshAllType refresh_all_type, NMPLookup *lookup) if (NM_IN_SET(refresh_all_info->obj_type, NMP_OBJECT_TYPE_ROUTING_RULE)) { return nmp_lookup_init_object_by_addr_family(lookup, refresh_all_info->obj_type, - refresh_all_info->addr_family); + refresh_all_info->addr_family_for_dump); } /* not yet implemented. */ - nm_assert(refresh_all_info->addr_family == AF_UNSPEC); + nm_assert(refresh_all_info->addr_family_for_dump == AF_UNSPEC); return nmp_lookup_init_obj_type(lookup, refresh_all_info->obj_type); } @@ -5915,28 +6233,42 @@ static NM_UTILS_LOOKUP_STR_DEFINE( delayed_action_to_string, DelayedActionType, NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT("unknown"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, "refresh-all-links"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, - "refresh-all-ip4-addresses"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, - "refresh-all-ip6-addresses"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, "refresh-all-ip4-routes"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, "refresh-all-ip6-routes"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4, - "refresh-all-routing-rules-ip4"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, - "refresh-all-routing-rules-ip6"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, "refresh-all-qdiscs"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, "refresh-all-tfilters"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_LINKS, "refresh-all-rtnl-links"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ADDRESSES, + "refresh-all-rtnl-ip4-addresses"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ADDRESSES, + "refresh-all-rtnl-ip6-addresses"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES, + "refresh-all-rtnl-ip4-routes"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES, + "refresh-all-rtnl-ip6-routes"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP4, + "refresh-all-rtnl-routing-rules-ip4"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_IP6, + "refresh-all-rtnl-routing-rules-ip6"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS, + "refresh-all-rtnl-qdiscs"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS, + "refresh-all-rtnl-tfilters"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_GENL_FAMILIES, + "refresh-all-genl-families"), NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_LINK, "refresh-link"), NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_MASTER_CONNECTED, "master-connected"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_READ_NETLINK, "read-netlink"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, "wait-for-nl-response"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_READ_RTNL, "read-rtnl"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_READ_GENL, "read-genl"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL, "wait-for-response-rtnl"), + NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_GENL, "wait-for-response-genl"), NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_NONE), - NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_REFRESH_ALL), - NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL), + NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL), + NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL), NM_UTILS_LOOKUP_ITEM_IGNORE(__DELAYED_ACTION_TYPE_MAX), ); +#define delayed_action_get_list_wait_for_resonse(priv, netlink_protocol, idx) \ + (&g_array_index((priv)->delayed_action.list_wait_for_response_x[nmp_netlink_protocol_check( \ + (netlink_protocol))], \ + DelayedActionWaitForNlResponseData, \ + (idx))) + static const char * delayed_action_to_string_full(DelayedActionType action_type, gpointer user_data, @@ -5947,6 +6279,7 @@ delayed_action_to_string_full(DelayedActionType action_type, const DelayedActionWaitForNlResponseData *data; nm_strbuf_append_str(&buf, &buf_size, delayed_action_to_string(action_type)); + switch (action_type) { case DELAYED_ACTION_TYPE_MASTER_CONNECTED: nm_strbuf_append(&buf, &buf_size, " (master-ifindex %d)", GPOINTER_TO_INT(user_data)); @@ -5954,7 +6287,8 @@ delayed_action_to_string_full(DelayedActionType action_type, case DELAYED_ACTION_TYPE_REFRESH_LINK: nm_strbuf_append(&buf, &buf_size, " (ifindex %d)", GPOINTER_TO_INT(user_data)); break; - case DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE: + case DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL: + case DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_GENL: data = user_data; if (data) { @@ -6005,8 +6339,8 @@ delayed_action_refresh_all_in_progress(NMPlatform *platform, DelayedActionType a RefreshAllType refresh_all_type; nm_assert(nm_utils_is_power_of_two(action_type)); - nm_assert(NM_FLAGS_ANY(action_type, DELAYED_ACTION_TYPE_REFRESH_ALL)); - nm_assert(!NM_FLAGS_ANY(action_type, ~DELAYED_ACTION_TYPE_REFRESH_ALL)); + nm_assert(NM_FLAGS_ANY(action_type, DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL)); + nm_assert(!NM_FLAGS_ANY(action_type, ~DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL)); if (NM_FLAGS_ANY(priv->delayed_action.flags, action_type)) return TRUE; @@ -6016,25 +6350,26 @@ delayed_action_refresh_all_in_progress(NMPlatform *platform, DelayedActionType a } static void -delayed_action_wait_for_nl_response_complete(NMPlatform *platform, - guint idx, - WaitForNlResponseResult seq_result) +delayed_action_wait_for_response_complete(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + guint idx, + WaitForNlResponseResult seq_result) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); DelayedActionWaitForNlResponseData *data; + const DelayedActionType ACTION_TYPE = + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response; - nm_assert(NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)); - nm_assert(idx < priv->delayed_action.list_wait_for_nl_response->len); + nm_assert(NM_FLAGS_ANY(priv->delayed_action.flags, ACTION_TYPE)); + nm_assert(idx < priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len); nm_assert(seq_result); - data = &g_array_index(priv->delayed_action.list_wait_for_nl_response, - DelayedActionWaitForNlResponseData, - idx); + data = delayed_action_get_list_wait_for_resonse(priv, netlink_protocol, idx); - _LOGt_delayed_action(DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, data, "complete"); + _LOGt_delayed_action(ACTION_TYPE, data, "complete"); - if (priv->delayed_action.list_wait_for_nl_response->len <= 1) - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE; + if (priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len <= 1) + priv->delayed_action.flags &= ~ACTION_TYPE; if (data->out_seq_result) *data->out_seq_result = seq_result; switch (data->response_type) { @@ -6055,15 +6390,16 @@ delayed_action_wait_for_nl_response_complete(NMPlatform *platform, break; } - g_array_remove_index_fast(priv->delayed_action.list_wait_for_nl_response, idx); + g_array_remove_index_fast(priv->delayed_action.list_wait_for_response_x[netlink_protocol], idx); } static void -delayed_action_wait_for_nl_response_complete_check(NMPlatform *platform, - WaitForNlResponseResult force_result, - guint32 *out_next_seq_number, - gint64 *out_next_timeout_abs_ns, - gint64 *p_now_nsec) +delayed_action_wait_for_response_complete_check(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + WaitForNlResponseResult force_result, + guint32 *out_next_seq_number, + gint64 *out_next_timeout_abs_ns, + gint64 *p_now_nsec) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); guint i; @@ -6071,24 +6407,25 @@ delayed_action_wait_for_nl_response_complete_check(NMPlatform *platf gint64 next_timeout_abs_ns = 0; gint64 now_nsec = 0; - for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len;) { + for (i = 0; i < priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len;) { const DelayedActionWaitForNlResponseData *data = - &g_array_index(priv->delayed_action.list_wait_for_nl_response, - DelayedActionWaitForNlResponseData, - i); + delayed_action_get_list_wait_for_resonse(priv, netlink_protocol, i); if (data->seq_result) - delayed_action_wait_for_nl_response_complete(platform, i, data->seq_result); + delayed_action_wait_for_response_complete(platform, + netlink_protocol, + i, + data->seq_result); else if (p_now_nsec && ((now_nsec ?: (now_nsec = nm_utils_get_monotonic_timestamp_nsec())) >= data->timeout_abs_nsec)) { /* the caller can optionally check for timeout by providing a p_now_nsec argument. */ - delayed_action_wait_for_nl_response_complete( - platform, - i, - WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT); + delayed_action_wait_for_response_complete(platform, + netlink_protocol, + i, + WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT); } else if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) - delayed_action_wait_for_nl_response_complete(platform, i, force_result); + delayed_action_wait_for_response_complete(platform, netlink_protocol, i, force_result); else { if (next_seq_number == 0 || next_timeout_abs_ns > data->timeout_abs_nsec) { next_seq_number = data->seq_number; @@ -6099,9 +6436,10 @@ delayed_action_wait_for_nl_response_complete_check(NMPlatform *platf } if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) { - nm_assert( - !NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)); - nm_assert(priv->delayed_action.list_wait_for_nl_response->len == 0); + nm_assert(!NM_FLAGS_ANY( + priv->delayed_action.flags, + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response)); + nm_assert(priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len == 0); } NM_SET_OUT(out_next_seq_number, next_seq_number); @@ -6111,9 +6449,15 @@ delayed_action_wait_for_nl_response_complete_check(NMPlatform *platf static void delayed_action_wait_for_nl_response_complete_all(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, WaitForNlResponseResult fallback_result) { - delayed_action_wait_for_nl_response_complete_check(platform, fallback_result, NULL, NULL, NULL); + delayed_action_wait_for_response_complete_check(platform, + nmp_netlink_protocol_check(netlink_protocol), + fallback_result, + NULL, + NULL, + NULL); } /*****************************************************************************/ @@ -6148,15 +6492,15 @@ delayed_action_handle_REFRESH_ALL(NMPlatform *platform, DelayedActionType flags) } static void -delayed_action_handle_READ_NETLINK(NMPlatform *platform) +delayed_action_handle_READ_NETLINK(NMPlatform *platform, NMPNetlinkProtocol netlink_protocol) { - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, netlink_protocol, FALSE); } static void -delayed_action_handle_WAIT_FOR_NL_RESPONSE(NMPlatform *platform) +delayed_action_handle_WAIT_FOR_RESPONSE(NMPlatform *platform, NMPNetlinkProtocol netlink_protocol) { - event_handler_read_netlink(platform, TRUE); + event_handler_read_netlink(platform, netlink_protocol, TRUE); } static gboolean @@ -6164,6 +6508,8 @@ delayed_action_handle_one(NMPlatform *platform) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); gpointer user_data; + NMPNetlinkProtocol netlink_protocol; + DelayedActionType iflags; if (priv->delayed_action.flags == DELAYED_ACTION_TYPE_NONE) return FALSE; @@ -6190,28 +6536,46 @@ delayed_action_handle_one(NMPlatform *platform) } nm_assert(priv->delayed_action.list_master_connected->len == 0); - /* Next we prefer read-netlink, because the buffer size is limited and we want to process events + /* Next we prefer read-genl/read-rtnl, because the buffer size is limited and we want to process events * from netlink early. */ - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_READ_NETLINK)) { - _LOGt_delayed_action(DELAYED_ACTION_TYPE_READ_NETLINK, NULL, "handle"); - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_READ_NETLINK; - delayed_action_handle_READ_NETLINK(platform); - return TRUE; + for (netlink_protocol = _NMP_NETLINK_FIRST; netlink_protocol < _NMP_NETLINK_NUM; + netlink_protocol++) { + const DelayedActionType ACTION_TYPE = + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_read; + + if (NM_FLAGS_ANY(priv->delayed_action.flags, ACTION_TYPE)) { + _LOGt_delayed_action(ACTION_TYPE, NULL, "handle"); + priv->delayed_action.flags &= ~ACTION_TYPE; + delayed_action_handle_READ_NETLINK(platform, netlink_protocol); + return TRUE; + } } - if (NM_FLAGS_ANY(priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_ALL)) { - DelayedActionType flags, iflags; + if (NM_FLAGS_ANY(priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_GENL_ALL)) { + const DelayedActionType FLAGS = + priv->delayed_action.flags & DELAYED_ACTION_TYPE_REFRESH_GENL_ALL; + + if (_LOGt_ENABLED()) { + FOR_EACH_DELAYED_ACTION (iflags, FLAGS) + _LOGt_delayed_action(iflags, NULL, "handle"); + } - flags = priv->delayed_action.flags & DELAYED_ACTION_TYPE_REFRESH_ALL; + priv->delayed_action.flags &= ~FLAGS; + delayed_action_handle_REFRESH_ALL(platform, FLAGS); + return TRUE; + } - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_ALL; + if (NM_FLAGS_ANY(priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL)) { + const DelayedActionType FLAGS = + (priv->delayed_action.flags & DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL); if (_LOGt_ENABLED()) { - FOR_EACH_DELAYED_ACTION (iflags, flags) + FOR_EACH_DELAYED_ACTION (iflags, FLAGS) _LOGt_delayed_action(iflags, NULL, "handle"); } - delayed_action_handle_REFRESH_ALL(platform, flags); + priv->delayed_action.flags &= ~FLAGS; + delayed_action_handle_REFRESH_ALL(platform, FLAGS); return TRUE; } @@ -6235,18 +6599,24 @@ delayed_action_handle_one(NMPlatform *platform) return TRUE; } - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) { - nm_assert(priv->delayed_action.list_wait_for_nl_response->len > 0); - _LOGt_delayed_action(DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, NULL, "handle"); - delayed_action_handle_WAIT_FOR_NL_RESPONSE(platform); - return TRUE; + for (netlink_protocol = _NMP_NETLINK_FIRST; netlink_protocol < _NMP_NETLINK_NUM; + netlink_protocol++) { + const DelayedActionType ACTION_TYPE = + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response; + + if (NM_FLAGS_ANY(priv->delayed_action.flags, ACTION_TYPE)) { + nm_assert(priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len > 0); + _LOGt_delayed_action(ACTION_TYPE, NULL, "handle"); + delayed_action_handle_WAIT_FOR_RESPONSE(platform, netlink_protocol); + return TRUE; + } } return FALSE; } static gboolean -delayed_action_handle_all(NMPlatform *platform, gboolean read_netlink) +delayed_action_handle_all(NMPlatform *platform) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); gboolean any = FALSE; @@ -6254,8 +6624,6 @@ delayed_action_handle_all(NMPlatform *platform, gboolean read_netlink) g_return_val_if_fail(priv->delayed_action.is_handling == 0, FALSE); priv->delayed_action.is_handling++; - if (read_netlink) - delayed_action_schedule(platform, DELAYED_ACTION_TYPE_READ_NETLINK, NULL); while (delayed_action_handle_one(platform)) any = TRUE; priv->delayed_action.is_handling--; @@ -6290,14 +6658,21 @@ delayed_action_schedule(NMPlatform *platform, DelayedActionType action_type, gpo < 0) g_ptr_array_add(priv->delayed_action.list_master_connected, user_data); break; - case DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE: - g_array_append_vals(priv->delayed_action.list_wait_for_nl_response, user_data, 1); + case DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL: + g_array_append_vals(priv->delayed_action.list_wait_for_response_rtnl, user_data, 1); + break; + case DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_GENL: + g_array_append_vals(priv->delayed_action.list_wait_for_response_genl, user_data, 1); break; default: + /* For other action types, we support setting multiple flags at once. They + * also don't have any user-data. */ nm_assert(!user_data); - nm_assert(!NM_FLAGS_HAS(action_type, DELAYED_ACTION_TYPE_REFRESH_LINK)); - nm_assert(!NM_FLAGS_HAS(action_type, DELAYED_ACTION_TYPE_MASTER_CONNECTED)); - nm_assert(!NM_FLAGS_HAS(action_type, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)); + nm_assert(!NM_FLAGS_ANY(action_type, + DELAYED_ACTION_TYPE_REFRESH_LINK + | DELAYED_ACTION_TYPE_MASTER_CONNECTED + | DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL + | DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_GENL)); break; } @@ -6310,12 +6685,37 @@ delayed_action_schedule(NMPlatform *platform, DelayedActionType action_type, gpo } static void -delayed_action_schedule_WAIT_FOR_NL_RESPONSE(NMPlatform *platform, - guint32 seq_number, - WaitForNlResponseResult *out_seq_result, - char **out_errmsg, - DelayedActionWaitForNlResponseType response_type, - gpointer response_out_data) +delayed_action_schedule_refresh_all(NMPlatform *platform, NMPNetlinkProtocol netlink_protocol) +{ + DelayedActionType action_type; + + if (netlink_protocol == NMP_NETLINK_ROUTE) { + action_type = DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_LINKS + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL; + if (nm_platform_get_cache_tc(platform)) { + action_type |= (DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS); + } + } else { + nm_assert(netlink_protocol == NMP_NETLINK_GENERIC); + action_type = DELAYED_ACTION_TYPE_REFRESH_ALL_GENL_FAMILIES; + } + + delayed_action_schedule(platform, action_type, NULL); +} + +static void +delayed_action_schedule_WAIT_FOR_RESPONSE(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + guint32 seq_number, + WaitForNlResponseResult *out_seq_result, + char **out_errmsg, + DelayedActionWaitForNlResponseType response_type, + gpointer response_out_data) { DelayedActionWaitForNlResponseData data = { .seq_number = seq_number, @@ -6327,7 +6727,10 @@ delayed_action_schedule_WAIT_FOR_NL_RESPONSE(NMPlatform * .response.out_data = response_out_data, }; - delayed_action_schedule(platform, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, &data); + delayed_action_schedule( + platform, + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response, + &data); } /*****************************************************************************/ @@ -6379,6 +6782,9 @@ cache_prune_all(NMPlatform *platform) if (priv->pruning[refresh_all_type] == 0) continue; + + nm_assert(refresh_all_type != REFRESH_ALL_TYPE_GENL_FAMILIES); + priv->pruning[refresh_all_type] -= 1; if (priv->pruning[refresh_all_type] > 0) continue; @@ -6462,15 +6868,18 @@ cache_on_change(NMPlatform *platform, ifindex = obj_new->link.ifindex; if (ifindex > 0) { - delayed_action_schedule(platform, - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL - | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS - | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, - NULL); + delayed_action_schedule( + platform, + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ADDRESSES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL + | (nm_platform_get_cache_tc(platform) + ? (DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_QDISCS + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_TFILTERS) + : DELAYED_ACTION_TYPE_NONE), + NULL); } } { @@ -6518,8 +6927,8 @@ cache_on_change(NMPlatform *platform, * think kernel does send RTM_DELROUTE events for IPv6 routes, so * we might not need to refresh IPv6 routes. */ delayed_action_schedule(platform, - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES + | DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES, NULL); } } @@ -6627,8 +7036,8 @@ cache_on_change(NMPlatform *platform, if (cache_op == NMP_CACHE_OPS_REMOVED) { delayed_action_schedule(platform, (klass->obj_type == NMP_OBJECT_TYPE_IP4_ADDRESS) - ? DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - : DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + ? DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP4_ROUTES + : DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_IP6_ROUTES, NULL); } } break; @@ -6640,12 +7049,14 @@ cache_on_change(NMPlatform *platform, /*****************************************************************************/ static guint32 -_nlh_seq_next_get(NMLinuxPlatformPrivate *priv) +_nlh_seq_next_get(NMLinuxPlatformPrivate *priv, NMPNetlinkProtocol netlink_protocol) { + guint32 *p = &priv->proto_data_x[netlink_protocol].nlh_seq_next; + /* generate a new sequence number, but never return zero. * Wrapping numbers are not a problem, because we don't rely * on strictly increasing sequence numbers. */ - return (++priv->nlh_seq_next) ?: (++priv->nlh_seq_next); + return (++(*p)) ?: (++(*p)); } /** @@ -6672,7 +7083,7 @@ _nl_send_nlmsghdr(NMPlatform *platform, nm_assert(nlhdr); - seq = _nlh_seq_next_get(priv); + seq = _nlh_seq_next_get(priv, NMP_NETLINK_ROUTE); nlhdr->nlmsg_seq = seq; { @@ -6689,12 +7100,12 @@ _nl_send_nlmsghdr(NMPlatform *platform, int try_count; if (!nlhdr->nlmsg_pid) - nlhdr->nlmsg_pid = nl_socket_get_local_port(priv->nlh); + nlhdr->nlmsg_pid = nl_socket_get_local_port(priv->sk_rtnl); nlhdr->nlmsg_flags |= (NLM_F_REQUEST | NLM_F_ACK); try_count = 0; again: - errsv = sendmsg(nl_socket_get_fd(priv->nlh), &msg, 0); + errsv = sendmsg(nl_socket_get_fd(priv->sk_rtnl), &msg, 0); if (errsv < 0) { errsv = errno; if (errsv == EINTR && try_count++ < 100) @@ -6706,32 +7117,24 @@ again: } } - delayed_action_schedule_WAIT_FOR_NL_RESPONSE(platform, - seq, - out_seq_result, - out_errmsg, - response_type, - response_out_data); + delayed_action_schedule_WAIT_FOR_RESPONSE(platform, + NMP_NETLINK_ROUTE, + seq, + out_seq_result, + out_errmsg, + response_type, + response_out_data); return 0; } -/** - * _nl_send_nlmsg: - * @platform: - * @nlmsg: - * @out_seq_result: - * @response_type: - * @response_out_data: - * - * Returns: 0 on success, or a negative libnl3 error code (beware, it's not an errno). - */ static int -_nl_send_nlmsg(NMPlatform *platform, - struct nl_msg *nlmsg, - WaitForNlResponseResult *out_seq_result, - char **out_errmsg, - DelayedActionWaitForNlResponseType response_type, - gpointer response_out_data) +_netlink_send_nlmsg(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + struct nl_msg *nlmsg, + WaitForNlResponseResult *out_seq_result, + char **out_errmsg, + DelayedActionWaitForNlResponseType response_type, + gpointer response_out_data) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); struct nlmsghdr *nlhdr; @@ -6739,24 +7142,40 @@ _nl_send_nlmsg(NMPlatform *platform, int nle; nlhdr = nlmsg_hdr(nlmsg); - seq = _nlh_seq_next_get(priv); + seq = _nlh_seq_next_get(priv, netlink_protocol); nlhdr->nlmsg_seq = seq; - nle = nl_send_auto(priv->nlh, nlmsg); + nle = nl_send_auto(priv->sk_x[netlink_protocol], nlmsg); if (nle < 0) { _LOGD("netlink: nl-send-nlmsg: failed sending message: %s (%d)", nm_strerror(nle), nle); return nle; } - delayed_action_schedule_WAIT_FOR_NL_RESPONSE(platform, - seq, - out_seq_result, - out_errmsg, - response_type, - response_out_data); + delayed_action_schedule_WAIT_FOR_RESPONSE(platform, + netlink_protocol, + seq, + out_seq_result, + out_errmsg, + response_type, + response_out_data); return 0; } +static int +_netlink_send_nlmsg_rtnl(NMPlatform *platform, + struct nl_msg *nlmsg, + WaitForNlResponseResult *out_seq_result, + char **out_errmsg) +{ + return _netlink_send_nlmsg(platform, + NMP_NETLINK_ROUTE, + nlmsg, + out_seq_result, + out_errmsg, + DELAYED_ACTION_RESPONSE_TYPE_VOID, + NULL); +} + static void do_request_link_no_delayed_actions(NMPlatform *platform, int ifindex, const char *name) { @@ -6776,16 +7195,16 @@ do_request_link_no_delayed_actions(NMPlatform *platform, int ifindex, const char entry = nmp_cache_lookup_entry_link(nm_platform_get_cache(platform), ifindex); if (entry) { - priv->pruning[REFRESH_ALL_TYPE_LINKS] += 1; + priv->pruning[REFRESH_ALL_TYPE_RTNL_LINKS] += 1; nm_dedup_multi_entry_set_dirty(entry, TRUE); } } - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); nlmsg = _nl_msg_new_link(RTM_GETLINK, 0, ifindex, name); if (nlmsg) { - nle = _nl_send_nlmsg(platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); + nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, NULL, NULL); if (nle < 0) { _LOGE("do-request-link: %d %s: failed sending netlink request \"%s\" (%d)", ifindex, @@ -6801,11 +7220,11 @@ static void do_request_link(NMPlatform *platform, int ifindex, const char *name) { do_request_link_no_delayed_actions(platform, ifindex, name); - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); } static struct nl_msg * -_nl_msg_new_dump(NMPObjectType obj_type, int preferred_addr_family) +_nl_msg_new_dump_rtnl(NMPObjectType obj_type, int preferred_addr_family) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; const NMPClass *klass; @@ -6855,6 +7274,26 @@ _nl_msg_new_dump(NMPObjectType obj_type, int preferred_addr_family) return g_steal_pointer(&nlmsg); } +static struct nl_msg * +_nl_msg_new_dump_genl_families(void) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + + nlmsg = nlmsg_alloc_size(nlmsg_total_size(GENL_HDRLEN)); + + if (!genlmsg_put(nlmsg, + NL_AUTO_PORT, + NL_AUTO_SEQ, + GENL_ID_CTRL, + 0, + NLM_F_DUMP, + CTRL_CMD_GETFAMILY, + 1)) + g_return_val_if_reached(NULL); + + return g_steal_pointer(&nlmsg); +} + static void do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action_type) { @@ -6862,29 +7301,36 @@ do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action DelayedActionType action_type_prune; DelayedActionType iflags; - nm_assert(!NM_FLAGS_ANY(action_type, ~DELAYED_ACTION_TYPE_REFRESH_ALL)); - action_type &= DELAYED_ACTION_TYPE_REFRESH_ALL; + nm_assert((NM_FLAGS_ANY(action_type, DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL) + && !NM_FLAGS_ANY(action_type, ~DELAYED_ACTION_TYPE_REFRESH_RTNL_ALL)) + || (NM_FLAGS_ANY(action_type, DELAYED_ACTION_TYPE_REFRESH_GENL_ALL) + && !NM_FLAGS_ANY(action_type, ~DELAYED_ACTION_TYPE_REFRESH_GENL_ALL))); action_type_prune = action_type; - /* calling nmp_cache_dirty_set_all_main() with a non-main lookup-index requires an extra - * cache lookup for every entry. - * - * Avoid that, by special casing routing-rules here. */ - if (NM_FLAGS_ALL(action_type_prune, DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL)) { + if (NM_FLAGS_ALL(action_type_prune, DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL)) { NMPLookup lookup; - priv->pruning[REFRESH_ALL_TYPE_ROUTING_RULES_IP4] += 1; - priv->pruning[REFRESH_ALL_TYPE_ROUTING_RULES_IP6] += 1; + /* calling nmp_cache_dirty_set_all_main() with a non-main lookup-index requires an extra + * cache lookup for every entry. + * + * Avoid that, by special casing routing-rules here. */ + priv->pruning[REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP4] += 1; + priv->pruning[REFRESH_ALL_TYPE_RTNL_ROUTING_RULES_IP6] += 1; nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_ROUTING_RULE); nmp_cache_dirty_set_all_main(nm_platform_get_cache(platform), &lookup); - action_type_prune &= ~DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL; + action_type_prune &= ~DELAYED_ACTION_TYPE_REFRESH_ALL_RTNL_ROUTING_RULES_ALL; } - FOR_EACH_DELAYED_ACTION (iflags, action_type_prune) { RefreshAllType refresh_all_type = delayed_action_type_to_refresh_all_type(iflags); NMPLookup lookup; + if (refresh_all_type == REFRESH_ALL_TYPE_GENL_FAMILIES) { + /* genl families are not tracked in the NMPObject cache, because there is + * only a static number of objects we care about (NMPGenlFamilyType). */ + continue; + } + priv->pruning[refresh_all_type] += 1; refresh_all_type_init_lookup(refresh_all_type, &lookup); nmp_cache_dirty_set_all_main(nm_platform_get_cache(platform), &lookup); @@ -6905,7 +7351,7 @@ do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action priv->delayed_action.flags &= ~iflags; _LOGt_delayed_action(iflags, NULL, "handle (do-request-all)"); - if (refresh_all_type == REFRESH_ALL_TYPE_LINKS) { + if (refresh_all_type == REFRESH_ALL_TYPE_RTNL_LINKS) { nm_assert( (priv->delayed_action.list_refresh_link->len > 0) == NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_LINK)); @@ -6918,23 +7364,30 @@ do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action } } - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, refresh_all_info->protocol, FALSE); + + if (refresh_all_info->protocol == NMP_NETLINK_ROUTE) { + nlmsg = _nl_msg_new_dump_rtnl(refresh_all_info->obj_type, + refresh_all_info->addr_family_for_dump); + } else { + nm_assert(refresh_all_type == REFRESH_ALL_TYPE_GENL_FAMILIES); + nlmsg = _nl_msg_new_dump_genl_families(); + } - nlmsg = _nl_msg_new_dump(refresh_all_info->obj_type, refresh_all_info->addr_family); if (!nlmsg) goto next_after_fail; - if (_nl_send_nlmsg(platform, - nlmsg, - NULL, - NULL, - DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, - out_refresh_all_in_progress) + if (_netlink_send_nlmsg(platform, + refresh_all_info->protocol, + nlmsg, + NULL, + NULL, + DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, + out_refresh_all_in_progress) < 0) goto next_after_fail; continue; - next_after_fail: nm_assert(*out_refresh_all_in_progress > 0); *out_refresh_all_in_progress -= 1; @@ -6946,102 +7399,109 @@ do_request_one_type_by_needle_object(NMPlatform *platform, const NMPObject *obj_ { do_request_all_no_delayed_actions(platform, delayed_action_refresh_from_needle_object(obj_needle)); - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); } static void -event_seq_check_refresh_all(NMPlatform *platform, guint32 seq_number) +event_seq_check_refresh_all(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + guint32 seq_number) { - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - DelayedActionWaitForNlResponseData *data; - guint i; + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); + guint i; - if (NM_IN_SET(seq_number, 0, priv->nlh_seq_last_seen)) + if (NM_IN_SET(seq_number, 0, priv->proto_data_x[netlink_protocol].nlh_seq_last_seen)) return; - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) { - nm_assert(priv->delayed_action.list_wait_for_nl_response->len > 0); + if (!NM_FLAGS_ANY( + priv->delayed_action.flags, + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response)) + goto out; + + nm_assert(priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len > 0); - for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; i++) { - data = &g_array_index(priv->delayed_action.list_wait_for_nl_response, - DelayedActionWaitForNlResponseData, - i); + for (i = 0; i < priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len; i++) { + DelayedActionWaitForNlResponseData *data = + delayed_action_get_list_wait_for_resonse(priv, netlink_protocol, i); - if (data->response_type == DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS - && data->response.out_refresh_all_in_progress - && data->seq_number == priv->nlh_seq_last_seen) { - *data->response.out_refresh_all_in_progress -= 1; - data->response.out_refresh_all_in_progress = NULL; - break; - } + if (data->response_type == DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS + && data->response.out_refresh_all_in_progress + && data->seq_number == priv->proto_data_x[netlink_protocol].nlh_seq_last_seen) { + *data->response.out_refresh_all_in_progress -= 1; + data->response.out_refresh_all_in_progress = NULL; + break; } } - priv->nlh_seq_last_seen = seq_number; +out: + priv->proto_data_x[netlink_protocol].nlh_seq_last_seen = seq_number; } static void event_seq_check(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, guint32 seq_number, WaitForNlResponseResult seq_result, const char *msg) { - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - DelayedActionWaitForNlResponseData *data; - guint i; + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); + guint i; if (seq_number == 0) return; - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) { - nm_assert(priv->delayed_action.list_wait_for_nl_response->len > 0); + if (!NM_FLAGS_ANY( + priv->delayed_action.flags, + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response)) + goto out; + + nm_assert(priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len > 0); - for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; i++) { - data = &g_array_index(priv->delayed_action.list_wait_for_nl_response, - DelayedActionWaitForNlResponseData, - i); + for (i = 0; i < priv->delayed_action.list_wait_for_response_x[netlink_protocol]->len; i++) { + DelayedActionWaitForNlResponseData *data = + delayed_action_get_list_wait_for_resonse(priv, netlink_protocol, i); - if (data->seq_number == seq_number) { - /* We potentially receive many parts partial responses for the same sequence number. + if (data->seq_number == seq_number) { + /* We potentially receive many parts partial responses for the same sequence number. * Thus, we only remember the result, and collect it later. */ - if (data->seq_result < 0) { - /* we already saw an error for this sequence number. + if (data->seq_result < 0) { + /* we already saw an error for this sequence number. * Preserve it. */ - } else if (seq_result != WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN - || data->seq_result == WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) - data->seq_result = seq_result; - if (data->out_errmsg && !*data->out_errmsg) - *data->out_errmsg = g_strdup(msg); - return; - } + } else if (seq_result != WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN + || data->seq_result == WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) + data->seq_result = seq_result; + if (data->out_errmsg && !*data->out_errmsg) + *data->out_errmsg = g_strdup(msg); + return; } } +out: + #if NM_MORE_LOGGING - if (seq_number != priv->nlh_seq_last_handled) + if (seq_number != priv->proto_data_x[netlink_protocol].nlh_seq_last_handled) _LOGt("netlink: recvmsg: unwaited sequence number %u", seq_number); - priv->nlh_seq_last_handled = seq_number; + priv->proto_data_x[netlink_protocol].nlh_seq_last_handled = seq_number; +#else + (void) 0; #endif } static void -event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events) +_rtnl_handle_msg(NMPlatform *platform, const struct nl_msg_lite *msg) { char sbuf1[NM_UTILS_TO_STRING_BUFFER_SIZE]; NMLinuxPlatformPrivate *priv; nm_auto_nmpobj NMPObject *obj = NULL; NMPCacheOpsType cache_op; - struct nlmsghdr *msghdr; + const struct nlmsghdr *msghdr; char buf_nlmsghdr[400]; gboolean is_del = FALSE; gboolean is_dump = FALSE; NMPCache *cache = nm_platform_get_cache(platform); ParseNlmsgIter parse_nlmsg_iter; - if (!handle_events) - return; - - msghdr = nlmsg_hdr(msg); + msghdr = msg->nm_nlh; if (NM_IN_SET(msghdr->nlmsg_type, RTM_DELLINK, @@ -7062,7 +7522,7 @@ event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events obj = nmp_object_new_from_nl(platform, cache, msg, is_del, &parse_nlmsg_iter); if (!obj) { _LOGT("event-notification: %s: ignore", - nl_nlmsghdr_to_str(msghdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); + nl_nlmsghdr_to_str(NETLINK_ROUTE, 0, msghdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); return; } @@ -7080,7 +7540,7 @@ event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events } _LOGT("event-notification: %s%s: %s", - nl_nlmsghdr_to_str(msghdr, buf_nlmsghdr, sizeof(buf_nlmsghdr)), + nl_nlmsghdr_to_str(NETLINK_ROUTE, 0, msghdr, buf_nlmsghdr, sizeof(buf_nlmsghdr)), is_dump ? ", in-dump" : "", nmp_object_to_string(obj, is_del ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, @@ -7119,20 +7579,18 @@ event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events nm_assert(is_ipv6 || !nmp_object_is_alive(obj)); priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); if (NM_FLAGS_HAS(priv->delayed_action.flags, - DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) { + DELAYED_ACTION_TYPE_WAIT_FOR_RESPONSE_RTNL)) { guint i; - nm_assert(priv->delayed_action.list_wait_for_nl_response->len > 0); - for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; i++) { + nm_assert(priv->delayed_action.list_wait_for_response_rtnl->len > 0); + for (i = 0; i < priv->delayed_action.list_wait_for_response_rtnl->len; i++) { DelayedActionWaitForNlResponseData *data = - &g_array_index(priv->delayed_action.list_wait_for_nl_response, - DelayedActionWaitForNlResponseData, - i); + delayed_action_get_list_wait_for_resonse(priv, NMP_NETLINK_ROUTE, i); if (data->response_type == DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET && data->response.out_route_get) { nm_assert(!*data->response.out_route_get); - if (data->seq_number == nlmsg_hdr(msg)->nlmsg_seq) { + if (data->seq_number == msg->nm_nlh->nlmsg_seq) { *data->response.out_route_get = nmp_object_clone(obj, FALSE); data->response.out_route_get = NULL; break; @@ -7269,14 +7727,9 @@ do_add_link_with_lookup(NMPlatform *platform, char s_buf[256]; NMPCache *cache = nm_platform_get_cache(platform); - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _nl_send_nlmsg(platform, - nlmsg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &errmsg); if (nle < 0) { _LOGE("do-add-link[%s/%s]: failed sending netlink request \"%s\" (%d)", name, @@ -7287,7 +7740,7 @@ do_add_link_with_lookup(NMPlatform *platform, return nle; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -7323,14 +7776,9 @@ do_add_addrroute(NMPlatform *platform, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _nl_send_nlmsg(platform, - nlmsg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &errmsg); if (nle < 0) { _LOGE("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)", NMP_OBJECT_GET_CLASS(obj_id)->obj_type_name, @@ -7340,7 +7788,7 @@ do_add_addrroute(NMPlatform *platform, return -NME_PL_NETLINK; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -7379,14 +7827,9 @@ do_delete_object(NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *n gboolean success; const char *log_detail = ""; - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _nl_send_nlmsg(platform, - nlmsg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &errmsg); if (nle < 0) { _LOGE("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)", NMP_OBJECT_GET_CLASS(obj_id)->obj_type_name, @@ -7396,7 +7839,7 @@ do_delete_object(NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *n return FALSE; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -7470,12 +7913,7 @@ do_change_link(NMPlatform *platform, } retry: - nle = _nl_send_nlmsg(platform, - nlmsg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, nlmsg, &seq_result, &errmsg); if (nle < 0) { log_level = LOGL_ERR; log_detail_free = @@ -7488,7 +7926,7 @@ retry: * and we sometimes lack events. Nuke it from the orbit... */ delayed_action_schedule(platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER(ifindex)); - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -7760,7 +8198,7 @@ link_set_address(NMPlatform *platform, int ifindex, gconstpointer address, size_ nm_auto_nlmsg struct nl_msg *nlmsg = NULL; const ChangeLinkData d = { .set_address = - { + { .address = address, .length = length, }, @@ -8596,11 +9034,11 @@ link_can_assume(NMPlatform *platform, int ifindex) if (link->link.master > 0) return TRUE; - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex); + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex); if (nmp_cache_lookup(cache, &lookup)) return TRUE; - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex); + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex); nmp_cache_iter_for_each (&iter, nmp_cache_lookup(cache, &lookup), &o) { nm_assert(NMP_OBJECT_GET_TYPE(o) == NMP_OBJECT_TYPE_IP6_ADDRESS); if (!IN6_IS_ADDR_LINKLOCAL(&o->ip6_address.address)) @@ -8750,8 +9188,7 @@ ip4_address_add(NMPlatform *platform, plen, &peer_addr, flags, - nm_utils_ip4_address_is_link_local(addr) ? RT_SCOPE_LINK - : RT_SCOPE_UNIVERSE, + nm_platform_ip4_address_get_scope(addr), lifetime, preferred, broadcast_address, @@ -8897,6 +9334,9 @@ object_delete(NMPlatform *platform, const NMPObject *obj) case NMP_OBJECT_TYPE_TFILTER: nlmsg = _nl_msg_new_tfilter(RTM_DELTFILTER, 0, NMP_OBJECT_CAST_TFILTER(obj)); break; + case NMP_OBJECT_TYPE_MPTCP_ADDR: + return (nm_platform_mptcp_addr_update(platform, FALSE, NMP_OBJECT_CAST_MPTCP_ADDR(obj)) + >= 0); default: break; } @@ -8967,7 +9407,7 @@ ip_route_get(NMPlatform *platform, return -NME_UNSPEC; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); /* Retry, if we failed due to a cache resync. That can happen when the netlink * socket fills up and we lost the response. */ @@ -9003,20 +9443,15 @@ routing_rule_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformRoutin msg = _nl_msg_new_routing_rule(RTM_NEWRULE, flags, routing_rule); - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _nl_send_nlmsg(platform, - msg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &errmsg); if (nle < 0) { _LOGE("do-add-rule: failed sending netlink request \"%s\" (%d)", nm_strerror(nle), -nle); return -NME_PL_NETLINK; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -9047,20 +9482,15 @@ qdisc_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformQdisc *qdisc) msg = _nl_msg_new_qdisc(RTM_NEWQDISC, flags, qdisc); - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _nl_send_nlmsg(platform, - msg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &errmsg); if (nle < 0) { _LOGE("do-add-qdisc: failed sending netlink request \"%s\" (%d)", nm_strerror(nle), -nle); return -NME_PL_NETLINK; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -9076,7 +9506,11 @@ qdisc_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformQdisc *qdisc) } static int -tc_delete(NMPlatform *platform, int nlmsgtype, int ifindex, guint32 parent, gboolean log_error) +tc_delete(NMPlatform *platform, + uint16_t nlmsg_type, + int ifindex, + guint32 parent, + gboolean log_error) { WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; gs_free char *errmsg = NULL; @@ -9089,7 +9523,7 @@ tc_delete(NMPlatform *platform, int nlmsgtype, int ifindex, guint32 parent, gboo .tcm_parent = parent, }; - switch (nlmsgtype) { + switch (nlmsg_type) { case RTM_DELQDISC: log_tag = "do-delete-qdisc"; break; @@ -9101,19 +9535,14 @@ tc_delete(NMPlatform *platform, int nlmsgtype, int ifindex, guint32 parent, gboo log_tag = "do-delete-tc"; } - msg = nlmsg_alloc_simple(nlmsgtype, NMP_NLM_FLAG_F_ECHO); + msg = nlmsg_alloc_simple(nlmsg_type, NMP_NLM_FLAG_F_ECHO); if (nlmsg_append_struct(msg, &tcm) < 0) goto nla_put_failure; - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _nl_send_nlmsg(platform, - msg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &errmsg); if (nle < 0) { _NMLOG(log_error ? LOGL_ERR : LOGL_DEBUG, "%s: failed sending netlink request \"%s\" (%d)", @@ -9123,7 +9552,7 @@ tc_delete(NMPlatform *platform, int nlmsgtype, int ifindex, guint32 parent, gboo return -NME_PL_NETLINK; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -9163,20 +9592,15 @@ tfilter_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformTfilter *tf msg = _nl_msg_new_tfilter(RTM_NEWTFILTER, flags, tfilter); - event_handler_read_netlink(platform, FALSE); + event_handler_read_netlink(platform, NMP_NETLINK_ROUTE, FALSE); - nle = _nl_send_nlmsg(platform, - msg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); + nle = _netlink_send_nlmsg_rtnl(platform, msg, &seq_result, &errmsg); if (nle < 0) { _LOGE("do-add-tfilter: failed sending netlink request \"%s\" (%d)", nm_strerror(nle), -nle); return -NME_PL_NETLINK; } - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); nm_assert(seq_result); @@ -9199,93 +9623,210 @@ tfilter_delete(NMPlatform *platform, int ifindex, guint32 parent, gboolean log_e /*****************************************************************************/ static gboolean -event_handler(int fd, GIOCondition io_condition, gpointer user_data) +_genl_family_id_update(NMPlatform *platform, NMPGenlFamilyType family_type, guint16 family_id) { - delayed_action_handle_all(NM_PLATFORM(user_data), TRUE); + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); + + if (priv->genl_family_data[family_type].family_id == family_id) + return FALSE; + + if (family_id != 0) { + _LOGD("genl:ctrl: new family-id for %s: 0x%x", + nmp_genl_family_infos[family_type].name, + family_id); + } else + _LOGD("genl:ctrl: del family-id for %s", nmp_genl_family_infos[family_type].name); + priv->genl_family_data[family_type].family_id = family_id; return TRUE; } -/*****************************************************************************/ - -/* copied from libnl3's recvmsgs() */ +static void +_genl_handle_msg_ctrl(NMPlatform *platform, const struct nlmsghdr *hdr) +{ + const struct genlmsghdr *ghdr = nlmsg_data(hdr); + + switch (ghdr->cmd) { + case CTRL_CMD_NEWFAMILY: + case CTRL_CMD_DELFAMILY: + { + struct nlattr *tb[G_N_ELEMENTS(genl_ctrl_policy)]; + NMPGenlFamilyType family_type; + const char *name; + guint16 family_id = 0; + + if (genlmsg_parse_arr(hdr, 0, tb, genl_ctrl_policy) < 0) + return; + + name = nla_get_string(tb[CTRL_ATTR_FAMILY_NAME]); + family_type = nmp_genl_family_type_from_name(name); + + if (family_type == _NMP_GENL_FAMILY_TYPE_NONE) + return; + + if (ghdr->cmd == CTRL_CMD_NEWFAMILY) + family_id = nla_get_u16(tb[CTRL_ATTR_FAMILY_ID]); + + _genl_family_id_update(platform, family_type, family_id); + } + } +} + +static void +_genl_handle_msg(NMPlatform *platform, guint32 pktinfo_group, const struct nl_msg_lite *msg) +{ + const struct nlmsghdr *hdr = msg->nm_nlh; + + if (!genlmsg_valid_hdr(hdr, 0)) + return; + + if (hdr->nlmsg_type == GENL_ID_CTRL) + _genl_handle_msg_ctrl(platform, hdr); +} + +/*****************************************************************************/ + static int -event_handler_recvmsgs(NMPlatform *platform, gboolean handle_events) +_netlink_recv(NMPlatform *platform, + struct nl_sock *sk, + struct sockaddr_nl *nla, + struct ucred *out_creds, + gboolean *out_creds_has, + guint32 *out_pktinfo_group, + gboolean *out_pktinfo_has) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - struct nl_sock *sk = priv->nlh; + unsigned char *buf = NULL; int n; - int err = 0; - gboolean multipart = 0; - gboolean interrupted = FALSE; - struct nlmsghdr *hdr; - WaitForNlResponseResult seq_result; - struct sockaddr_nl nla; - struct ucred creds; - gboolean creds_has; - unsigned char *buf; -continue_reading: - buf = NULL; + nm_assert(nla); + nm_assert(out_creds); + nm_assert(out_creds_has); + + /* We use a pre-allocated receive buffer. We use it both for sk_rtnl + * and sk_genl. We can do that, because we are deep inside the netlink + * handling, and we never will need to use it for both sockets at the + * same time. */ n = nl_recv(sk, priv->netlink_recv_buf.buf, priv->netlink_recv_buf.len, - &nla, + nla, &buf, - &creds, - &creds_has); + out_creds, + out_creds_has, + out_pktinfo_group, + out_pktinfo_has); nm_assert((n <= 0 && !buf) || (n > 0 && n <= priv->netlink_recv_buf.len && buf == priv->netlink_recv_buf.buf)); - if (n <= 0) { - if (n == -NME_NL_MSG_TRUNC) { - /* the message receive buffer was too small. We lost one message, which - * is unfortunate. Try to double the buffer size for the next time. */ - priv->netlink_recv_buf.len *= 2; - priv->netlink_recv_buf.buf = - g_realloc(priv->netlink_recv_buf.buf, priv->netlink_recv_buf.len); - _LOGT("netlink: recvmsg: increase message buffer size for recvmsg() to %zu bytes", - priv->netlink_recv_buf.len); - if (!handle_events) - goto continue_reading; - } - - return n; + if (n == -NME_NL_MSG_TRUNC) { + /* the message receive buffer was too small. We lost one message, which + * is unfortunate. Try to double the buffer size for the next time. */ + priv->netlink_recv_buf.len *= 2; + priv->netlink_recv_buf.buf = + g_realloc(priv->netlink_recv_buf.buf, priv->netlink_recv_buf.len); + _LOGT("netlink: recvmsg: increase message buffer size for recvmsg() to %zu bytes", + priv->netlink_recv_buf.len); } - hdr = (struct nlmsghdr *) buf; - while (nlmsg_ok(hdr, n)) { - nm_auto_nlmsg struct nl_msg *msg = NULL; - gboolean abort_parsing = FALSE; - gboolean process_valid_msg = FALSE; - guint32 seq_number; - char buf_nlmsghdr[400]; - const char *extack_msg = NULL; + return n; +} - msg = nlmsg_alloc_convert(hdr); +/*****************************************************************************/ - nlmsg_set_proto(msg, NETLINK_ROUTE); - nlmsg_set_src(msg, &nla); +static gboolean +_nl_event_handler(NMPlatform *platform, DelayedActionType action_type) +{ + delayed_action_schedule(platform, action_type, NULL); + delayed_action_handle_all(platform); + return TRUE; +} - if (!creds_has || creds.pid) { - if (!creds_has) - _LOGT("netlink: recvmsg: received message without credentials"); - else - _LOGT("netlink: recvmsg: received non-kernel message (pid %d)", creds.pid); - err = 0; - goto stop; - } +static gboolean +_nl_event_handler_genl(int fd, GIOCondition io_condition, gpointer user_data) +{ + return _nl_event_handler(user_data, DELAYED_ACTION_TYPE_READ_GENL); +} + +static gboolean +_nl_event_handler_rtnl(int fd, GIOCondition io_condition, gpointer user_data) +{ + return _nl_event_handler(user_data, DELAYED_ACTION_TYPE_READ_RTNL); +} + +/*****************************************************************************/ + +static int +_netlink_recv_handle(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + gboolean handle_events) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); + int n; + int retval = 0; + gboolean multipart = 0; + gboolean interrupted = FALSE; + struct nlmsghdr *hdr; + struct sockaddr_nl nla; + struct ucred creds; + gboolean creds_has; + guint32 pktinfo_group = 0; + gboolean pktinfo_has = FALSE; + const char *const log_prefix = nmp_netlink_protocol_info(netlink_protocol)->name; + +continue_reading: - _LOGt("netlink: recvmsg: new message %s", - nl_nlmsghdr_to_str(hdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); + n = _netlink_recv(platform, + priv->sk_x[netlink_protocol], + &nla, + &creds, + &creds_has, + &pktinfo_group, + netlink_protocol == NMP_NETLINK_GENERIC ? &pktinfo_has : NULL); + if (n < 0) { + if (n == -NME_NL_MSG_TRUNC && !handle_events) + goto continue_reading; + return n; + } + + if (!creds_has || creds.pid) { + if (!creds_has) + _LOGT("%s: recvmsg: received message without credentials", log_prefix); + else + _LOGT("%s: recvmsg: received non-kernel message (pid %d)", log_prefix, creds.pid); + goto stop; + } + + hdr = (struct nlmsghdr *) priv->netlink_recv_buf.buf; + while (nlmsg_ok(hdr, n)) { + WaitForNlResponseResult seq_result; + gboolean process_valid_msg = FALSE; + char buf_nlmsghdr[400]; + const char *extack_msg = NULL; + const struct nl_msg_lite msg = { + .nm_protocol = nmp_netlink_protocol_info(netlink_protocol)->netlink_protocol, + .nm_src = &nla, + .nm_creds = &creds, + .nm_size = NLMSG_ALIGN(hdr->nlmsg_len), + .nm_nlh = hdr, + }; + const guint32 seq_number = msg.nm_nlh->nlmsg_seq; + + nm_assert((((uintptr_t) (const void *) msg.nm_nlh) % NLMSG_ALIGNTO) == 0); - nlmsg_set_creds(msg, &creds); + _LOGt("%s: recvmsg: new message %s", + log_prefix, + nl_nlmsghdr_to_str(nmp_netlink_protocol_info(netlink_protocol)->netlink_protocol, + pktinfo_group, + msg.nm_nlh, + buf_nlmsghdr, + sizeof(buf_nlmsghdr))); - if (hdr->nlmsg_flags & NLM_F_MULTI) + if (msg.nm_nlh->nlmsg_flags & NLM_F_MULTI) multipart = TRUE; - if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) { + if (msg.nm_nlh->nlmsg_flags & NLM_F_DUMP_INTR) { /* * We have to continue reading to clear * all messages until a NLMSG_DONE is @@ -9294,105 +9835,75 @@ continue_reading: interrupted = TRUE; } - /* Other side wishes to see an ack for this message */ - if (hdr->nlmsg_flags & NLM_F_ACK) { - /* FIXME: implement */ + if (msg.nm_nlh->nlmsg_flags & NLM_F_ACK) { + /* TODO: Other side wishes to see an ack for this message */ } seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN; - if (hdr->nlmsg_type == NLMSG_DONE) { + if (msg.nm_nlh->nlmsg_type == NLMSG_DONE) { /* messages terminates a multipart message, this is * usually the end of a message and therefore we slip * out of the loop by default. the user may overrule * this action by skipping this packet. */ multipart = FALSE; seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; - } else if (hdr->nlmsg_type == NLMSG_NOOP) { + } else if (msg.nm_nlh->nlmsg_type == NLMSG_NOOP) { /* Message to be ignored, the default action is to * skip this message if no callback is specified. The * user may overrule this action by returning * NL_PROCEED. */ - } else if (hdr->nlmsg_type == NLMSG_OVERRUN) { + } else if (msg.nm_nlh->nlmsg_type == NLMSG_OVERRUN) { /* Data got lost, report back to user. The default action is to * quit parsing. The user may overrule this action by returning * NL_SKIP or NL_PROCEED (dangerous) */ - err = -NME_NL_MSG_OVERFLOW; - abort_parsing = TRUE; - } else if (hdr->nlmsg_type == NLMSG_ERROR) { - /* Message carries a nlmsgerr */ - struct nlmsgerr *e = nlmsg_data(hdr); - - if (hdr->nlmsg_len < nlmsg_size(sizeof(*e))) { - /* Truncated error message, the default action - * is to stop parsing. The user may overrule - * this action by returning NL_SKIP or - * NL_PROCEED (dangerous) */ - err = -NME_NL_MSG_TRUNC; - abort_parsing = TRUE; - } else if (e->error) { - int errsv = nm_errno_native(e->error); - - if (NM_FLAGS_HAS(hdr->nlmsg_flags, NLM_F_ACK_TLVS) - && hdr->nlmsg_len >= sizeof(*e) + e->msg.nlmsg_len) { - static const struct nla_policy policy[] = { - [NLMSGERR_ATTR_MSG] = {.type = NLA_STRING}, - [NLMSGERR_ATTR_OFFS] = {.type = NLA_U32}, - }; - struct nlattr *tb[G_N_ELEMENTS(policy)]; - struct nlattr *tlvs; - - tlvs = (struct nlattr *) ((char *) e + sizeof(*e) + e->msg.nlmsg_len - - NLMSG_HDRLEN); - if (nla_parse_arr(tb, - tlvs, - hdr->nlmsg_len - sizeof(*e) - e->msg.nlmsg_len, - policy) - >= 0) { - if (tb[NLMSGERR_ATTR_MSG]) - extack_msg = nla_get_string(tb[NLMSGERR_ATTR_MSG]); - } - } + retval = -NME_NL_MSG_OVERFLOW; + } else if (msg.nm_nlh->nlmsg_type == NLMSG_ERROR) { + int errsv; - /* Error message reported back from kernel. */ - _LOGD("netlink: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d", - nm_strerror_native(errsv), + errsv = nlmsg_parse_error(msg.nm_nlh, &extack_msg); + if (errsv == 0) + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; + else { + _LOGD("%s: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d", + log_prefix, + nm_strerror(errsv), errsv, NM_PRINT_FMT_QUOTED(extack_msg, " \"", extack_msg, "\"", ""), - nlmsg_hdr(msg)->nlmsg_seq); - seq_result = -NM_ERRNO_NATIVE(errsv); - } else - seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; + msg.nm_nlh->nlmsg_seq); + seq_result = errsv; + } } else process_valid_msg = TRUE; - seq_number = nlmsg_hdr(msg)->nlmsg_seq; - /* check whether the seq number is different from before, and * whether the previous number (@nlh_seq_last_seen) is a pending * refresh-all request. In that case, the pending request is thereby * completed. * - * We must do that before processing the message with event_valid_msg(), + * We must do that before processing the message with _rtnl_handle_msg(), * because we must track the completion of the pending request before that. */ - event_seq_check_refresh_all(platform, seq_number); + event_seq_check_refresh_all(platform, netlink_protocol, seq_number); if (process_valid_msg) { - /* Valid message (not checking for MULTIPART bit to - * get along with broken kernels. NL_SKIP has no - * effect on this. */ - - event_valid_msg(platform, msg, handle_events); - + if (handle_events) { + /* Valid message (not checking for MULTIPART bit to + * get along with broken kernels. NL_SKIP has no + * effect on this. */ + if (netlink_protocol == NMP_NETLINK_ROUTE) { + _rtnl_handle_msg(platform, &msg); + } else { + _genl_handle_msg(platform, pktinfo_group, &msg); + } + } seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; } - event_seq_check(platform, seq_number, seq_result, extack_msg); + event_seq_check(platform, netlink_protocol, seq_number, seq_result, extack_msg); - if (abort_parsing) + if (retval != 0) goto stop; - err = 0; hdr = nlmsg_next(hdr, &n); } @@ -9400,6 +9911,7 @@ continue_reading: /* Multipart message not yet complete, continue reading */ goto continue_reading; } + stop: if (!handle_events) { /* when we don't handle events, we want to drain all messages from the socket @@ -9410,13 +9922,15 @@ stop: if (interrupted) return -NME_NL_DUMP_INTR; - return err; + return retval; } /*****************************************************************************/ static gboolean -event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) +event_handler_read_netlink(NMPlatform *platform, + NMPNetlinkProtocol netlink_protocol, + gboolean wait_for_acks) { nm_auto_pop_netns NMPNetns *netns = NULL; NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); @@ -9430,8 +9944,11 @@ event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) gint64 now_nsec; } next; + nmp_netlink_protocol_check(netlink_protocol); + if (!nm_platform_netns_push(platform, &netns)) { delayed_action_wait_for_nl_response_complete_all(platform, + netlink_protocol, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS); return FALSE; } @@ -9440,20 +9957,24 @@ event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) for (;;) { int nle; - nle = event_handler_recvmsgs(platform, TRUE); + nle = _netlink_recv_handle(platform, netlink_protocol, TRUE); if (nle < 0) { switch (nle) { case -EAGAIN: goto after_read; case -NME_NL_DUMP_INTR: - _LOGD("netlink: read: uncritical failure to retrieve incoming events: %s (%d)", + _LOGD("netlink[%s]: read: uncritical failure to retrieve incoming events: %s " + "(%d)", + nmp_netlink_protocol_info(netlink_protocol)->name, nm_strerror(nle), nle); break; case -NME_NL_MSG_TRUNC: case -ENOBUFS: - _LOGI("netlink: read: %s. Need to resynchronize platform cache", ({ + _LOGI("netlink[%s]: read: %s. Need to resynchronize platform cache", + nmp_netlink_protocol_info(netlink_protocol)->name, + ({ const char *_reason = "unknown"; switch (nle) { case -NME_NL_MSG_TRUNC: @@ -9465,24 +9986,16 @@ event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) } _reason; })); - event_handler_recvmsgs(platform, FALSE); + _netlink_recv_handle(platform, netlink_protocol, FALSE); delayed_action_wait_for_nl_response_complete_all( platform, + netlink_protocol, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC); - - delayed_action_schedule(platform, - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL - | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS - | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, - NULL); + delayed_action_schedule_refresh_all(platform, netlink_protocol); break; default: - _LOGE("netlink: read: failed to retrieve incoming events: %s (%d)", + _LOGE("netlink[%s]: read: failed to retrieve incoming events: %s (%d)", + nmp_netlink_protocol_info(netlink_protocol)->name, nm_strerror(nle), nle); break; @@ -9493,17 +10006,22 @@ event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) after_read: - if (!NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) + if (!NM_FLAGS_ANY( + priv->delayed_action.flags, + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response)) return any; - delayed_action_wait_for_nl_response_complete_check(platform, - WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN, - &next.seq_number, - &next.timeout_abs_nsec, - &next.now_nsec); + delayed_action_wait_for_response_complete_check(platform, + netlink_protocol, + WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN, + &next.seq_number, + &next.timeout_abs_nsec, + &next.now_nsec); if (!wait_for_acks - || !NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) + || !NM_FLAGS_ANY( + priv->delayed_action.flags, + nmp_netlink_protocol_info(netlink_protocol)->delayed_action_type_wait_for_response)) return any; nm_assert(next.seq_number); @@ -9521,7 +10039,7 @@ after_read: timeout_msec); memset(&pfd, 0, sizeof(pfd)); - pfd.fd = nl_socket_get_fd(priv->nlh); + pfd.fd = nl_socket_get_fd(priv->sk_rtnl); pfd.events = POLLIN; r = poll(&pfd, 1, timeout_msec); @@ -9539,6 +10057,7 @@ after_read: _LOGE("netlink: read: poll failed with %s", nm_strerror_native(errsv)); delayed_action_wait_for_nl_response_complete_all( platform, + netlink_protocol, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL); return any; } @@ -9549,6 +10068,337 @@ after_read: /*****************************************************************************/ +static guint16 +genl_get_family_id(NMPlatform *platform, NMPGenlFamilyType family_type) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); + int family_id; + + nm_assert(_NM_INT_NOT_NEGATIVE(family_type)); + nm_assert(family_type < G_N_ELEMENTS(priv->genl_family_data)); + + if (priv->genl_family_data[family_type].family_id != 0) + goto out; + + /* Unknown family ID... usually we expect to start using the protocol. + * Let's try harder and fetch the ID synchronously. + * + * Note that we might also be called back during delayed_action_handle_all(), + * when we add a WireGuard link, the module gets autoloaded, and we didn't + * yet process the genl notification about the new family. Let's not call + * delayed_action_handle_all() again, because that might emit various + * signals. */ + + family_id = genl_ctrl_resolve(priv->sk_genl_sync, nmp_genl_family_infos[family_type].name); + if (family_id < 0) + family_id = 0; + + /* We cache the family ID and update it via genl notifications. + * Here we bypass the order of that, and update the cached value + * directly. */ + _genl_family_id_update(platform, family_type, family_id); + +out: + return priv->genl_family_data[family_type].family_id; +} + +/*****************************************************************************/ + +static const NMPObject * +_mptcp_addrs_dump_parse_addr(struct nlattr *attr) +{ + static const struct nla_policy policy[] = { + [MPTCP_PM_ADDR_ATTR_FAMILY] = {.type = NLA_U16}, + [MPTCP_PM_ADDR_ATTR_ID] = {.type = NLA_U8}, + [MPTCP_PM_ADDR_ATTR_ADDR4] = {.minlen = sizeof(in_addr_t)}, + [MPTCP_PM_ADDR_ATTR_ADDR6] = {.minlen = sizeof(struct in6_addr)}, + [MPTCP_PM_ADDR_ATTR_PORT] = {.type = NLA_U16}, + [MPTCP_PM_ADDR_ATTR_FLAGS] = {.type = NLA_U32}, + [MPTCP_PM_ADDR_ATTR_IF_IDX] = {.type = NLA_S32}, + }; + struct nlattr *tb[G_N_ELEMENTS(policy)]; + nm_auto_nmpobj NMPObject *obj = NULL; + NMPlatformMptcpAddr *mptcp_addr; + int addr_family; + int addr_attr; + + if (nla_parse_nested_arr(tb, attr, policy) < 0) + return NULL; + + if (!tb[MPTCP_PM_ADDR_ATTR_ID]) + return NULL; + + obj = nmp_object_new(NMP_OBJECT_TYPE_MPTCP_ADDR, NULL); + mptcp_addr = &obj->mptcp_addr; + + mptcp_addr->id = nla_get_u8(tb[MPTCP_PM_ADDR_ATTR_ID]); + + if (!tb[MPTCP_PM_ADDR_ATTR_FAMILY]) { + /* If we don't have the family. Only create a stub object containing + * the ID. */ + goto out; + } + + addr_family = nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_FAMILY]); + + if (addr_family == AF_INET) + addr_attr = MPTCP_PM_ADDR_ATTR_ADDR4; + else if (addr_family == AF_INET6) + addr_attr = MPTCP_PM_ADDR_ATTR_ADDR6; + else + goto out; + + if (!tb[addr_attr]) + goto out; + + mptcp_addr->addr_family = addr_family; + memcpy(&mptcp_addr->addr, nla_data(tb[addr_attr]), nm_utils_addr_family_to_size(addr_family)); + + if (tb[MPTCP_PM_ADDR_ATTR_PORT]) + mptcp_addr->port = nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_PORT]); + + if (tb[MPTCP_PM_ADDR_ATTR_IF_IDX]) + mptcp_addr->ifindex = nla_get_s32(tb[MPTCP_PM_ADDR_ATTR_IF_IDX]); + + if (tb[MPTCP_PM_ADDR_ATTR_FLAGS]) + mptcp_addr->flags = nla_get_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]); + +out: + + return g_steal_pointer(&obj); +} + +typedef struct { + GPtrArray *addrs; +} FetchMptcpAddrParseData; + +static int +_mptcp_addrs_dump_parse_cb(const struct nl_msg *msg, void *arg) +{ + static const struct nla_policy policy[] = { + [MPTCP_PM_ATTR_ADDR] = {.type = NLA_NESTED}, + }; + struct nlattr *tb[G_N_ELEMENTS(policy)]; + FetchMptcpAddrParseData *parse_data = arg; + + if (genlmsg_parse_arr(nlmsg_hdr(msg), 0, tb, policy) < 0) + return NL_SKIP; + + if (tb[MPTCP_PM_ATTR_ADDR]) { + const NMPObject *obj; + + obj = _mptcp_addrs_dump_parse_addr(tb[MPTCP_PM_ATTR_ADDR]); + if (obj) + g_ptr_array_add(parse_data->addrs, (gpointer) obj); + } + + return NL_OK; +} + +#define EXTACK_MSG_BUFSIZE 200 + +static int +_mptcp_addr_update_err_cb(const struct sockaddr_nl *nla, const struct nlmsgerr *nlerr, void *arg) +{ + char *out_extack_msg = arg; + const char *extack_msg; + int errsv; + + errsv = nlmsg_parse_error(nlmsg_undata(nlerr), &extack_msg); + if (extack_msg) + g_strlcpy(out_extack_msg, extack_msg, EXTACK_MSG_BUFSIZE); + return errsv; +} + +static int +mptcp_addr_update(NMPlatform *platform, NMOptionBool add, const NMPlatformMptcpAddr *addr) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *nla_nest; + char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; + guint16 genl_family_id; + guint8 cmd_num; + const char *cmd_str; + int nle; + char extack_msg[EXTACK_MSG_BUFSIZE]; + const struct nl_cb cb = { + .err_cb = _mptcp_addr_update_err_cb, + .err_arg = extack_msg, + }; + + extack_msg[0] = '\0'; + + if (add == NM_OPTION_BOOL_DEFAULT) { + cmd_num = MPTCP_PM_CMD_SET_FLAGS; + cmd_str = "update"; + } else if (add) { + cmd_num = MPTCP_PM_CMD_ADD_ADDR; + cmd_str = "add"; + } else { + cmd_num = MPTCP_PM_CMD_DEL_ADDR; + cmd_str = "delete"; + } + + nm_assert_addr_family_or_unspec(addr->addr_family); + nm_assert(cmd_num != MPTCP_PM_CMD_ADD_ADDR + || (addr->port == 0 && addr->addr_family != AF_UNSPEC)); + nm_assert(cmd_num != MPTCP_PM_CMD_SET_FLAGS || (addr->id != 0 && addr->port == 0)); + nm_assert(cmd_num != MPTCP_PM_CMD_DEL_ADDR || addr->id != 0); + + genl_family_id = nm_platform_genl_get_family_id(platform, NMP_GENL_FAMILY_TYPE_MPTCP_PM); + if (genl_family_id == 0) { + _LOGT("mptcp: %s address %s fails because %s generic netlink family is unknown", + cmd_str, + nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf)), + nmp_genl_family_infos[NMP_GENL_FAMILY_TYPE_MPTCP_PM].name); + return -ENOSYS; + } + + _LOGT("mptcp: %s address %s", + cmd_str, + nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf))); + + nlmsg = nlmsg_alloc_size(nlmsg_total_size(GENL_HDRLEN) + 200); + + if (!genlmsg_put(nlmsg, + NL_AUTO_PORT, + NL_AUTO_SEQ, + genl_family_id, + 0, + NLM_F_REQUEST, + cmd_num, + MPTCP_PM_VER)) + goto nla_put_failure; + + nla_nest = nla_nest_start(nlmsg, MPTCP_PM_ATTR_ADDR | NLA_F_NESTED); + if (!nla_nest) + goto nla_put_failure; + + if (addr->id != 0) + NLA_PUT_U8(nlmsg, MPTCP_PM_ADDR_ATTR_ID, addr->id); + if (addr->flags != 0) + NLA_PUT_U32(nlmsg, MPTCP_PM_ADDR_ATTR_FLAGS, addr->flags); + if (addr->ifindex != 0) + NLA_PUT_S32(nlmsg, MPTCP_PM_ADDR_ATTR_IF_IDX, addr->ifindex); + if (addr->port != 0) + NLA_PUT_U16(nlmsg, MPTCP_PM_ADDR_ATTR_PORT, addr->port); + if (addr->addr_family != AF_UNSPEC) { + int addr_attr; + + NLA_PUT_U16(nlmsg, MPTCP_PM_ADDR_ATTR_FAMILY, addr->addr_family); + if (addr->addr_family == AF_INET) + addr_attr = MPTCP_PM_ADDR_ATTR_ADDR4; + else if (addr->addr_family == AF_INET6) + addr_attr = MPTCP_PM_ADDR_ATTR_ADDR6; + else + g_return_val_if_reached(-NME_BUG); + NLA_PUT(nlmsg, addr_attr, nm_utils_addr_family_to_size(addr->addr_family), &addr->addr); + } + + NLA_NEST_END(nlmsg, nla_nest); + + nle = nl_send_auto(priv->sk_genl_sync, nlmsg); + if (nle < 0) { + _LOGT("mptcp: %s address %s: failed sending request: %s (%d)", + cmd_str, + nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf)), + nm_strerror(nle), + nle); + return nle; + } + + do { + nle = nl_recvmsgs(priv->sk_genl_sync, &cb); + } while (nle == -EAGAIN); + + if (nle < 0) { + _LOGT("mptcp: %s address %s: failed: %s (%d)%s%s%s", + cmd_str, + nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf)), + nm_strerror(nle), + nle, + NM_PRINT_FMT_QUOTED(extack_msg[0] != '\0', " \"", extack_msg, "\"", "")); + return nle; + } + + _LOGT("mptcp: %s address %s: success", + cmd_str, + nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf))); + + return 0; + +nla_put_failure: + g_return_val_if_reached(-NME_BUG); +} + +static GPtrArray * +mptcp_addrs_dump(NMPlatform *platform) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); + gs_unref_ptrarray GPtrArray *addrs = NULL; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + FetchMptcpAddrParseData parse_data; + guint16 genl_family_id; + int r; + guint i; + + genl_family_id = nm_platform_genl_get_family_id(platform, NMP_GENL_FAMILY_TYPE_MPTCP_PM); + if (genl_family_id == 0) { + _LOGT("mptcp: dump addresses fails because %s generic netlink family is unknown", + nmp_genl_family_infos[NMP_GENL_FAMILY_TYPE_MPTCP_PM].name); + return NULL; + } + + nlmsg = nlmsg_alloc_size(nlmsg_total_size(GENL_HDRLEN)); + + if (!genlmsg_put(nlmsg, + NL_AUTO_PORT, + NL_AUTO_SEQ, + genl_family_id, + 0, + NLM_F_REQUEST | NLM_F_DUMP, + MPTCP_PM_CMD_GET_ADDR, + MPTCP_PM_VER)) + g_return_val_if_reached(NULL); + + r = nl_send_auto(priv->sk_genl_sync, nlmsg); + if (r < 0) { + _LOGT("mptcp: dump addresses failed to send dump request: %s", nm_strerror(r)); + return NULL; + } + + addrs = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); + + parse_data = (FetchMptcpAddrParseData){ + .addrs = addrs, + }; + + nl_recvmsgs(priv->sk_genl_sync, + &((const struct nl_cb){ + .valid_cb = _mptcp_addrs_dump_parse_cb, + .valid_arg = (gpointer) &parse_data, + })); + + if (_LOGT_ENABLED()) { + _LOGT("mptcp: %u addresses dumped", addrs->len); + for (i = 0; i < addrs->len; i++) { + char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; + + _LOGT("mptcp: address[%04d]: %s", + i, + nmp_object_to_string(addrs->pdata[i], + NMP_OBJECT_TO_STRING_PUBLIC, + sbuf, + sizeof(sbuf))); + } + } + + return g_steal_pointer(&addrs); +} + +/*****************************************************************************/ + static void cache_update_link_udev(NMPlatform *platform, int ifindex, struct udev_device *udevice) { @@ -9689,7 +10539,9 @@ nm_linux_platform_init(NMLinuxPlatform *self) priv->delayed_action.list_master_connected = g_ptr_array_new(); priv->delayed_action.list_refresh_link = g_ptr_array_new(); - priv->delayed_action.list_wait_for_nl_response = + priv->delayed_action.list_wait_for_response_rtnl = + g_array_new(FALSE, TRUE, sizeof(DelayedActionWaitForNlResponseData)); + priv->delayed_action.list_wait_for_response_genl = g_array_new(FALSE, TRUE, sizeof(DelayedActionWaitForNlResponseData)); } @@ -9721,43 +10573,53 @@ constructed(GObject *_object) nm_platform_get_use_udev(platform) ? "use" : "no", nm_platform_get_cache_tc(platform) ? "use" : "no"); - priv->genl = nl_socket_alloc(); - g_assert(priv->genl); + /*************************************************************************/ - nle = nl_connect(priv->genl, NETLINK_GENERIC); - if (nle) { - _LOGE("unable to connect the generic netlink socket \"%s\" (%d)", nm_strerror(nle), -nle); - nl_socket_free(priv->genl); - priv->genl = NULL; - } + nle = nl_socket_new(&priv->sk_genl_sync, NETLINK_GENERIC, NL_SOCKET_FLAGS_NONE, 0, 0); + g_assert(!nle); - priv->nlh = nl_socket_alloc(); - g_assert(priv->nlh); + _LOGD("genl: generic netlink socket for sync operations created: port=%u, fd=%d", + nl_socket_get_local_port(priv->sk_genl_sync), + nl_socket_get_fd(priv->sk_genl_sync)); - nle = nl_connect(priv->nlh, NETLINK_ROUTE); - g_assert(!nle); - nle = nl_socket_set_passcred(priv->nlh, 1); - g_assert(!nle); + /*************************************************************************/ - /* No blocking for event socket, so that we can drain it safely. */ - nle = nl_socket_set_nonblocking(priv->nlh); + /* disable MSG_PEEK, we will handle lost messages ourselves. */ + nle = nl_socket_new(&priv->sk_genl, + NETLINK_GENERIC, + NL_SOCKET_FLAGS_NONBLOCK | NL_SOCKET_FLAGS_PASSCRED + | NL_SOCKET_FLAGS_DISABLE_MSG_PEEK, + 8 * 1024 * 1024, + 0); g_assert(!nle); - /* use 8 MB for receive socket kernel queue. */ - nle = nl_socket_set_buffer_size(priv->nlh, 8 * 1024 * 1024, 0); + nle = nl_socket_add_memberships(priv->sk_genl, GENL_ID_CTRL, 0); g_assert(!nle); - nle = nl_socket_set_ext_ack(priv->nlh, TRUE); - if (nle) - _LOGD("could not enable extended acks on netlink socket"); + fd = nl_socket_get_fd(priv->sk_genl); - /* explicitly set the msg buffer size and disable MSG_PEEK. - * We use our own receive buffer priv->netlink_recv_buf. - * If we encounter NME_NL_MSG_TRUNC, we will increase the buffer - * and resync (as we would have lost the message without NL_MSG_PEEK). */ - nl_socket_disable_msg_peek(priv->nlh); + _LOGD("genl: generic netlink socket created: port=%u, fd=%d", + nl_socket_get_local_port(priv->sk_genl), + fd); + + priv->event_source_genl = + nm_g_unix_fd_add_source(fd, + G_IO_IN | G_IO_NVAL | G_IO_PRI | G_IO_ERR | G_IO_HUP, + _nl_event_handler_genl, + platform); + + /*************************************************************************/ + + /* disable MSG_PEEK, we will handle lost messages ourselves. */ + nle = nl_socket_new(&priv->sk_rtnl, + NETLINK_ROUTE, + NL_SOCKET_FLAGS_NONBLOCK | NL_SOCKET_FLAGS_PASSCRED + | NL_SOCKET_FLAGS_DISABLE_MSG_PEEK, + 8 * 1024 * 1024, + 0); + g_assert(!nle); - nle = nl_socket_add_memberships(priv->nlh, + nle = nl_socket_add_memberships(priv->sk_rtnl, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV4_RULE, @@ -9769,37 +10631,32 @@ constructed(GObject *_object) g_assert(!nle); if (nm_platform_get_cache_tc(platform)) { - nle = nl_socket_add_memberships(priv->nlh, RTNLGRP_TC, 0); + nle = nl_socket_add_memberships(priv->sk_rtnl, RTNLGRP_TC, 0); nm_assert(!nle); } - fd = nl_socket_get_fd(priv->nlh); + fd = nl_socket_get_fd(priv->sk_rtnl); - _LOGD("Netlink socket for events established: port=%u, fd=%d", - nl_socket_get_local_port(priv->nlh), + _LOGD("rtnl: rtnetlink socket created: port=%u, fd=%d", + nl_socket_get_local_port(priv->sk_rtnl), fd); - priv->event_source = + priv->event_source_rtnl = nm_g_unix_fd_add_source(fd, G_IO_IN | G_IO_NVAL | G_IO_PRI | G_IO_ERR | G_IO_HUP, - event_handler, + _nl_event_handler_rtnl, platform); + /*************************************************************************/ + /* complete construction of the GObject instance before populating the cache. */ G_OBJECT_CLASS(nm_linux_platform_parent_class)->constructed(_object); _LOGD("populate platform cache"); - delayed_action_schedule( - platform, - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL - | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, - NULL); + delayed_action_schedule_refresh_all(platform, NMP_NETLINK_ROUTE); + delayed_action_schedule_refresh_all(platform, NMP_NETLINK_GENERIC); - delayed_action_handle_all(platform, FALSE); + delayed_action_handle_all(platform); /* Set up udev monitoring */ if (priv->udev_client) { @@ -9881,6 +10738,11 @@ dispose(GObject *object) _LOGD("dispose"); delayed_action_wait_for_nl_response_complete_all(platform, + NMP_NETLINK_GENERIC, + WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING); + + delayed_action_wait_for_nl_response_complete_all(platform, + NMP_NETLINK_ROUTE, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING); priv->delayed_action.flags = DELAYED_ACTION_TYPE_NONE; @@ -9897,13 +10759,15 @@ finalize(GObject *object) g_ptr_array_unref(priv->delayed_action.list_master_connected); g_ptr_array_unref(priv->delayed_action.list_refresh_link); - g_array_unref(priv->delayed_action.list_wait_for_nl_response); + g_array_unref(priv->delayed_action.list_wait_for_response_rtnl); + g_array_unref(priv->delayed_action.list_wait_for_response_genl); - nl_socket_free(priv->genl); + nm_clear_g_source_inst(&priv->event_source_genl); + nm_clear_g_source_inst(&priv->event_source_rtnl); - nm_clear_g_source_inst(&priv->event_source); - - nl_socket_free(priv->nlh); + nl_socket_free(priv->sk_genl_sync); + nl_socket_free(priv->sk_genl); + nl_socket_free(priv->sk_rtnl); { NM_G_MUTEX_LOCKED(&sysctl_clear_cache_lock); @@ -10021,4 +10885,8 @@ nm_linux_platform_class_init(NMLinuxPlatformClass *klass) platform_class->tfilter_delete = tfilter_delete; platform_class->process_events = process_events; + + platform_class->genl_get_family_id = genl_get_family_id; + platform_class->mptcp_addr_update = mptcp_addr_update; + platform_class->mptcp_addrs_dump = mptcp_addrs_dump; } diff --git a/src/libnm-platform/nm-netlink.c b/src/libnm-platform/nm-netlink.c index 697ae591..36841d56 100644 --- a/src/libnm-platform/nm-netlink.c +++ b/src/libnm-platform/nm-netlink.c @@ -18,10 +18,15 @@ /*****************************************************************************/ -#define NL_SOCK_PASSCRED (1 << 1) -#define NL_MSG_PEEK (1 << 3) -#define NL_MSG_PEEK_EXPLICIT (1 << 4) -#define NL_NO_AUTO_ACK (1 << 5) +#define nm_assert_sk(sk) \ + G_STMT_START \ + { \ + const struct nl_sock *_sk = (sk); \ + \ + nm_assert(_sk); \ + nm_assert(_sk->s_fd >= 0); \ + } \ + G_STMT_END #ifndef NETLINK_EXT_ACK #define NETLINK_EXT_ACK 11 @@ -33,19 +38,20 @@ struct nl_msg { struct sockaddr_nl nm_dst; struct ucred nm_creds; struct nlmsghdr *nm_nlh; - size_t nm_size; + uint32_t nm_size; bool nm_creds_has : 1; }; struct nl_sock { struct sockaddr_nl s_local; struct sockaddr_nl s_peer; + size_t s_bufsize; int s_fd; int s_proto; unsigned int s_seq_next; unsigned int s_seq_expect; - int s_flags; - size_t s_bufsize; + bool s_msg_peek : 1; + bool s_auto_ack : 1; }; /*****************************************************************************/ @@ -71,13 +77,62 @@ NM_UTILS_FLAGS2STR_DEFINE(nl_nlmsg_flags2str, NM_UTILS_FLAGS2STR(NLM_F_CREATE, "CREATE"), NM_UTILS_FLAGS2STR(NLM_F_APPEND, "APPEND"), ); +static NM_UTILS_LOOKUP_STR_DEFINE(_rtnl_type_to_str, + guint16, + NM_UTILS_LOOKUP_DEFAULT(NULL), + NM_UTILS_LOOKUP_STR_ITEM(RTM_GETLINK, "RTM_GETLINK"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_NEWLINK, "RTM_NEWLINK"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_DELLINK, "RTM_DELLINK"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_SETLINK, "RTM_SETLINK"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_GETADDR, "RTM_GETADDR"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_NEWADDR, "RTM_NEWADDR"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_DELADDR, "RTM_DELADDR"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_GETROUTE, "RTM_GETROUTE"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_NEWROUTE, "RTM_NEWROUTE"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_DELROUTE, "RTM_DELROUTE"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_GETRULE, "RTM_GETRULE"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_NEWRULE, "RTM_NEWRULE"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_DELRULE, "RTM_DELRULE"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_GETQDISC, "RTM_GETQDISC"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_NEWQDISC, "RTM_NEWQDISC"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_DELQDISC, "RTM_DELQDISC"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_GETTFILTER, "RTM_GETTFILTER"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_NEWTFILTER, "RTM_NEWTFILTER"), + NM_UTILS_LOOKUP_STR_ITEM(RTM_DELTFILTER, "RTM_DELTFILTER"), + NM_UTILS_LOOKUP_STR_ITEM(NLMSG_NOOP, "NLMSG_NOOP"), + NM_UTILS_LOOKUP_STR_ITEM(NLMSG_ERROR, "NLMSG_ERROR"), + NM_UTILS_LOOKUP_STR_ITEM(NLMSG_DONE, "NLMSG_DONE"), + NM_UTILS_LOOKUP_STR_ITEM(NLMSG_OVERRUN, "NLMSG_OVERRUN"), ); + +static NM_UTILS_LOOKUP_STR_DEFINE( + _genl_ctrl_cmd_to_str, + guint8, + NM_UTILS_LOOKUP_DEFAULT(NULL), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_UNSPEC, "CTRL_CMD_UNSPEC"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_NEWFAMILY, "CTRL_CMD_NEWFAMILY"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_DELFAMILY, "CTRL_CMD_DELFAMILY"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_GETFAMILY, "CTRL_CMD_GETFAMILY"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_NEWOPS, "CTRL_CMD_NEWOPS"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_DELOPS, "CTRL_CMD_DELOPS"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_GETOPS, "CTRL_CMD_GETOPS"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_NEWMCAST_GRP, "CTRL_CMD_NEWMCAST_GRP"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_DELMCAST_GRP, "CTRL_CMD_DELMCAST_GRP"), + NM_UTILS_LOOKUP_STR_ITEM(CTRL_CMD_GETMCAST_GRP, "CTRL_CMD_GETMCAST_GRP"), + /* CTRL_CMD_GETPOLICY was added in Linux 5.7 (released on 31 May, 2020), + * commit d07dcf9aadd6 ('netlink: add infrastructure to expose policies to userspace') */ + NM_UTILS_LOOKUP_STR_ITEM(10 /* CTRL_CMD_GETPOLICY */, "CTRL_CMD_GETPOLICY"), ); + /*****************************************************************************/ const char * -nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len) +nl_nlmsghdr_to_str(int netlink_protocol, + guint32 pktinfo_group, + const struct nlmsghdr *hdr, + char *buf, + gsize len) { const char *b; - const char *s; + const char *s = NULL; guint flags, flags_before; const char *prefix; @@ -86,86 +141,46 @@ nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len) b = buf; - switch (hdr->nlmsg_type) { - case RTM_GETLINK: - s = "RTM_GETLINK"; - break; - case RTM_NEWLINK: - s = "RTM_NEWLINK"; - break; - case RTM_DELLINK: - s = "RTM_DELLINK"; - break; - case RTM_SETLINK: - s = "RTM_SETLINK"; - break; - case RTM_GETADDR: - s = "RTM_GETADDR"; - break; - case RTM_NEWADDR: - s = "RTM_NEWADDR"; - break; - case RTM_DELADDR: - s = "RTM_DELADDR"; - break; - case RTM_GETROUTE: - s = "RTM_GETROUTE"; - break; - case RTM_NEWROUTE: - s = "RTM_NEWROUTE"; - break; - case RTM_DELROUTE: - s = "RTM_DELROUTE"; - break; - case RTM_GETRULE: - s = "RTM_GETRULE"; - break; - case RTM_NEWRULE: - s = "RTM_NEWRULE"; - break; - case RTM_DELRULE: - s = "RTM_DELRULE"; - break; - case RTM_GETQDISC: - s = "RTM_GETQDISC"; - break; - case RTM_NEWQDISC: - s = "RTM_NEWQDISC"; - break; - case RTM_DELQDISC: - s = "RTM_DELQDISC"; - break; - case RTM_GETTFILTER: - s = "RTM_GETTFILTER"; - break; - case RTM_NEWTFILTER: - s = "RTM_NEWTFILTER"; - break; - case RTM_DELTFILTER: - s = "RTM_DELTFILTER"; - break; - case NLMSG_NOOP: - s = "NLMSG_NOOP"; - break; - case NLMSG_ERROR: - s = "NLMSG_ERROR"; - break; - case NLMSG_DONE: - s = "NLMSG_DONE"; - break; - case NLMSG_OVERRUN: - s = "NLMSG_OVERRUN"; + switch (netlink_protocol) { + case NETLINK_ROUTE: + s = _rtnl_type_to_str(hdr->nlmsg_type); + if (s) + nm_strbuf_append_str(&buf, &len, s); + else + nm_strbuf_append(&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type); break; default: + nm_assert_not_reached(); + /* fall-through */ + case NETLINK_GENERIC: + if (pktinfo_group == 0) + nm_strbuf_append(&buf, &len, "group:unicast"); + else + nm_strbuf_append(&buf, &len, "group:multicast(%u)", (unsigned) pktinfo_group); + s = NULL; + if (hdr->nlmsg_type == GENL_ID_CTRL) + s = "GENL_ID_CTRL"; + if (s) + nm_strbuf_append(&buf, &len, ", msg-type:%s", s); + else + nm_strbuf_append(&buf, &len, ", msg-type:(%u)", (unsigned) hdr->nlmsg_type); + + if (genlmsg_valid_hdr(hdr, 0)) { + const struct genlmsghdr *ghdr; + + ghdr = nlmsg_data(hdr); + s = NULL; + if (hdr->nlmsg_type == GENL_ID_CTRL) + s = _genl_ctrl_cmd_to_str(ghdr->cmd); + if (s) + nm_strbuf_append(&buf, &len, ", cmd:%s", s); + else + nm_strbuf_append(&buf, &len, ", cmd:(%u)", (unsigned) ghdr->cmd); + } break; } - if (s) - nm_strbuf_append_str(&buf, &len, s); - else - nm_strbuf_append(&buf, &len, "(%u)", (unsigned) hdr->nlmsg_type); - flags = hdr->nlmsg_flags; if (!flags) { @@ -198,27 +213,30 @@ nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len) if (flags_before != flags) prefix = ";"; - switch (hdr->nlmsg_type) { - case RTM_NEWLINK: - case RTM_NEWADDR: - case RTM_NEWROUTE: - case RTM_NEWQDISC: - case RTM_NEWTFILTER: - _F(NLM_F_REPLACE, "replace"); - _F(NLM_F_EXCL, "excl"); - _F(NLM_F_CREATE, "create"); - _F(NLM_F_APPEND, "append"); - break; - case RTM_GETLINK: - case RTM_GETADDR: - case RTM_GETROUTE: - case RTM_DELQDISC: - case RTM_DELTFILTER: - _F(NLM_F_DUMP, "dump"); - _F(NLM_F_ROOT, "root"); - _F(NLM_F_MATCH, "match"); - _F(NLM_F_ATOMIC, "atomic"); - break; + switch (netlink_protocol) { + case NETLINK_ROUTE: + switch (hdr->nlmsg_type) { + case RTM_NEWLINK: + case RTM_NEWADDR: + case RTM_NEWROUTE: + case RTM_NEWQDISC: + case RTM_NEWTFILTER: + _F(NLM_F_REPLACE, "replace"); + _F(NLM_F_EXCL, "excl"); + _F(NLM_F_CREATE, "create"); + _F(NLM_F_APPEND, "append"); + break; + case RTM_GETLINK: + case RTM_GETADDR: + case RTM_GETROUTE: + case RTM_DELQDISC: + case RTM_DELTFILTER: + _F(NLM_F_DUMP, "dump"); + _F(NLM_F_ROOT, "root"); + _F(NLM_F_MATCH, "match"); + _F(NLM_F_ATOMIC, "atomic"); + break; + } } #undef _F @@ -237,29 +255,32 @@ flags_done: /*****************************************************************************/ struct nlmsghdr * -nlmsg_hdr(struct nl_msg *n) +nlmsg_hdr(const struct nl_msg *n) { return n->nm_nlh; } void * -nlmsg_reserve(struct nl_msg *n, size_t len, int pad) +nlmsg_reserve(struct nl_msg *n, uint32_t len, uint32_t pad) { - char *buf = (char *) n->nm_nlh; - size_t nlmsg_len = n->nm_nlh->nlmsg_len; - size_t tlen; - - nm_assert(pad >= 0); + char *buf = (char *) n->nm_nlh; + uint32_t tlen; - if (len > n->nm_size) - return NULL; + nm_assert(n); + nm_assert(pad == 0 || nm_utils_is_power_of_two(pad)); + nm_assert(n->nm_nlh->nlmsg_len <= n->nm_size); - tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len; + if (pad != 0) { + tlen = (len + (pad - 1u)) & ~(pad - 1u); + if (tlen < len) + return NULL; + } else + tlen = len; - if ((tlen + nlmsg_len) > n->nm_size) + if (tlen > n->nm_size - n->nm_nlh->nlmsg_len) return NULL; - buf += nlmsg_len; + buf += n->nm_nlh->nlmsg_len; n->nm_nlh->nlmsg_len += tlen; if (tlen > len) @@ -270,6 +291,52 @@ nlmsg_reserve(struct nl_msg *n, size_t len, int pad) /*****************************************************************************/ +int +nlmsg_parse_error(const struct nlmsghdr *nlh, const char **out_extack_msg) +{ + const struct nlmsgerr *e; + + nm_assert(nlh); + + NM_SET_OUT(out_extack_msg, NULL); + + if (nlh->nlmsg_type != NLMSG_ERROR) + return -NME_NL_MSG_INVAL; + + if (nlh->nlmsg_len < nlmsg_size(sizeof(struct nlmsgerr))) { + /* Truncated error message, the default action + * is to stop parsing. The user may overrule + * this action by returning NL_SKIP or + * NL_PROCEED (dangerous) */ + return -NME_NL_MSG_TRUNC; + } + + e = nlmsg_data(nlh); + + if (!e->error) + return 0; + + if (NM_FLAGS_HAS(nlh->nlmsg_flags, NLM_F_ACK_TLVS) && out_extack_msg + && nlh->nlmsg_len >= sizeof(*e) + e->msg.nlmsg_len) { + static const struct nla_policy policy[] = { + [NLMSGERR_ATTR_MSG] = {.type = NLA_STRING}, + [NLMSGERR_ATTR_OFFS] = {.type = NLA_U32}, + }; + struct nlattr *tb[G_N_ELEMENTS(policy)]; + struct nlattr *tlvs; + + tlvs = (struct nlattr *) ((char *) e + sizeof(*e) + e->msg.nlmsg_len - NLMSG_HDRLEN); + if (nla_parse_arr(tb, tlvs, nlh->nlmsg_len - sizeof(*e) - e->msg.nlmsg_len, policy) >= 0) { + if (tb[NLMSGERR_ATTR_MSG]) + *out_extack_msg = nla_get_string(tb[NLMSGERR_ATTR_MSG]); + } + } + + return -nm_errno_from_native(e->error); +} + +/*****************************************************************************/ + struct nlattr * nla_reserve(struct nl_msg *msg, int attrtype, int attrlen) { @@ -304,6 +371,8 @@ nlmsg_alloc_size(size_t len) if (len < sizeof(struct nlmsghdr)) len = sizeof(struct nlmsghdr); + else if (len > UINT32_MAX) + g_return_val_if_reached(NULL); nm = g_slice_new(struct nl_msg); *nm = (struct nl_msg){ @@ -341,7 +410,7 @@ nlmsg_alloc_convert(struct nlmsghdr *hdr) } struct nl_msg * -nlmsg_alloc_simple(int nlmsgtype, int flags) +nlmsg_alloc_simple(uint16_t nlmsgtype, uint16_t flags) { struct nl_msg *nm; struct nlmsghdr *new; @@ -366,27 +435,27 @@ nlmsg_free(struct nl_msg *msg) /*****************************************************************************/ int -nlmsg_append(struct nl_msg *n, const void *data, size_t len, int pad) +nlmsg_append(struct nl_msg *n, const void *data, uint32_t len, uint32_t pad) { void *tmp; nm_assert(n); - nm_assert(data); - nm_assert(len > 0); - nm_assert(pad >= 0); + nm_assert(len == 0 || data); tmp = nlmsg_reserve(n, len, pad); - if (tmp == NULL) + if (!tmp) return -ENOMEM; - memcpy(tmp, data, len); + if (len > 0) + memcpy(tmp, data, len); + return 0; } /*****************************************************************************/ int -nlmsg_parse(struct nlmsghdr *nlh, +nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, @@ -399,14 +468,17 @@ nlmsg_parse(struct nlmsghdr *nlh, } struct nlmsghdr * -nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, int flags) +nlmsg_put(struct nl_msg *n, + uint32_t pid, + uint32_t seq, + uint16_t type, + uint32_t payload, + uint16_t flags) { - struct nlmsghdr *nlh; + struct nlmsghdr *nlh = (struct nlmsghdr *) n->nm_nlh; - if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN) - g_return_val_if_reached(NULL); + nm_assert(nlh->nlmsg_len >= NLMSG_HDRLEN); - nlh = (struct nlmsghdr *) n->nm_nlh; nlh->nlmsg_type = type; nlh->nlmsg_flags = flags; nlh->nlmsg_pid = pid; @@ -547,7 +619,8 @@ nla_nest_start(struct nl_msg *msg, int attrtype) static int _nest_end(struct nl_msg *msg, struct nlattr *start, int keep_empty) { - size_t pad, len; + size_t len; + uint32_t pad; len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) start; @@ -566,14 +639,18 @@ _nest_end(struct nl_msg *msg, struct nlattr *start, int keep_empty) pad = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len; if (pad > 0) { + void *p; + /* * Data inside attribute does not end at a alignment boundary. * Pad accordingly and account for the additional space in * the message. nlmsg_reserve() may never fail in this situation, * the allocate message buffer must be a multiple of NLMSG_ALIGNTO. */ - if (!nlmsg_reserve(msg, pad, 0)) + p = nlmsg_reserve(msg, pad, 0); + if (!p) g_return_val_if_reached(-NME_BUG); + memset(p, 0, pad); } return 0; @@ -588,6 +665,7 @@ nla_nest_end(struct nl_msg *msg, struct nlattr *start) static const uint8_t nla_attr_minlen[NLA_TYPE_MAX + 1] = { [NLA_U8] = sizeof(uint8_t), [NLA_U16] = sizeof(uint16_t), + [NLA_S32] = sizeof(int32_t), [NLA_U32] = sizeof(uint32_t), [NLA_U64] = sizeof(uint64_t), [NLA_STRING] = 1, @@ -712,9 +790,9 @@ void * genlmsg_put(struct nl_msg *msg, uint32_t port, uint32_t seq, - int family, - int hdrlen, - int flags, + uint16_t family, + uint32_t hdrlen, + uint16_t flags, uint8_t cmd, uint8_t version) { @@ -745,8 +823,8 @@ genlmsg_user_hdr(const struct genlmsghdr *gnlh) return genlmsg_data(gnlh); } -struct genlmsghdr * -genlmsg_hdr(struct nlmsghdr *nlh) +const struct genlmsghdr * +genlmsg_hdr(const struct nlmsghdr *nlh) { return nlmsg_data(nlh); } @@ -779,7 +857,7 @@ genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen) } int -genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen) +genlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen) { struct genlmsghdr *ghdr; @@ -794,13 +872,13 @@ genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen) } int -genlmsg_parse(struct nlmsghdr *nlh, +genlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy) { - struct genlmsghdr *ghdr; + const struct genlmsghdr *ghdr; if (!genlmsg_valid_hdr(nlh, hdrlen)) return -NME_NL_MSG_TOOSHORT; @@ -813,23 +891,24 @@ genlmsg_parse(struct nlmsghdr *nlh, policy); } +const struct nla_policy genl_ctrl_policy[CTRL_ATTR_MCAST_GROUPS + 1] = { + [CTRL_ATTR_FAMILY_ID] = {.type = NLA_U16}, + [CTRL_ATTR_FAMILY_NAME] = {.type = NLA_STRING, .maxlen = GENL_NAMSIZ}, + [CTRL_ATTR_VERSION] = {.type = NLA_U32}, + [CTRL_ATTR_HDRSIZE] = {.type = NLA_U32}, + [CTRL_ATTR_MAXATTR] = {.type = NLA_U32}, + [CTRL_ATTR_OPS] = {.type = NLA_NESTED}, + [CTRL_ATTR_MCAST_GROUPS] = {.type = NLA_NESTED}, +}; + static int -_genl_parse_getfamily(struct nl_msg *msg, void *arg) +_genl_parse_getfamily(const struct nl_msg *msg, void *arg) { - static const struct nla_policy ctrl_policy[] = { - [CTRL_ATTR_FAMILY_ID] = {.type = NLA_U16}, - [CTRL_ATTR_FAMILY_NAME] = {.type = NLA_STRING, .maxlen = GENL_NAMSIZ}, - [CTRL_ATTR_VERSION] = {.type = NLA_U32}, - [CTRL_ATTR_HDRSIZE] = {.type = NLA_U32}, - [CTRL_ATTR_MAXATTR] = {.type = NLA_U32}, - [CTRL_ATTR_OPS] = {.type = NLA_NESTED}, - [CTRL_ATTR_MCAST_GROUPS] = {.type = NLA_NESTED}, - }; - struct nlattr *tb[G_N_ELEMENTS(ctrl_policy)]; + struct nlattr *tb[G_N_ELEMENTS(genl_ctrl_policy)]; struct nlmsghdr *nlh = nlmsg_hdr(msg); gint32 *response_data = arg; - if (genlmsg_parse_arr(nlh, 0, tb, ctrl_policy) < 0) + if (genlmsg_parse_arr(nlh, 0, tb, genl_ctrl_policy) < 0) return NL_SKIP; if (tb[CTRL_ATTR_FAMILY_ID]) @@ -879,30 +958,14 @@ genl_ctrl_resolve(struct nl_sock *sk, const char *name) /*****************************************************************************/ -struct nl_sock * -nl_socket_alloc(void) -{ - struct nl_sock *sk; - - sk = g_slice_new0(struct nl_sock); - - sk->s_fd = -1; - sk->s_local.nl_family = AF_NETLINK; - sk->s_peer.nl_family = AF_NETLINK; - sk->s_seq_expect = sk->s_seq_next = time(NULL); - - return sk; -} - void nl_socket_free(struct nl_sock *sk) { if (!sk) return; - if (sk->s_fd >= 0) - nm_close(sk->s_fd); - g_slice_free(struct nl_sock, sk); + nm_close(sk->s_fd); + nm_g_slice_free(sk); } int @@ -928,18 +991,24 @@ nl_socket_set_passcred(struct nl_sock *sk, int state) { int err; - if (sk->s_fd == -1) - return -NME_NL_BAD_SOCK; + nm_assert_sk(sk); err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED, &state, sizeof(state)); if (err < 0) return -nm_errno_from_native(errno); + return 0; +} - if (state) - sk->s_flags |= NL_SOCK_PASSCRED; - else - sk->s_flags &= ~NL_SOCK_PASSCRED; +int +nl_socket_set_pktinfo(struct nl_sock *sk, int state) +{ + int err; + nm_assert_sk(sk); + + err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_PKTINFO, &state, sizeof(state)); + if (err < 0) + return -nm_errno_from_native(errno); return 0; } @@ -960,8 +1029,7 @@ nlmsg_get_dst(struct nl_msg *msg) int nl_socket_set_nonblocking(const struct nl_sock *sk) { - if (sk->s_fd == -1) - return -NME_NL_BAD_SOCK; + nm_assert_sk(sk); if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0) return -nm_errno_from_native(errno); @@ -974,15 +1042,14 @@ nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf) { int err; + nm_assert_sk(sk); + if (rxbuf <= 0) rxbuf = 32768; if (txbuf <= 0) txbuf = 32768; - if (sk->s_fd == -1) - return -NME_NL_BAD_SOCK; - err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, &txbuf, sizeof(txbuf)); if (err < 0) { return -nm_errno_from_native(errno); @@ -1002,8 +1069,7 @@ nl_socket_add_memberships(struct nl_sock *sk, int group, ...) int err; va_list ap; - if (sk->s_fd == -1) - return -NME_NL_BAD_SOCK; + nm_assert_sk(sk); va_start(ap, group); @@ -1029,85 +1095,96 @@ nl_socket_add_memberships(struct nl_sock *sk, int group, ...) return 0; } +/*****************************************************************************/ + int -nl_socket_set_ext_ack(struct nl_sock *sk, gboolean enable) +nl_socket_new(struct nl_sock **out_sk, + int protocol, + NLSocketFlags flags, + int bufsize_rx, + int bufsize_tx) { - int err, val; - - if (sk->s_fd == -1) - return -NME_NL_BAD_SOCK; - - val = !!enable; - err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &val, sizeof(val)); - if (err < 0) + nm_auto_nlsock struct nl_sock *sk = NULL; + nm_auto_close int fd = -1; + time_t t; + int err; + int nmerr; + socklen_t addrlen; + struct sockaddr_nl local = {0}; + int i_val; + + nm_assert(out_sk && !*out_sk); + + fd = socket(AF_NETLINK, + SOCK_RAW | SOCK_CLOEXEC + | (NM_FLAGS_HAS(flags, NL_SOCKET_FLAGS_NONBLOCK) ? SOCK_NONBLOCK : 0), + protocol); + if (fd < 0) return -nm_errno_from_native(errno); - return 0; -} - -void -nl_socket_disable_msg_peek(struct nl_sock *sk) -{ - sk->s_flags |= NL_MSG_PEEK_EXPLICIT; - sk->s_flags &= ~NL_MSG_PEEK; -} + t = time(NULL); + + sk = g_slice_new(struct nl_sock); + *sk = (struct nl_sock){ + .s_fd = nm_steal_fd(&fd), + .s_local = + { + .nl_pid = 0, + .nl_family = AF_NETLINK, + .nl_groups = 0, + }, + .s_peer = + { + .nl_pid = 0, + .nl_family = AF_NETLINK, + .nl_groups = 0, + }, + .s_seq_expect = t, + .s_seq_next = t, + .s_bufsize = 0, + .s_msg_peek = !NM_FLAGS_HAS(flags, NL_SOCKET_FLAGS_DISABLE_MSG_PEEK), + .s_auto_ack = TRUE, + }; -int -nl_connect(struct nl_sock *sk, int protocol) -{ - int err, nmerr; - socklen_t addrlen; - struct sockaddr_nl local = {0}; + nmerr = nl_socket_set_buffer_size(sk, bufsize_rx, bufsize_tx); + if (nmerr < 0) + return nmerr; - if (sk->s_fd != -1) - return -NME_NL_BAD_SOCK; + i_val = 1; + (void) setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_EXT_ACK, &i_val, sizeof(i_val)); - sk->s_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); - if (sk->s_fd < 0) { - nmerr = -nm_errno_from_native(errno); - goto errout; + if (NM_FLAGS_HAS(flags, NL_SOCKET_FLAGS_PASSCRED)) { + err = nl_socket_set_passcred(sk, 1); + if (err < 0) + return err; } - nmerr = nl_socket_set_buffer_size(sk, 0, 0); - if (nmerr < 0) - goto errout; - - nm_assert(sk->s_local.nl_pid == 0); + if (NM_FLAGS_HAS(flags, NL_SOCKET_FLAGS_PKTINFO)) { + err = nl_socket_set_pktinfo(sk, 1); + if (err < 0) + return err; + } err = bind(sk->s_fd, (struct sockaddr *) &sk->s_local, sizeof(sk->s_local)); - if (err != 0) { - nmerr = -nm_errno_from_native(errno); - goto errout; - } + if (err != 0) + return -nm_errno_from_native(errno); addrlen = sizeof(local); err = getsockname(sk->s_fd, (struct sockaddr *) &local, &addrlen); - if (err < 0) { - nmerr = -nm_errno_from_native(errno); - goto errout; - } + if (err < 0) + return -nm_errno_from_native(errno); - if (addrlen != sizeof(local)) { - nmerr = -NME_UNSPEC; - goto errout; - } + if (addrlen != sizeof(local)) + return -NME_UNSPEC; - if (local.nl_family != AF_NETLINK) { - nmerr = -NME_UNSPEC; - goto errout; - } + if (local.nl_family != AF_NETLINK) + return -NME_UNSPEC; sk->s_local = local; sk->s_proto = protocol; + *out_sk = g_steal_pointer(&sk); return 0; - -errout: - if (sk->s_fd != -1) { - close(sk->s_fd); - sk->s_fd = -1; - } - return nmerr; } /*****************************************************************************/ @@ -1124,7 +1201,7 @@ _cb_init(struct nl_cb *dst, const struct nl_cb *src) } static int -ack_wait_handler(struct nl_msg *msg, void *arg) +ack_wait_handler(const struct nl_msg *msg, void *arg) { return NL_STOP; } @@ -1176,7 +1253,7 @@ nl_recvmsgs(struct nl_sock *sk, const struct nl_cb *cb) gboolean creds_has; continue_reading: - n = nl_recv(sk, NULL, 0, &nla, &buf, &creds, &creds_has); + n = nl_recv(sk, NULL, 0, &nla, &buf, &creds, &creds_has, NULL, NULL); if (n <= 0) return n; @@ -1193,7 +1270,7 @@ continue_reading: nrecv++; /* Only do sequence checking if auto-ack mode is enabled */ - if (!(sk->s_flags & NL_NO_AUTO_ACK)) { + if (sk->s_auto_ack) { if (hdr->nlmsg_seq != sk->s_seq_expect) { nmerr = -NME_NL_SEQ_MISMATCH; goto out; @@ -1378,7 +1455,7 @@ nl_complete_msg(struct nl_sock *sk, struct nl_msg *msg) nlh->nlmsg_flags |= NLM_F_REQUEST; - if (!(sk->s_flags & NL_NO_AUTO_ACK)) + if (sk->s_auto_ack) nlh->nlmsg_flags |= NLM_F_ACK; } @@ -1413,6 +1490,10 @@ nl_send_auto(struct nl_sock *sk, struct nl_msg *msg) * on success. * @out_creds_has: (out) (allow-none): result indicating whether * @out_creds was filled. +* @out_pktinfo_group: (out) (allow-none): optional out buffer for NETLINK_PKTINFO +* group on success. + * @out_pktinfo_has: (out) (allow-none): result indicating whether + * @out_pktinfo_group was filled. * * If @buf0_len is zero, the function will g_malloc() a new receive buffer of size * nl_socket_get_msg_buf_size(). If @buf0_len is larger than zero, then @buf0 @@ -1435,18 +1516,20 @@ nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, unsigned char **buf, struct ucred *out_creds, - gboolean *out_creds_has) + gboolean *out_creds_has, + uint32_t *out_pktinfo_group, + gboolean *out_pktinfo_has) { - /* We really expect msg_contol_buf to be large enough and MSG_CTRUNC not - * happening. We nm_assert() against that. However, in release builds - * we don't assert, so add some extra safety space for the unexpected - * case where we might need more than CMSG_SPACE(sizeof(struct ucred)). - * It should not hurt and should not be necessary. It's just some - * extra defensive space. */ -#define _MSG_CONTROL_BUF_EXTRA_SPACE (NM_MORE_ASSERTS ? 512u : 0u) union { - struct cmsghdr cmsghdr; - char buf[CMSG_SPACE(sizeof(struct ucred)) + _MSG_CONTROL_BUF_EXTRA_SPACE]; + struct cmsghdr _dummy_for_alignment; + struct { + char buf[CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(struct nl_pktinfo))]; + + /* We really expect that "buf" is large enough end even assert against + * that. We don't expect and don't want to handle MSG_CTRUNC error. + * Still, add some extra safety. This is on the stack and essentially for free. */ + char _extra[512]; + }; } msg_contol_buf; ssize_t n; int flags = 0; @@ -1459,17 +1542,16 @@ nl_recv(struct nl_sock *sk, .msg_controllen = 0, .msg_control = NULL, }; - struct ucred tmpcreds; - gboolean tmpcreds_has = FALSE; - int retval; - int errsv; + struct cmsghdr *cmsg; + int retval; + int errsv; nm_assert(nla); nm_assert(buf && !*buf); - nm_assert(!out_creds_has == !out_creds); + nm_assert(!out_creds_has || out_creds); + nm_assert(!out_pktinfo_has || out_pktinfo_group); - if ((sk->s_flags & NL_MSG_PEEK) - || (!(sk->s_flags & NL_MSG_PEEK_EXPLICIT) && sk->s_bufsize == 0)) + if (sk->s_msg_peek) flags |= MSG_PEEK | MSG_TRUNC; if (buf0_len > 0) { @@ -1480,7 +1562,7 @@ nl_recv(struct nl_sock *sk, iov.iov_base = g_malloc(iov.iov_len); } - if (out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) { + if (out_creds_has || out_pktinfo_has) { msg.msg_controllen = sizeof(msg_contol_buf); msg.msg_control = msg_contol_buf.buf; } @@ -1500,11 +1582,14 @@ retry: goto abort; } + nm_assert((gsize) n <= G_MAXINT); + /* We really don't expect truncation of ancillary data. We provided a large * enough buffer, so this is likely a bug. In the worst case, we might lack * the requested credentials and the caller likely will reject the message * later. */ nm_assert(!(msg.msg_flags & MSG_CTRUNC)); + nm_assert(msg.msg_controllen <= G_STRUCT_OFFSET(typeof(msg_contol_buf), _extra)); if (iov.iov_len < n || (msg.msg_flags & MSG_TRUNC)) { /* respond with error to an incomplete message */ @@ -1533,32 +1618,35 @@ retry: goto abort; } - if (out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) { - struct cmsghdr *cmsg; - + if (out_creds_has || out_pktinfo_has) { + NM_SET_OUT(out_creds_has, FALSE); + NM_SET_OUT(out_pktinfo_has, FALSE); for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level != SOL_SOCKET) - continue; - if (cmsg->cmsg_type != SCM_CREDENTIALS) - continue; - memcpy(&tmpcreds, CMSG_DATA(cmsg), sizeof(tmpcreds)); - tmpcreds_has = TRUE; - break; + switch (cmsg->cmsg_level) { + case SOL_SOCKET: + if (cmsg->cmsg_type == SCM_CREDENTIALS && out_creds_has) { + memcpy(out_creds, CMSG_DATA(cmsg), sizeof(*out_creds)); + *out_creds_has = TRUE; + } + break; + case SOL_NETLINK: + if (cmsg->cmsg_type == NETLINK_PKTINFO && out_pktinfo_has) { + struct nl_pktinfo p; + + memcpy(&p, CMSG_DATA(cmsg), sizeof(p)); + *out_pktinfo_group = p.group; + *out_pktinfo_has = TRUE; + } + break; + } } } - retval = n; + *buf = iov.iov_base; + return (int) n; abort: - if (retval <= 0) { - if (iov.iov_base != buf0) - g_free(iov.iov_base); - return retval; - } - - *buf = iov.iov_base; - if (out_creds && tmpcreds_has) - *out_creds = tmpcreds; - NM_SET_OUT(out_creds_has, tmpcreds_has); + if (iov.iov_base != buf0) + g_free(iov.iov_base); return retval; } diff --git a/src/libnm-platform/nm-netlink.h b/src/libnm-platform/nm-netlink.h index bb1e41ee..44ed70af 100644 --- a/src/libnm-platform/nm-netlink.h +++ b/src/libnm-platform/nm-netlink.h @@ -31,6 +31,7 @@ enum { NLA_UNSPEC, /* Unspecified type, binary data chunk */ NLA_U8, /* 8 bit integer */ NLA_U16, /* 16 bit integer */ + NLA_S32, /* 32 bit integer */ NLA_U32, /* 32 bit integer */ NLA_U64, /* 64 bit integer */ NLA_STRING, /* NUL terminated character string */ @@ -43,13 +44,37 @@ enum { struct nl_msg; +/* This is similar to "struct nl_msg", in that it contains a + * netlink message including additional information like the + * src, creds, protocol. + * + * The difference is that "struct nl_msg" is an opaque type and + * contains a copy of the message (requiring two heap allocations). + * "struct nl_msg_lite" can be on the stack and it can directly + * point to the receive buffer, without need to copy the message. + * That can be useful, if you don't need to clone the message and + * just need to pass it "down the stack" for somebody to parse + * the message. */ +struct nl_msg_lite { + int nm_protocol; + const struct sockaddr_nl *nm_src; + const struct sockaddr_nl *nm_dst; + const struct ucred *nm_creds; + const struct nlmsghdr *nm_nlh; + uint32_t nm_size; +}; + /*****************************************************************************/ const char *nl_nlmsgtype2str(int type, char *buf, size_t size); const char *nl_nlmsg_flags2str(int flags, char *buf, size_t len); -const char *nl_nlmsghdr_to_str(const struct nlmsghdr *hdr, char *buf, gsize len); +const char *nl_nlmsghdr_to_str(int netlink_protocol, + guint32 pktinfo_group, + const struct nlmsghdr *hdr, + char *buf, + gsize len); /*****************************************************************************/ @@ -267,20 +292,21 @@ nla_put_uint32(struct nl_msg *msg, int attrtype, uint32_t val) return nla_put(msg, attrtype, sizeof(val), &val); } -#define NLA_PUT(msg, attrtype, attrlen, data) \ - G_STMT_START \ - { \ - if (nla_put(msg, attrtype, attrlen, data) < 0) \ - goto nla_put_failure; \ - } \ +#define NLA_PUT(msg, attrtype, attrlen, data) \ + G_STMT_START \ + { \ + if (nla_put((msg), (attrtype), (attrlen), (data)) < 0) \ + goto nla_put_failure; \ + } \ G_STMT_END -#define NLA_PUT_TYPE(msg, type, attrtype, value) \ - G_STMT_START \ - { \ - type __nla_tmp = value; \ - NLA_PUT(msg, attrtype, sizeof(type), &__nla_tmp); \ - } \ +#define NLA_PUT_TYPE(msg, type, attrtype, value) \ + G_STMT_START \ + { \ + type const _nla_tmp = value; \ + \ + NLA_PUT((msg), (attrtype), sizeof(_nla_tmp), &_nla_tmp); \ + } \ G_STMT_END #define NLA_PUT_U8(msg, attrtype, value) NLA_PUT_TYPE(msg, uint8_t, attrtype, value) @@ -328,6 +354,14 @@ void nla_nest_cancel(struct nl_msg *msg, const struct nlattr *attr); struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype); int nla_nest_end(struct nl_msg *msg, struct nlattr *start); +#define NLA_NEST_END(msg, nest_start) \ + G_STMT_START \ + { \ + if (nla_nest_end((msg), (nest_start)) < 0) \ + goto nla_put_failure; \ + } \ + G_STMT_END + int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, @@ -365,13 +399,13 @@ struct nl_msg *nlmsg_alloc_size(size_t max); struct nl_msg *nlmsg_alloc_convert(struct nlmsghdr *hdr); -struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags); +struct nl_msg *nlmsg_alloc_simple(uint16_t nlmsgtype, uint16_t flags); -void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad); +void *nlmsg_reserve(struct nl_msg *n, uint32_t len, uint32_t pad); -int nlmsg_append(struct nl_msg *n, const void *data, size_t len, int pad); +int nlmsg_append(struct nl_msg *n, const void *data, uint32_t len, uint32_t pad); -#define nlmsg_append_struct(n, data) nlmsg_append(n, (data), sizeof(*(data)), NLMSG_ALIGNTO) +#define nlmsg_append_struct(n, data) (nlmsg_append((n), (data), sizeof(*(data)), NLMSG_ALIGNTO)) void nlmsg_free(struct nl_msg *msg); @@ -413,26 +447,29 @@ void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr); struct ucred *nlmsg_get_creds(struct nl_msg *msg); void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds); -static inline void -_nm_auto_nl_msg_cleanup(struct nl_msg **ptr) +NM_AUTO_DEFINE_FCN0(struct nl_msg *, _nm_auto_nl_msg_cleanup, nlmsg_free); +#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup) + +static inline const struct nlmsghdr * +nlmsg_undata(const void *data) { - nlmsg_free(*ptr); + /* from the data, get back the header. It's the inverse of nlmsg_data(). */ + return (void *) (((unsigned char *) data) - NLMSG_HDRLEN); } -#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup) static inline void * nlmsg_data(const struct nlmsghdr *nlh) { - return (unsigned char *) nlh + NLMSG_HDRLEN; + return ((unsigned char *) nlh) + NLMSG_HDRLEN; } static inline void * nlmsg_tail(const struct nlmsghdr *nlh) { - return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len); + return ((unsigned char *) nlh) + NLMSG_ALIGN(nlh->nlmsg_len); } -struct nlmsghdr *nlmsg_hdr(struct nl_msg *n); +struct nlmsghdr *nlmsg_hdr(const struct nl_msg *n); static inline int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen) @@ -468,7 +505,9 @@ nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype) return nla_find(nlmsg_attrdata(nlh, hdrlen), nlmsg_attrlen(nlh, hdrlen), attrtype); } -int nlmsg_parse(struct nlmsghdr *nlh, +int nlmsg_parse_error(const struct nlmsghdr *nlh, const char **out_extack_msg); + +int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, @@ -482,20 +521,41 @@ int nlmsg_parse(struct nlmsghdr *nlh, nlmsg_parse((nlh), (hdrlen), (tb), G_N_ELEMENTS(tb) - 1, (policy)); \ }) -struct nlmsghdr * -nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq, int type, int payload, int flags); +struct nlmsghdr *nlmsg_put(struct nl_msg *n, + uint32_t pid, + uint32_t seq, + uint16_t type, + uint32_t payload, + uint16_t flags); /*****************************************************************************/ +typedef enum { + NL_SOCKET_FLAGS_NONE = 0, + NL_SOCKET_FLAGS_NONBLOCK = 0x1, + NL_SOCKET_FLAGS_PASSCRED = 0x2, + NL_SOCKET_FLAGS_PKTINFO = 0x4, + NL_SOCKET_FLAGS_DISABLE_MSG_PEEK = 0x8, + + _NL_SOCKET_FLAGS_ALL = (NL_SOCKET_FLAGS_DISABLE_MSG_PEEK << 1) - 1, +} NLSocketFlags; + #define NL_AUTO_PORT 0 #define NL_AUTO_SEQ 0 struct nl_sock; -struct nl_sock *nl_socket_alloc(void); +int nl_socket_new(struct nl_sock **out_sk, + int protocol, + NLSocketFlags flags, + int bufsize_rx, + int bufsize_tx); void nl_socket_free(struct nl_sock *sk); +NM_AUTO_DEFINE_FCN0(struct nl_sock *, _nm_auto_nlsock, nl_socket_free); +#define nm_auto_nlsock nm_auto(_nm_auto_nlsock) + int nl_socket_get_fd(const struct nl_sock *sk); struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg); @@ -507,9 +567,9 @@ int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf); int nl_socket_set_passcred(struct nl_sock *sk, int state); -int nl_socket_set_nonblocking(const struct nl_sock *sk); +int nl_socket_set_pktinfo(struct nl_sock *sk, int state); -void nl_socket_disable_msg_peek(struct nl_sock *sk); +int nl_socket_set_nonblocking(const struct nl_sock *sk); uint32_t nl_socket_get_local_port(const struct nl_sock *sk); @@ -523,7 +583,9 @@ int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, unsigned char **buf, struct ucred *out_creds, - gboolean *out_creds_has); + gboolean *out_creds_has, + uint32_t *out_pktinfo_group, + gboolean *out_pktinfo_has); int nl_send(struct nl_sock *sk, struct nl_msg *msg); @@ -540,9 +602,11 @@ enum nl_cb_action { NL_STOP, }; -typedef int (*nl_recvmsg_msg_cb_t)(struct nl_msg *msg, void *arg); +typedef int (*nl_recvmsg_msg_cb_t)(const struct nl_msg *msg, void *arg); -typedef int (*nl_recvmsg_err_cb_t)(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg); +typedef int (*nl_recvmsg_err_cb_t)(const struct sockaddr_nl *nla, + const struct nlmsgerr *nlerr, + void *arg); struct nl_cb { nl_recvmsg_msg_cb_t valid_cb; @@ -568,28 +632,28 @@ int nl_recvmsgs(struct nl_sock *sk, const struct nl_cb *cb); int nl_wait_for_ack(struct nl_sock *sk, const struct nl_cb *cb); -int nl_socket_set_ext_ack(struct nl_sock *sk, gboolean enable); - /*****************************************************************************/ -void *genlmsg_put(struct nl_msg *msg, - uint32_t port, - uint32_t seq, - int family, - int hdrlen, - int flags, - uint8_t cmd, - uint8_t version); -void *genlmsg_data(const struct genlmsghdr *gnlh); -void *genlmsg_user_hdr(const struct genlmsghdr *gnlh); -struct genlmsghdr *genlmsg_hdr(struct nlmsghdr *nlh); -void *genlmsg_user_data(const struct genlmsghdr *gnlh, const int hdrlen); -struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen); -int genlmsg_len(const struct genlmsghdr *gnlh); -int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen); -int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen); - -int genlmsg_parse(struct nlmsghdr *nlh, +extern const struct nla_policy genl_ctrl_policy[8]; + +void *genlmsg_put(struct nl_msg *msg, + uint32_t port, + uint32_t seq, + uint16_t family, + uint32_t hdrlen, + uint16_t flags, + uint8_t cmd, + uint8_t version); +void *genlmsg_data(const struct genlmsghdr *gnlh); +void *genlmsg_user_hdr(const struct genlmsghdr *gnlh); +const struct genlmsghdr *genlmsg_hdr(const struct nlmsghdr *nlh); +void *genlmsg_user_data(const struct genlmsghdr *gnlh, const int hdrlen); +struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen); +int genlmsg_len(const struct genlmsghdr *gnlh); +int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen); +int genlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen); + +int genlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 090af26d..df177485 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -7,6 +7,8 @@ #include "nm-platform.h" +#include "libnm-std-aux/nm-linux-compat.h" + #include #include #include @@ -113,24 +115,29 @@ nmp_link_address_get_as_bytes(const NMPLinkAddress *addr) #define _NMLOG_DOMAIN LOGD_PLATFORM #define _NMLOG_PREFIX_NAME "platform" -#define NMLOG_COMMON(level, name, ...) \ - char __prefix[32]; \ - const char *__p_prefix = _NMLOG_PREFIX_NAME; \ - const NMPlatform *const __self = (self); \ - const char *__name = name; \ - \ - if (__self && NM_PLATFORM_GET_PRIVATE(__self)->log_with_ptr) { \ - g_snprintf(__prefix, sizeof(__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ - __p_prefix = __prefix; \ - } \ - _nm_log(__level, \ - _NMLOG_DOMAIN, \ - 0, \ - __name, \ - NULL, \ - "%s: %s%s%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - __p_prefix, \ - NM_PRINT_FMT_QUOTED(__name, "(", __name, ") ", "") _NM_UTILS_MACRO_REST(__VA_ARGS__)); +#define NMLOG_COMMON(level, name, ...) \ + G_STMT_START \ + { \ + char __prefix[32]; \ + const char *__p_prefix = _NMLOG_PREFIX_NAME; \ + const NMPlatform *const __self = (self); \ + const char *__name = name; \ + \ + if (__self && NM_PLATFORM_GET_PRIVATE(__self)->log_with_ptr) { \ + g_snprintf(__prefix, sizeof(__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ + __p_prefix = __prefix; \ + } \ + _nm_log((level), \ + _NMLOG_DOMAIN, \ + 0, \ + __name, \ + NULL, \ + "%s: %s%s%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + __p_prefix, \ + NM_PRINT_FMT_QUOTED(__name, "(", __name, ") ", "") \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + G_STMT_END #define _NMLOG(level, ...) \ G_STMT_START \ @@ -395,6 +402,76 @@ _nm_platform_kernel_support_init(NMPlatformKernelSupportType type, int value) /*****************************************************************************/ +const NMPGenlFamilyInfo nmp_genl_family_infos[_NMP_GENL_FAMILY_TYPE_NUM] = { + [NMP_GENL_FAMILY_TYPE_ETHTOOL] = + { + .name = "ethtool", + }, + [NMP_GENL_FAMILY_TYPE_MPTCP_PM] = + { + .name = MPTCP_PM_NAME, + }, + [NMP_GENL_FAMILY_TYPE_NL80211] = + { + .name = "nl80211", + }, + [NMP_GENL_FAMILY_TYPE_NL802154] = + { + .name = "nl802154", + }, + [NMP_GENL_FAMILY_TYPE_WIREGUARD] = + { + .name = "wireguard", + }, +}; + +NMPGenlFamilyType +nmp_genl_family_type_from_name(const char *name) +{ + int imin, imax, imid; + + if (NM_MORE_ASSERT_ONCE(50)) { + int i; + + for (i = 0; i < (int) G_N_ELEMENTS(nmp_genl_family_infos); i++) { + nm_assert(nmp_genl_family_infos[i].name); + if (i > 0) + nm_assert(strcmp(nmp_genl_family_infos[i - 1].name, nmp_genl_family_infos[i].name) + < 0); + } + } + + if (!name) + goto out; + + imin = 0; + imax = G_N_ELEMENTS(nmp_genl_family_infos) - 1; + imid = imax / 2; + + while (TRUE) { + int c; + + c = strcmp(nmp_genl_family_infos[imid].name, name); + if (c == 0) + return (NMPGenlFamilyType) imid; + + if (c < 0) + imin = imid + 1; + else + imax = imid - 1; + + if (imin > imax) + break; + + imid = (imax + imin) / 2; + } + +out: + return _NMP_GENL_FAMILY_TYPE_NONE; +} + +/*****************************************************************************/ + /** * nm_platform_process_events: * @self: platform instance @@ -1292,6 +1369,12 @@ nm_platform_link_add(NMPlatform *self, buf_p, buf_len); break; + case NM_LINK_TYPE_BOND: + nm_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_platform_lnk_bond_to_string((const NMPlatformLnkBond *) extra_data, + buf_p, + buf_len); + break; default: nm_assert(!extra_data); break; @@ -1332,6 +1415,12 @@ nm_platform_link_change(NMPlatform *self, NMLinkType type, int ifindex, gconstpo buf_p, buf_len); break; + case NM_LINK_TYPE_BOND: + nm_strbuf_append_str(&buf_p, &buf_len, ", "); + nm_platform_lnk_bond_to_string((const NMPlatformLnkBond *) extra_data, + buf_p, + buf_len); + break; default: nm_assert(!extra_data); break; @@ -2232,6 +2321,12 @@ _link_get_lnk(NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatf return lnk ? &lnk->object : NULL; } +const NMPlatformLnkBond * +nm_platform_link_get_lnk_bond(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk(self, ifindex, NM_LINK_TYPE_BOND, out_link); +} + const NMPlatformLnkBridge * nm_platform_link_get_lnk_bridge(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -4133,7 +4228,7 @@ nm_platform_ip_address_sync(NMPlatform *self, * we check the "secondary" flag. */ plat_addresses = nm_platform_lookup_clone( self, - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex), + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex), NULL, NULL); @@ -4436,18 +4531,20 @@ next_plat:; nm_platform_ip4_broadcast_address_from_addr(&known_address->a4), lifetime, preferred, - IFA_F_NOPREFIXROUTE, + known_address->ax.a_no_auto_noprefixroute ? 0 : IFA_F_NOPREFIXROUTE, known_address->a4.label)) success = FALSE; } else { - if (!nm_platform_ip6_address_add(self, - ifindex, - known_address->a6.address, - known_address->a6.plen, - known_address->a6.peer_address, - lifetime, - preferred, - IFA_F_NOPREFIXROUTE | known_address->a6.n_ifa_flags)) + if (!nm_platform_ip6_address_add( + self, + ifindex, + known_address->a6.address, + known_address->a6.plen, + known_address->a6.peer_address, + lifetime, + preferred, + (known_address->ax.a_no_auto_noprefixroute ? 0 : IFA_F_NOPREFIXROUTE) + | known_address->a6.n_ifa_flags)) success = FALSE; } } @@ -4545,7 +4642,9 @@ nm_platform_ip_address_get_prune_list(NMPlatform *self, GPtrArray *result = NULL; CList *iter; - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(NM_IS_IPv4(addr_family)), ifindex); + nmp_lookup_init_object_by_ifindex(&lookup, + NMP_OBJECT_TYPE_IP_ADDRESS(NM_IS_IPv4(addr_family)), + ifindex); head_entry = nm_platform_lookup(self, &lookup); @@ -4626,7 +4725,9 @@ nm_platform_ip_route_get_prune_list(NMPlatform *self, NM_IP_ROUTE_TABLE_SYNC_MODE_ALL, NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE)); - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)), ifindex); + nmp_lookup_init_object_by_ifindex(&lookup, + NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)), + ifindex); head_entry = nm_platform_lookup(self, &lookup); if (!head_entry) return NULL; @@ -5226,23 +5327,26 @@ nm_platform_object_delete(NMPlatform *self, const NMPObject *obj) _CHECK_SELF(self, klass, FALSE); - switch (NMP_OBJECT_GET_TYPE(obj)) { - case NMP_OBJECT_TYPE_ROUTING_RULE: - _LOGD("%s: delete %s", - NMP_OBJECT_GET_CLASS(obj)->obj_type_name, - nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf))); - break; - case NMP_OBJECT_TYPE_IP4_ROUTE: - case NMP_OBJECT_TYPE_IP6_ROUTE: - case NMP_OBJECT_TYPE_QDISC: - case NMP_OBJECT_TYPE_TFILTER: - ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj)->ifindex; - _LOG3D("%s: delete %s", - NMP_OBJECT_GET_CLASS(obj)->obj_type_name, - nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf))); - break; - default: - g_return_val_if_reached(FALSE); + if (_LOGD_ENABLED()) { + switch (NMP_OBJECT_GET_TYPE(obj)) { + case NMP_OBJECT_TYPE_ROUTING_RULE: + case NMP_OBJECT_TYPE_MPTCP_ADDR: + _LOGD("%s: delete %s", + NMP_OBJECT_GET_CLASS(obj)->obj_type_name, + nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf))); + break; + case NMP_OBJECT_TYPE_IP4_ROUTE: + case NMP_OBJECT_TYPE_IP6_ROUTE: + case NMP_OBJECT_TYPE_QDISC: + case NMP_OBJECT_TYPE_TFILTER: + ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj)->ifindex; + _LOG3D("%s: delete %s", + NMP_OBJECT_GET_CLASS(obj)->obj_type_name, + nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf))); + break; + default: + g_return_val_if_reached(FALSE); + } } return klass->object_delete(self, obj); @@ -5971,6 +6075,123 @@ nm_platform_lnk_bridge_to_string(const NMPlatformLnkBridge *lnk, char *buf, gsiz return buf; } +const char * +nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize len) +{ + char sbuf_miimon[30]; + char sbuf_updelay[30]; + char sbuf_downdelay[30]; + char sbuf_peer_notif_delay[60]; + char sbuf_arp_all_targets[30]; + char sbuf_resend_igmp[30]; + char sbuf_lp_interval[30]; + char sbuf_tlb_dynamic_lb[30]; + int i; + + if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len)) + return buf; + + nm_strbuf_append( + &buf, + &len, + "bond" + " mode %u" + " primary %u" + "%s" /* miimon */ + "%s" /* updelay */ + "%s" /* downdelay */ + " arp_interval %u" + "%s" /* resend_igmp */ + " min_links %u" + "%s" /* lp_interval */ + " packets_per_port %u" + "%s" /* peer_notif_delay */ + "%s" /* arp_all_targets */ + " arp_validate %u" + " ad_actor_sys_prio %u" + " ad_user_port_key %u" + " ad_actor_system " NM_ETHER_ADDR_FORMAT_STR "" + " primary_reselect %u" + " fail_over_mac %u" + " xmit_hash_policy %u" + " num_gray_arp %u" + " all_ports_active %u" + " lacp_rate %u" + " ad_select %u" + " use_carrier %d" + "%s" /* tlb_dynamic_lb */, + lnk->mode, + lnk->primary, + lnk->miimon_has || lnk->miimon != 0 + ? nm_sprintf_buf(sbuf_miimon, " miimon%s %u", !lnk->miimon_has ? "?" : "", lnk->miimon) + : "", + lnk->updelay_has || lnk->updelay != 0 ? nm_sprintf_buf(sbuf_updelay, + " updelay%s %u", + !lnk->updelay_has ? "?" : "", + lnk->updelay) + : "", + lnk->downdelay_has || lnk->downdelay != 0 ? nm_sprintf_buf(sbuf_downdelay, + " downdelay%s %u", + !lnk->downdelay_has ? "?" : "", + lnk->downdelay) + : "", + lnk->arp_interval, + lnk->resend_igmp_has || lnk->resend_igmp != 0 + ? nm_sprintf_buf(sbuf_resend_igmp, + " resend_igmp%s %u", + !lnk->resend_igmp_has ? "?" : "", + lnk->resend_igmp) + : "", + lnk->min_links, + lnk->lp_interval_has || lnk->lp_interval != 1 + ? nm_sprintf_buf(sbuf_lp_interval, + " lp_interval%s %u", + !lnk->lp_interval_has ? "?" : "", + lnk->lp_interval) + : "", + lnk->packets_per_port, + lnk->peer_notif_delay_has || lnk->peer_notif_delay != 0 + ? nm_sprintf_buf(sbuf_peer_notif_delay, + " peer_notif_delay%s %u", + !lnk->peer_notif_delay_has ? "?" : "", + lnk->peer_notif_delay) + : "", + lnk->arp_all_targets_has || lnk->arp_all_targets != 0 + ? nm_sprintf_buf(sbuf_arp_all_targets, + " arp_all_targets%s %u", + !lnk->arp_all_targets_has ? "?" : "", + lnk->arp_all_targets) + : "", + lnk->arp_validate, + lnk->ad_actor_sys_prio, + lnk->ad_user_port_key, + NM_ETHER_ADDR_FORMAT_VAL(&lnk->ad_actor_system), + lnk->primary_reselect, + lnk->fail_over_mac, + lnk->xmit_hash_policy, + lnk->num_grat_arp, + lnk->all_ports_active, + lnk->lacp_rate, + lnk->ad_select, + (int) lnk->use_carrier, + lnk->tlb_dynamic_lb_has ? nm_sprintf_buf(sbuf_tlb_dynamic_lb, + " tlb_dynamic_lb%s %u", + !lnk->tlb_dynamic_lb_has ? "?" : "", + (int) lnk->tlb_dynamic_lb) + : ""); + + if (lnk->arp_ip_targets_num > 0) { + nm_strbuf_append_str(&buf, &len, " arp_ip_target"); + for (i = 0; i < lnk->arp_ip_targets_num; i++) { + char target[INET_ADDRSTRLEN]; + + nm_strbuf_append_c(&buf, &len, ' '); + nm_strbuf_append_str(&buf, &len, _nm_utils_inet4_ntop(lnk->arp_ip_target[i], target)); + } + } + return buf; +} + const char * nm_platform_lnk_gre_to_string(const NMPlatformLnkGre *lnk, char *buf, gsize len) { @@ -6580,6 +6801,7 @@ nm_platform_ip4_address_to_string(const NMPlatformIP4Address *address, char *buf " src %s" "%s" /* a_acd_not_ready */ "%s" /* a_force_commit */ + "%s" /* a_no_auto_noprefixroute */ "", s_address, address->plen, @@ -6598,7 +6820,8 @@ nm_platform_ip4_address_to_string(const NMPlatformIP4Address *address, char *buf str_label, nmp_utils_ip_config_source_to_string(address->addr_source, s_source, sizeof(s_source)), address->a_acd_not_ready ? " ip4acd-not-ready" : "", - address->a_force_commit ? " force-commit" : ""); + address->a_force_commit ? " force-commit" : "", + address->a_no_auto_noprefixroute ? " no-auto-noprefixroute" : ""); g_free(str_peer); return buf; } @@ -6719,6 +6942,7 @@ nm_platform_ip6_address_to_string(const NMPlatformIP6Address *address, char *buf len, "%s/%d lft %s pref %s%s%s%s%s src %s" "%s" /* a_force_commit */ + "%s" /* a_no_auto_noprefixroute */ "", s_address, address->plen, @@ -6729,7 +6953,8 @@ nm_platform_ip6_address_to_string(const NMPlatformIP6Address *address, char *buf str_dev, _to_string_ifa_flags(address->n_ifa_flags, s_flags, sizeof(s_flags)), nmp_utils_ip_config_source_to_string(address->addr_source, s_source, sizeof(s_source)), - address->a_force_commit ? " force-commit" : ""); + address->a_force_commit ? " force-commit" : "", + address->a_no_auto_noprefixroute ? " no-auto-noprefixroute" : ""); g_free(str_peer); return buf; } @@ -6787,6 +7012,7 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz char s_gateway[INET_ADDRSTRLEN]; char s_pref_src[INET_ADDRSTRLEN]; char str_dev[TO_STRING_DEV_BUF_SIZE]; + char str_mss[32]; char str_table[30]; char str_scope[30]; char s_source[50]; @@ -6795,6 +7021,7 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz char str_cwnd[32]; char str_initcwnd[32]; char str_initrwnd[32]; + char str_rto_min[32]; char str_mtu[32]; char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN]; char str_type[30]; @@ -6821,18 +7048,20 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz "%s%s" /* gateway */ "%s" " metric %s" - " mss %" G_GUINT32_FORMAT /* mss */ - " rt-src %s" /* protocol */ - "%s" /* rtm_flags */ - "%s%s" /* scope */ - "%s%s" /* pref-src */ - "%s" /* tos */ - "%s" /* window */ - "%s" /* cwnd */ - "%s" /* initcwnd */ - "%s" /* initrwnd */ - "%s" /* mtu */ - "%s" /* r_force_commit */ + "%s" /* mss */ + " rt-src %s" /* protocol */ + "%s" /* rtm_flags */ + "%s%s" /* scope */ + "%s%s" /* pref-src */ + "%s" /* tos */ + "%s" /* window */ + "%s" /* cwnd */ + "%s" /* initcwnd */ + "%s" /* initrwnd */ + "%s" /* rto_min */ + "%s" /* quickack */ + "%s" /* mtu */ + "%s" /* r_force_commit */ "", nm_net_aux_rtnl_rtntype_n2a_maybe_buf(nm_platform_route_type_uncoerce(route->type_coerced), str_type), @@ -6851,7 +7080,10 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz route->metric_any ? (route->metric ? nm_sprintf_buf(str_metric, "??+%u", route->metric) : "??") : nm_sprintf_buf(str_metric, "%u", route->metric), - route->mss, + nm_sprintf_buf(str_mss, + " mss %s%" G_GUINT32_FORMAT, + route->lock_mss ? "lock " : "", + route->mss), nmp_utils_ip_config_source_to_string(route->rt_source, s_source, sizeof(s_source)), _rtm_flags_to_string_full(str_rtm_flags, sizeof(str_rtm_flags), route->r_rtm_flags), route->scope_inv ? " scope " : "", @@ -6885,6 +7117,9 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz route->lock_initrwnd ? "lock " : "", route->initrwnd) : "", + route->rto_min ? nm_sprintf_buf(str_rto_min, " rto_min %" G_GUINT32_FORMAT, route->rto_min) + : "", + route->quickack ? " quickack 1" : "", route->mtu || route->lock_mtu ? nm_sprintf_buf(str_mtu, " mtu %s%" G_GUINT32_FORMAT, route->lock_mtu ? "lock " : "", @@ -6919,11 +7154,13 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz char str_pref[40]; char str_pref2[30]; char str_dev[TO_STRING_DEV_BUF_SIZE]; + char str_mss[32]; char s_source[50]; char str_window[32]; char str_cwnd[32]; char str_initcwnd[32]; char str_initrwnd[32]; + char str_rto_min[32]; char str_mtu[32]; char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN]; char str_metric[30]; @@ -6954,18 +7191,20 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz "%s%s" /* gateway */ "%s" " metric %s" - " mss %" G_GUINT32_FORMAT /* mss */ - " rt-src %s" /* protocol */ - "%s" /* source */ - "%s" /* rtm_flags */ - "%s%s" /* pref-src */ - "%s" /* window */ - "%s" /* cwnd */ - "%s" /* initcwnd */ - "%s" /* initrwnd */ - "%s" /* mtu */ - "%s" /* pref */ - "%s" /* r_force_commit */ + "%s" /* mss */ + " rt-src %s" /* protocol */ + "%s" /* source */ + "%s" /* rtm_flags */ + "%s%s" /* pref-src */ + "%s" /* window */ + "%s" /* cwnd */ + "%s" /* initcwnd */ + "%s" /* initrwnd */ + "%s" /* rto_min */ + "%s" /* quickack */ + "%s" /* mtu */ + "%s" /* pref */ + "%s" /* r_force_commit */ "", nm_net_aux_rtnl_rtntype_n2a_maybe_buf(nm_platform_route_type_uncoerce(route->type_coerced), str_type), @@ -6984,7 +7223,10 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz route->metric_any ? (route->metric ? nm_sprintf_buf(str_metric, "??+%u", route->metric) : "??") : nm_sprintf_buf(str_metric, "%u", route->metric), - route->mss, + nm_sprintf_buf(str_mss, + " mss %s%" G_GUINT32_FORMAT, + route->lock_mss ? "lock " : "", + route->mss), nmp_utils_ip_config_source_to_string(route->rt_source, s_source, sizeof(s_source)), route->src_plen || !IN6_IS_ADDR_UNSPECIFIED(&route->src) ? nm_sprintf_buf(s_src_all, @@ -7017,6 +7259,9 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz route->lock_initrwnd ? "lock " : "", route->initrwnd) : "", + route->rto_min ? nm_sprintf_buf(str_rto_min, " rto_min %" G_GUINT32_FORMAT, route->rto_min) + : "", + route->quickack ? " quickack 1" : "", route->mtu || route->lock_mtu ? nm_sprintf_buf(str_mtu, " mtu %s%" G_GUINT32_FORMAT, route->lock_mtu ? "lock " : "", @@ -7492,6 +7737,107 @@ nm_platform_tfilter_cmp(const NMPlatformTfilter *a, const NMPlatformTfilter *b) return 0; } +static NM_UTILS_FLAGS2STR_DEFINE(_mptcp_flags_to_string, + guint32, + NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_SIGNAL, "signal"), + NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_SUBFLOW, "subflow"), + NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_BACKUP, "backup"), + NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_FULLMESH, "fullmesh")); + +const char * +nm_platform_mptcp_addr_to_string(const NMPlatformMptcpAddr *mptcp_addr, char *buf, gsize len) +{ + char str_addr[30 + NM_UTILS_INET_ADDRSTRLEN]; + char str_port[30]; + char str_id[30]; + char str_flags[200]; + char str_flags2[30 + sizeof(str_flags)]; + char str_ifindex[30]; + + if (!nm_utils_to_string_buffer_init_null(mptcp_addr, &buf, &len)) + return buf; + + if (mptcp_addr->addr_family == 0) + nm_sprintf_buf(str_addr, "no-addr"); + else if (NM_IN_SET(mptcp_addr->addr_family, AF_INET, AF_INET6)) + nm_utils_inet_ntop(mptcp_addr->addr_family, &mptcp_addr->addr, str_addr); + else + nm_sprintf_buf(str_addr, "af %d", mptcp_addr->addr_family); + + if (mptcp_addr->flags != 0) + _mptcp_flags_to_string(mptcp_addr->flags, str_flags, sizeof(str_flags)); + else + str_flags[0] = '\0'; + + g_snprintf(buf, + len, + "%s" /* address */ + "%s" /* port */ + "%s" /* id */ + "%s" /* flags */ + "%s" /* ifindex */ + "", + str_addr, + mptcp_addr->port == 0 ? "" : nm_sprintf_buf(str_port, " port %u", mptcp_addr->port), + mptcp_addr->id == 0 ? "" : nm_sprintf_buf(str_id, " id %u", mptcp_addr->id), + str_flags[0] == '\0' ? "" : nm_sprintf_buf(str_flags2, " flags %s", str_flags), + mptcp_addr->ifindex == 0 + ? "" + : nm_sprintf_buf(str_ifindex, " ifindex %d", mptcp_addr->ifindex)); + return buf; +} + +void +nm_platform_mptcp_addr_hash_update(const NMPlatformMptcpAddr *obj, NMHashState *h) +{ + nm_assert(obj); + nm_assert_addr_family_or_unspec(obj->addr_family); + + nm_hash_update_vals(h, obj->id, obj->flags, obj->port, obj->addr_family, obj->ifindex); + if (NM_IN_SET(obj->addr_family, AF_INET, AF_INET6)) + nm_hash_update(h, &obj->addr, nm_utils_addr_family_to_size(obj->addr_family)); +} + +int +nm_platform_mptcp_addr_cmp(const NMPlatformMptcpAddr *a, const NMPlatformMptcpAddr *b) +{ + NM_CMP_SELF(a, b); + + nm_assert_addr_family_or_unspec(a->addr_family); + nm_assert_addr_family_or_unspec(b->addr_family); + + NM_CMP_FIELD(a, b, ifindex); + NM_CMP_FIELD(a, b, id); + NM_CMP_FIELD(a, b, addr_family); + if (NM_IN_SET(a->addr_family, AF_INET, AF_INET6)) + NM_CMP_FIELD_MEMCMP_LEN(a, b, addr, nm_utils_addr_family_to_size(a->addr_family)); + NM_CMP_FIELD(a, b, port); + + return 0; +} + +guint +nm_platform_mptcp_addr_index_addr_cmp(gconstpointer data) +{ + const NMPlatformMptcpAddr *mptcp_addr = data; + NMHashState h; + + nm_hash_init(&h, 1408914077u); + nm_hash_update_val(&h, mptcp_addr->addr_family); + nm_hash_update(&h, &mptcp_addr->addr, nm_utils_addr_family_to_size(mptcp_addr->addr_family)); + return nm_hash_complete(&h); +} + +gboolean +nm_platform_mptcp_addr_index_addr_equal(gconstpointer data_a, gconstpointer data_b) +{ + const NMPlatformMptcpAddr *mptcp_addr_a = data_a; + const NMPlatformMptcpAddr *mptcp_addr_b = data_b; + + return mptcp_addr_a->addr_family == mptcp_addr_b->addr_family + && nm_ip_addr_equal(mptcp_addr_a->addr_family, &mptcp_addr_a->addr, &mptcp_addr_b->addr); +} + const char * nm_platform_vf_to_string(const NMPlatformVF *vf, char *buf, gsize len) { @@ -7668,6 +8014,95 @@ nm_platform_lnk_bridge_hash_update(const NMPlatformLnkBridge *obj, NMHashState * obj->vlan_stats_enabled)); } +void +nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h) +{ + nm_hash_update_vals(h, + obj->arp_all_targets, + obj->arp_interval, + obj->arp_validate, + obj->downdelay, + obj->lp_interval, + obj->miimon, + obj->min_links, + obj->packets_per_port, + obj->peer_notif_delay, + obj->primary, + obj->resend_igmp, + obj->updelay, + obj->ad_actor_sys_prio, + obj->ad_user_port_key, + obj->ad_actor_system, + obj->ad_select, + obj->all_ports_active, + obj->arp_ip_targets_num, + obj->fail_over_mac, + obj->lacp_rate, + obj->num_grat_arp, + obj->mode, + obj->primary_reselect, + obj->xmit_hash_policy, + NM_HASH_COMBINE_BOOLS(guint16, + obj->arp_all_targets_has, + obj->downdelay_has, + obj->lp_interval_has, + obj->miimon_has, + obj->peer_notif_delay_has, + obj->resend_igmp_has, + obj->tlb_dynamic_lb, + obj->tlb_dynamic_lb_has, + obj->updelay_has, + obj->use_carrier)); + + nm_hash_update(h, obj->arp_ip_target, obj->arp_ip_targets_num * sizeof(obj->arp_ip_target[0])); +} + +int +nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b) +{ + NM_CMP_SELF(a, b); + NM_CMP_FIELD_MEMCMP_LEN(a, + b, + arp_ip_target, + a->arp_ip_targets_num * sizeof(a->arp_ip_target[0])); + NM_CMP_FIELD(a, b, arp_all_targets); + NM_CMP_FIELD(a, b, arp_interval); + NM_CMP_FIELD(a, b, arp_validate); + NM_CMP_FIELD(a, b, downdelay); + NM_CMP_FIELD(a, b, lp_interval); + NM_CMP_FIELD(a, b, miimon); + NM_CMP_FIELD(a, b, min_links); + NM_CMP_FIELD(a, b, packets_per_port); + NM_CMP_FIELD(a, b, peer_notif_delay); + NM_CMP_FIELD(a, b, primary); + NM_CMP_FIELD(a, b, resend_igmp); + NM_CMP_FIELD(a, b, updelay); + NM_CMP_FIELD(a, b, ad_actor_sys_prio); + NM_CMP_FIELD(a, b, ad_user_port_key); + NM_CMP_FIELD_MEMCMP(a, b, ad_actor_system); + NM_CMP_FIELD(a, b, ad_select); + NM_CMP_FIELD(a, b, all_ports_active); + NM_CMP_FIELD(a, b, arp_ip_targets_num); + NM_CMP_FIELD(a, b, fail_over_mac); + NM_CMP_FIELD(a, b, lacp_rate); + NM_CMP_FIELD(a, b, num_grat_arp); + NM_CMP_FIELD(a, b, mode); + NM_CMP_FIELD(a, b, primary_reselect); + NM_CMP_FIELD(a, b, xmit_hash_policy); + NM_CMP_FIELD_BOOL(a, b, arp_all_targets_has); + NM_CMP_FIELD_BOOL(a, b, downdelay_has); + NM_CMP_FIELD_BOOL(a, b, lp_interval_has); + NM_CMP_FIELD_BOOL(a, b, miimon_has); + NM_CMP_FIELD_BOOL(a, b, peer_notif_delay_has); + NM_CMP_FIELD_BOOL(a, b, resend_igmp_has); + NM_CMP_FIELD_BOOL(a, b, tlb_dynamic_lb); + NM_CMP_FIELD_BOOL(a, b, tlb_dynamic_lb_has); + NM_CMP_FIELD_BOOL(a, b, updelay_has); + NM_CMP_FIELD_BOOL(a, b, use_carrier); + + return 0; +} + int nm_platform_lnk_bridge_cmp(const NMPlatformLnkBridge *a, const NMPlatformLnkBridge *b) { @@ -8182,7 +8617,8 @@ nm_platform_ip4_address_hash_update(const NMPlatformIP4Address *obj, NMHashState NM_HASH_COMBINE_BOOLS(guint8, obj->use_ip4_broadcast_address, obj->a_acd_not_ready, - obj->a_force_commit)); + obj->a_force_commit, + obj->a_no_auto_noprefixroute)); nm_hash_update_strarr(h, obj->label); } @@ -8231,6 +8667,7 @@ nm_platform_ip4_address_cmp(const NMPlatformIP4Address *a, NM_CMP_FIELD(a, b, broadcast_address); NM_CMP_FIELD_UNSAFE(a, b, a_acd_not_ready); NM_CMP_FIELD_UNSAFE(a, b, a_force_commit); + NM_CMP_FIELD_UNSAFE(a, b, a_no_auto_noprefixroute); } return 0; } @@ -8240,17 +8677,18 @@ nm_platform_ip4_address_cmp(const NMPlatformIP4Address *a, void nm_platform_ip6_address_hash_update(const NMPlatformIP6Address *obj, NMHashState *h) { - nm_hash_update_vals(h, - obj->ifindex, - obj->addr_source, - obj->timestamp, - obj->lifetime, - obj->preferred, - obj->n_ifa_flags, - obj->plen, - obj->address, - obj->peer_address, - NM_HASH_COMBINE_BOOLS(guint8, obj->a_force_commit)); + nm_hash_update_vals( + h, + obj->ifindex, + obj->addr_source, + obj->timestamp, + obj->lifetime, + obj->preferred, + obj->n_ifa_flags, + obj->plen, + obj->address, + obj->peer_address, + NM_HASH_COMBINE_BOOLS(guint8, obj->a_force_commit, obj->a_no_auto_noprefixroute)); } int @@ -8294,6 +8732,7 @@ nm_platform_ip6_address_cmp(const NMPlatformIP6Address *a, NM_CMP_FIELD(a, b, n_ifa_flags); NM_CMP_FIELD(a, b, addr_source); NM_CMP_FIELD_UNSAFE(a, b, a_force_commit); + NM_CMP_FIELD_UNSAFE(a, b, a_no_auto_noprefixroute); } return 0; } @@ -8337,15 +8776,18 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, obj->initcwnd, obj->initrwnd, obj->mtu, + obj->rto_min, obj->r_rtm_flags & RTNH_F_ONLINK, - NM_HASH_COMBINE_BOOLS(guint8, + NM_HASH_COMBINE_BOOLS(guint16, obj->metric_any, obj->table_any, + obj->quickack, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, obj->lock_initrwnd, - obj->lock_mtu)); + obj->lock_mtu, + obj->lock_mss)); break; case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY: nm_hash_update_vals( @@ -8367,15 +8809,18 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, obj->initcwnd, obj->initrwnd, obj->mtu, + obj->rto_min, obj->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK), - NM_HASH_COMBINE_BOOLS(guint8, + NM_HASH_COMBINE_BOOLS(guint16, obj->metric_any, obj->table_any, + obj->quickack, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, obj->lock_initrwnd, - obj->lock_mtu)); + obj->lock_mtu, + obj->lock_mss)); break; case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL: nm_hash_update_vals(h, @@ -8396,15 +8841,18 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, obj->initcwnd, obj->initrwnd, obj->mtu, + obj->rto_min, obj->r_rtm_flags, - NM_HASH_COMBINE_BOOLS(guint8, + NM_HASH_COMBINE_BOOLS(guint16, obj->metric_any, obj->table_any, + obj->quickack, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, obj->lock_initrwnd, obj->lock_mtu, + obj->lock_mss, obj->r_force_commit)); break; } @@ -8442,12 +8890,15 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a, NM_CMP_FIELD(a, b, initcwnd); NM_CMP_FIELD(a, b, initrwnd); NM_CMP_FIELD(a, b, mtu); + NM_CMP_FIELD(a, b, rto_min); NM_CMP_DIRECT(a->r_rtm_flags & RTNH_F_ONLINK, b->r_rtm_flags & RTNH_F_ONLINK); + NM_CMP_FIELD_UNSAFE(a, b, quickack); NM_CMP_FIELD_UNSAFE(a, b, lock_window); NM_CMP_FIELD_UNSAFE(a, b, lock_cwnd); NM_CMP_FIELD_UNSAFE(a, b, lock_initcwnd); NM_CMP_FIELD_UNSAFE(a, b, lock_initrwnd); NM_CMP_FIELD_UNSAFE(a, b, lock_mtu); + NM_CMP_FIELD_UNSAFE(a, b, lock_mss); } break; case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY: @@ -8485,16 +8936,19 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a, } else NM_CMP_FIELD(a, b, r_rtm_flags); NM_CMP_FIELD(a, b, tos); + NM_CMP_FIELD_UNSAFE(a, b, quickack); NM_CMP_FIELD_UNSAFE(a, b, lock_window); NM_CMP_FIELD_UNSAFE(a, b, lock_cwnd); NM_CMP_FIELD_UNSAFE(a, b, lock_initcwnd); NM_CMP_FIELD_UNSAFE(a, b, lock_initrwnd); NM_CMP_FIELD_UNSAFE(a, b, lock_mtu); + NM_CMP_FIELD_UNSAFE(a, b, lock_mss); NM_CMP_FIELD(a, b, window); NM_CMP_FIELD(a, b, cwnd); NM_CMP_FIELD(a, b, initcwnd); NM_CMP_FIELD(a, b, initrwnd); NM_CMP_FIELD(a, b, mtu); + NM_CMP_FIELD(a, b, rto_min); if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) NM_CMP_FIELD_UNSAFE(a, b, r_force_commit); break; @@ -8552,19 +9006,22 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj, nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source), obj->mss, obj->r_rtm_flags & RTM_F_CLONED, - NM_HASH_COMBINE_BOOLS(guint8, + NM_HASH_COMBINE_BOOLS(guint16, obj->metric_any, obj->table_any, + obj->quickack, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, obj->lock_initrwnd, - obj->lock_mtu), + obj->lock_mtu, + obj->lock_mss), obj->window, obj->cwnd, obj->initcwnd, obj->initrwnd, obj->mtu, + obj->rto_min, _route_pref_normalize(obj->rt_pref)); break; case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL: @@ -8584,17 +9041,20 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj, NM_HASH_COMBINE_BOOLS(guint16, obj->metric_any, obj->table_any, + obj->quickack, obj->lock_window, obj->lock_cwnd, obj->lock_initcwnd, obj->lock_initrwnd, obj->lock_mtu, + obj->lock_mss, obj->r_force_commit), obj->window, obj->cwnd, obj->initcwnd, obj->initrwnd, obj->mtu, + obj->rto_min, obj->rt_pref); break; } @@ -8658,16 +9118,19 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a, NM_CMP_DIRECT(a->r_rtm_flags & RTM_F_CLONED, b->r_rtm_flags & RTM_F_CLONED); } else NM_CMP_FIELD(a, b, r_rtm_flags); + NM_CMP_FIELD_UNSAFE(a, b, quickack); NM_CMP_FIELD_UNSAFE(a, b, lock_window); NM_CMP_FIELD_UNSAFE(a, b, lock_cwnd); NM_CMP_FIELD_UNSAFE(a, b, lock_initcwnd); NM_CMP_FIELD_UNSAFE(a, b, lock_initrwnd); NM_CMP_FIELD_UNSAFE(a, b, lock_mtu); + NM_CMP_FIELD_UNSAFE(a, b, lock_mss); NM_CMP_FIELD(a, b, window); NM_CMP_FIELD(a, b, cwnd); NM_CMP_FIELD(a, b, initcwnd); NM_CMP_FIELD(a, b, initrwnd); NM_CMP_FIELD(a, b, mtu); + NM_CMP_FIELD(a, b, rto_min); if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) NM_CMP_DIRECT(_route_pref_normalize(a->rt_pref), _route_pref_normalize(b->rt_pref)); else @@ -8927,6 +9390,37 @@ nm_platform_ip_address_cmp_expiry(const NMPlatformIPAddress *a, const NMPlatform /*****************************************************************************/ +guint16 +nm_platform_genl_get_family_id(NMPlatform *self, NMPGenlFamilyType family_type) +{ + _CHECK_SELF(self, klass, 0); + + if (!_NM_INT_NOT_NEGATIVE(family_type) || family_type >= _NMP_GENL_FAMILY_TYPE_NUM) + g_return_val_if_reached(0); + + return klass->genl_get_family_id(self, family_type); +} + +/*****************************************************************************/ + +int +nm_platform_mptcp_addr_update(NMPlatform *self, NMOptionBool add, const NMPlatformMptcpAddr *addr) +{ + _CHECK_SELF(self, klass, -NME_BUG); + + return klass->mptcp_addr_update(self, add, addr); +} + +GPtrArray * +nm_platform_mptcp_addrs_dump(NMPlatform *self) +{ + _CHECK_SELF(self, klass, NULL); + + return klass->mptcp_addrs_dump(self); +} + +/*****************************************************************************/ + GHashTable * nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex) { @@ -8939,7 +9433,7 @@ nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex) g_return_val_if_fail(NM_IS_PLATFORM(self), NULL); g_return_val_if_fail(ifindex > 0, NULL); - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex); + nmp_lookup_init_object_by_ifindex(&lookup, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex); head_entry = nmp_cache_lookup(NM_PLATFORM_GET_PRIVATE(self)->cache, &lookup); @@ -8975,8 +9469,6 @@ nm_platform_ip4_address_generate_device_route(const NMPlatformIP4Address *addr, nm_assert(addr); nm_assert(addr->plen <= 32); - if (addr->plen == 0) - return NULL; if (addr->plen == 0) return NULL; @@ -9037,9 +9529,13 @@ log_link(NMPlatform *self, { char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; - _LOG3D("signal: link %7s: %s", - nm_platform_signal_change_type_to_string(change_type), - nm_platform_link_to_string(device, sbuf, sizeof(sbuf))); + if (_LOGD_ENABLED()) { + NMLOG_COMMON(LOGL_DEBUG, + device->name, + "signal: link %7s: %s", + nm_platform_signal_change_type_to_string(change_type), + nm_platform_link_to_string(device, sbuf, sizeof(sbuf))); + } } static void diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 190a91dc..90ffbed0 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -61,6 +61,12 @@ typedef gboolean (*NMPObjectPredicateFunc)(const NMPObject *obj, gpointer user_d #define NM_IFF_MULTI_QUEUE 0x0100 /* IFF_MULTI_QUEUE */ +#define NM_MPTCP_PM_ADDR_FLAG_SIGNAL ((guint32) (1 << 0)) +#define NM_MPTCP_PM_ADDR_FLAG_SUBFLOW ((guint32) (1 << 1)) +#define NM_MPTCP_PM_ADDR_FLAG_BACKUP ((guint32) (1 << 2)) +#define NM_MPTCP_PM_ADDR_FLAG_FULLMESH ((guint32) (1 << 3)) +#define NM_MPTCP_PM_ADDR_FLAG_IMPLICIT ((guint32) (1 << 4)) + /* Redefine this in host's endianness */ #define NM_GRE_KEY 0x2000 @@ -333,6 +339,12 @@ typedef enum { * should be configured. */ \ bool a_force_commit : 1; \ \ + /* nm_platform_ip_address_sync() likes to add IFA_F_NOPREFIXROUTE flag for all + * addresses, regardless of a_ifi_flags property. By setting this boolean, that + * automatism can be suppressed, and the noprefixroute flag does not get added + * automatically. */ \ + bool a_no_auto_noprefixroute : 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. */ \ @@ -453,6 +465,9 @@ typedef union { /* RTA_METRICS.RTAX_INITRWND (iproute2: initrwnd) */ \ guint32 initrwnd; \ \ + /* RTA_METRICS.RTAX_RTO_MIN (iproute2: rto_min) */ \ + guint32 rto_min; \ + \ /* RTA_METRICS.RTAX_MTU (iproute2: mtu) */ \ guint32 mtu; \ \ @@ -499,6 +514,10 @@ typedef union { bool lock_initcwnd : 1; \ bool lock_initrwnd : 1; \ bool lock_mtu : 1; \ + bool lock_mss : 1; \ + \ + /* RTA_METRICS.RTAX_QUICKACK (iproute2: quickack) */ \ + bool quickack : 1; \ \ /* if TRUE, the "metric" field is interpreted as an offset that is added to a default * metric. For example, form a DHCP lease we don't know the actually used metric, because @@ -775,8 +794,6 @@ typedef struct { NMPlatformAction action; } NMPlatformTfilter; -#undef __NMPlatformObjWithIfindex_COMMON - typedef struct { bool is_ip4; NMPObjectType obj_type; @@ -826,10 +843,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 */ @@ -847,41 +864,82 @@ 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; +/* Defined in net/bonding.h. */ +#define NM_BOND_MAX_ARP_TARGETS 16 + typedef struct { + in_addr_t arp_ip_target[NM_BOND_MAX_ARP_TARGETS]; + guint32 arp_all_targets; + guint32 arp_interval; + guint32 arp_validate; + guint32 downdelay; + guint32 lp_interval; + guint32 miimon; + guint32 min_links; + guint32 packets_per_port; + guint32 peer_notif_delay; + guint32 primary; + guint32 resend_igmp; + guint32 updelay; + guint16 ad_actor_sys_prio; + guint16 ad_user_port_key; + NMEtherAddr ad_actor_system; + guint8 ad_select; + guint8 all_ports_active; + guint8 arp_ip_targets_num; + guint8 fail_over_mac; + guint8 lacp_rate; + guint8 num_grat_arp; + guint8 mode; + guint8 primary_reselect; + guint8 xmit_hash_policy; + bool arp_all_targets_has : 1; + bool downdelay_has : 1; + bool lp_interval_has : 1; + bool miimon_has : 1; + bool peer_notif_delay_has : 1; + bool resend_igmp_has : 1; + bool tlb_dynamic_lb : 1; + bool tlb_dynamic_lb_has : 1; + bool updelay_has : 1; + bool use_carrier : 1; +} NMPlatformLnkBond; + +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; @@ -897,12 +955,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; @@ -914,9 +972,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; @@ -945,9 +1003,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; @@ -983,9 +1041,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; @@ -1038,6 +1096,17 @@ typedef enum { typedef void (*NMPlatformAsyncCallback)(GError *error, gpointer user_data); +typedef struct { + __NMPlatformObjWithIfindex_COMMON; + guint32 id; + guint32 flags; + guint16 port; + NMIPAddr addr; + gint8 addr_family; +} NMPlatformMptcpAddr; + +#undef __NMPlatformObjWithIfindex_COMMON + /*****************************************************************************/ typedef struct _NMPlatformCsmeConnInfo { @@ -1096,6 +1165,25 @@ nm_platform_kernel_support_get(NMPlatformKernelSupportType type) return nm_platform_kernel_support_get_full(type, TRUE) != NM_OPTION_BOOL_FALSE; } +typedef enum { + NMP_GENL_FAMILY_TYPE_ETHTOOL, + NMP_GENL_FAMILY_TYPE_MPTCP_PM, + NMP_GENL_FAMILY_TYPE_NL80211, + NMP_GENL_FAMILY_TYPE_NL802154, + NMP_GENL_FAMILY_TYPE_WIREGUARD, + + _NMP_GENL_FAMILY_TYPE_NUM, + _NMP_GENL_FAMILY_TYPE_NONE = _NMP_GENL_FAMILY_TYPE_NUM, +} NMPGenlFamilyType; + +typedef struct { + const char *name; +} NMPGenlFamilyInfo; + +extern const NMPGenlFamilyInfo nmp_genl_family_infos[_NMP_GENL_FAMILY_TYPE_NUM]; + +NMPGenlFamilyType nmp_genl_family_type_from_name(const char *name); + /*****************************************************************************/ struct _NMPlatformPrivate; @@ -1205,6 +1293,7 @@ typedef struct { gboolean egress_reset_all, const NMVlanQosMapping *egress_map, gsize n_egress_map); + gboolean (*link_tun_add)(NMPlatform *self, const char *name, const NMPlatformLnkTun *props, @@ -1302,6 +1391,13 @@ typedef struct { int (*tfilter_add)(NMPlatform *self, NMPNlmFlags flags, const NMPlatformTfilter *tfilter); int (*tfilter_delete)(NMPlatform *self, int ifindex, guint32 parent, gboolean log_error); + + guint16 (*genl_get_family_id)(NMPlatform *platform, NMPGenlFamilyType family_type); + + int (*mptcp_addr_update)(NMPlatform *self, NMOptionBool add, const NMPlatformMptcpAddr *addr); + + GPtrArray *(*mptcp_addrs_dump)(NMPlatform *self); + } NMPlatformClass; /* NMPlatform signals @@ -1489,6 +1585,49 @@ nm_platform_route_type_uncoerce(guint8 type_coerced) return nm_platform_route_type_coerce(type_coerced); } +static inline guint8 +nm_platform_ip4_address_get_scope(in_addr_t addr) +{ + /* For IPv4 addresses, we can set any scope we want (for any address). + * However, there are scopes that make sense based on the address, + * so choose those. */ + return nm_utils_ip4_address_is_loopback(addr) ? (254 /* RT_SCOPE_HOST */) + : nm_utils_ip4_address_is_link_local(addr) ? (253 /* RT_SCOPE_LINK */) + : (0 /* RT_SCOPE_UNIVERSE */); +} + +static inline guint8 +nm_platform_ip6_address_get_scope(const struct in6_addr *addr) +{ + /* For IPv6, kernel does not allow userspace to configure the address scope. + * Instead, it is calculated based on the address. See rt_scope() and + * ipv6_addr_scope(). We do the same here. */ + return IN6_IS_ADDR_LOOPBACK(addr) ? (254 /* RT_SCOPE_HOST */) + : IN6_IS_ADDR_LINKLOCAL(addr) ? (253 /* RT_SCOPE_LINK */) + : IN6_IS_ADDR_SITELOCAL(addr) ? (200 /* RT_SCOPE_SITE */) + : (0 /* RT_SCOPE_UNIVERSE */); +} + +static inline guint8 +nm_platform_ip_address_get_scope(int addr_family, gconstpointer addr) +{ + /* Note that this function returns the scope as we configure + * it in kernel (for IPv4) or as kernel chooses it (for IPv6). + * + * That means, rfc1918 private addresses nm_utils_ip_is_site_local() are + * considered RT_SCOPE_UNIVERSE. + * + * Also, the deprecated IN6_IS_ADDR_SITELOCAL() addresses (fec0::/10) + * are considered RT_SCOPE_SITE, while unique local addresses (ULA, fc00::/7) + * are considered RT_SCOPE_UNIVERSE. + * + * You may not want to use this function when reasoning about + * site-local addresses (RFC1918, ULA). */ + if (NM_IS_IPv4(addr_family)) + return nm_platform_ip4_address_get_scope(*((in_addr_t *) addr)); + return nm_platform_ip6_address_get_scope(addr); +} + gboolean nm_platform_get_use_udev(NMPlatform *self); gboolean nm_platform_get_log_with_ptr(NMPlatform *self); gboolean nm_platform_get_cache_tc(NMPlatform *self); @@ -1657,9 +1796,18 @@ nm_platform_link_bridge_change(NMPlatform *self, int ifindex, const NMPlatformLn } static inline int -nm_platform_link_bond_add(NMPlatform *self, const char *name, const NMPlatformLink **out_link) +nm_platform_link_bond_change(NMPlatform *self, int ifindex, const NMPlatformLnkBond *props) { - return nm_platform_link_add(self, NM_LINK_TYPE_BOND, name, 0, NULL, 0, 0, NULL, out_link); + return nm_platform_link_change(self, NM_LINK_TYPE_BOND, ifindex, props); +} + +static inline int +nm_platform_link_bond_add(NMPlatform *self, + const char *name, + const NMPlatformLnkBond *props, + const NMPlatformLink **out_link) +{ + return nm_platform_link_add(self, NM_LINK_TYPE_BOND, name, 0, NULL, 0, 0, props, out_link); } static inline int @@ -1993,6 +2141,8 @@ const NMPObject *nm_platform_link_get_lnk(NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link); +const NMPlatformLnkBond * +nm_platform_link_get_lnk_bond(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkBridge * nm_platform_link_get_lnk_bridge(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkGre * @@ -2287,6 +2437,7 @@ gboolean nm_platform_tc_sync(NMPlatform *self, GPtrArray *known_tfilters); const char *nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len); +const char *nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize len); const char *nm_platform_lnk_bridge_to_string(const NMPlatformLnkBridge *lnk, char *buf, gsize len); const char *nm_platform_lnk_gre_to_string(const NMPlatformLnkGre *lnk, char *buf, gsize len); const char * @@ -2326,7 +2477,11 @@ const char *nm_platform_vlan_qos_mapping_to_string(const char *name, const char * nm_platform_wireguard_peer_to_string(const struct _NMPWireGuardPeer *peer, char *buf, gsize len); +const char * +nm_platform_mptcp_addr_to_string(const NMPlatformMptcpAddr *mptcp_addr, char *buf, gsize len); + int nm_platform_link_cmp(const NMPlatformLink *a, const NMPlatformLink *b); +int nm_platform_lnk_bond_cmp(const NMPlatformLnkBond *a, const NMPlatformLnkBond *b); int nm_platform_lnk_bridge_cmp(const NMPlatformLnkBridge *a, const NMPlatformLnkBridge *b); int nm_platform_lnk_gre_cmp(const NMPlatformLnkGre *a, const NMPlatformLnkGre *b); int nm_platform_lnk_infiniband_cmp(const NMPlatformLnkInfiniband *a, @@ -2404,6 +2559,8 @@ int nm_platform_qdisc_cmp_full(const NMPlatformQdisc *a, gboolean compare_handle); int nm_platform_tfilter_cmp(const NMPlatformTfilter *a, const NMPlatformTfilter *b); +int nm_platform_mptcp_addr_cmp(const NMPlatformMptcpAddr *a, const NMPlatformMptcpAddr *b); + void nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h); void nm_platform_ip4_address_hash_update(const NMPlatformIP4Address *obj, NMHashState *h); void nm_platform_ip6_address_hash_update(const NMPlatformIP6Address *obj, NMHashState *h); @@ -2416,6 +2573,7 @@ void nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj, void nm_platform_routing_rule_hash_update(const NMPlatformRoutingRule *obj, NMPlatformRoutingRuleCmpType cmp_type, NMHashState *h); +void nm_platform_lnk_bond_hash_update(const NMPlatformLnkBond *obj, NMHashState *h); void nm_platform_lnk_bridge_hash_update(const NMPlatformLnkBridge *obj, NMHashState *h); void nm_platform_lnk_gre_hash_update(const NMPlatformLnkGre *obj, NMHashState *h); void nm_platform_lnk_infiniband_hash_update(const NMPlatformLnkInfiniband *obj, NMHashState *h); @@ -2433,6 +2591,11 @@ void nm_platform_lnk_wireguard_hash_update(const NMPlatformLnkWireGuard *obj, NM void nm_platform_qdisc_hash_update(const NMPlatformQdisc *obj, NMHashState *h); void nm_platform_tfilter_hash_update(const NMPlatformTfilter *obj, NMHashState *h); +void nm_platform_mptcp_addr_hash_update(const NMPlatformMptcpAddr *obj, NMHashState *h); + +guint nm_platform_mptcp_addr_index_addr_cmp(gconstpointer data); +gboolean nm_platform_mptcp_addr_index_addr_equal(gconstpointer data_a, gconstpointer data_b); + #define NM_PLATFORM_LINK_FLAGS2STR_MAX_LEN ((gsize) 162) const char *nm_platform_link_flags2str(unsigned flags, char *buf, gsize len); @@ -2505,4 +2668,13 @@ gboolean nm_platform_ip_address_match(int addr_family, const NMPlatformIPAddress *addr, NMPlatformMatchFlags match_flag); +/*****************************************************************************/ + +guint16 nm_platform_genl_get_family_id(NMPlatform *self, NMPGenlFamilyType family_type); + +int +nm_platform_mptcp_addr_update(NMPlatform *self, NMOptionBool add, const NMPlatformMptcpAddr *addr); + +GPtrArray *nm_platform_mptcp_addrs_dump(NMPlatform *self); + #endif /* __NETWORKMANAGER_PLATFORM_H__ */ diff --git a/src/libnm-platform/nmp-base.h b/src/libnm-platform/nmp-base.h index 48631688..a6ee3df1 100644 --- a/src/libnm-platform/nmp-base.h +++ b/src/libnm-platform/nmp-base.h @@ -147,6 +147,9 @@ typedef enum _nm_packed { NMP_OBJECT_TYPE_LNK_VRF, NMP_OBJECT_TYPE_LNK_VXLAN, NMP_OBJECT_TYPE_LNK_WIREGUARD, + NMP_OBJECT_TYPE_LNK_BOND, + + NMP_OBJECT_TYPE_MPTCP_ADDR, __NMP_OBJECT_TYPE_LAST, NMP_OBJECT_TYPE_MAX = __NMP_OBJECT_TYPE_LAST - 1, diff --git a/src/libnm-platform/nmp-global-tracker.c b/src/libnm-platform/nmp-global-tracker.c new file mode 100644 index 00000000..ea4da284 --- /dev/null +++ b/src/libnm-platform/nmp-global-tracker.c @@ -0,0 +1,1261 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "libnm-glib-aux/nm-default-glib-i18n-lib.h" + +#include "nmp-global-tracker.h" + +#include +#include + +#include "libnm-log-core/nm-logging.h" +#include "libnm-std-aux/c-list-util.h" +#include "nmp-object.h" + +/* This limit comes from kernel, and it limits the number of MPTCP addresses + * we can configure. */ +#define MPTCP_PM_ADDR_MAX 8 + +/*****************************************************************************/ + +/* NMPGlobalTracker tracks certain objects for the entire network namespace and can + * commit them. + * + * We tend to configure things per-interface and per-profile. In many cases, + * we thereby only need to care about the things for that interface. For example, + * we can configure IP addresses and (unicast) routes without having a system wide + * view. That is mainly, because such objects are themselves tied to an ifindex. + * + * However, for certain objects that's not the case. For example, policy routing + * rules, certain route types (blackhole, unavailable, prohibit, throw) and MPTCP + * endpoints require a holistic view of the system. That is, because rules and + * these route types have no ifindex. For MPTCP endpoints, they have an ifindex, + * however we can only configure a small number of them at a time, so we need a + * central (global) instance that can track which endpoints to configure. + * + * In general, the NMPGlobalTracker tracks objects for the entire namespace, and + * it's sync() method will figure out how to configure them. + * + * Since the users of NMPGloablTracker (NML3Cfg, NMDevice) themselves don't + * have this holistic view, the API of NMPGlobalTracker allows them to track + * individual objects independently (they register their objects for a private + * user-tag). If multiple such independent users track the same object, the tracking + * priority (track_priority_val) determines which one wins. + * + * NMPGlobalTracker can not only track whether an object should be present, + * it also can track whether it should be absent. See track_priority_present. + */ + +/*****************************************************************************/ + +struct _NMPGlobalTracker { + NMPlatform *platform; + GHashTable *by_obj; + GHashTable *by_user_tag; + GHashTable *by_data; + CList by_obj_lst_heads[4]; + guint ref_count; +}; + +/*****************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_PLATFORM +#define _NMLOG_PREFIX_NAME "global-tracker" + +#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, LOGD_PLATFORM, _NMLOG_PREFIX_NAME, __VA_ARGS__) + +/*****************************************************************************/ + +static gboolean +NMP_IS_GLOBAL_TRACKER(gpointer self) +{ + return self && ((NMPGlobalTracker *) self)->ref_count > 0 + && NM_IS_PLATFORM(((NMPGlobalTracker *) self)->platform); +} + +/*****************************************************************************/ + +typedef struct { + const NMPObject *obj; + gconstpointer user_tag; + CList obj_lst; + CList user_tag_lst; + + /* @track_priority_val zero is special: those are weakly tracked objects. + * That means: NetworkManager will restore them only if it removed them earlier. + * But it will not remove or add them otherwise. + * + * Otherwise, @track_priority_val goes together with @track_priority_present. + * In case of one object being tracked multiple times (with different priorities), + * the one with higher priority wins. See _track_obj_data_get_best_data(). + * Then, the winning present state either enforces that the rule is present + * or absent. + * + * If an object is not tracked at all, it is ignored by NetworkManager (except + * for MPTCP endpoints for the tracked interface). Assuming that it was added + * externally by the user. But unlike weakly tracked rules, NM will *not* restore + * such rules if NetworkManager themself removed them. */ + guint32 track_priority_val; + bool track_priority_present : 1; + + /* Calling nmp_global_tracker_track() will ensure that the tracked entry is + * non-dirty. Together with nmp_global_tracker_set_dirty() and nmp_global_tracker_untrack_all()'s + * @all parameter, this can be used to remove stale entries. */ + bool dirty : 1; +} TrackData; + +typedef enum { + CONFIG_STATE_NONE = 0, + CONFIG_STATE_ADDED_BY_US = 1, + CONFIG_STATE_REMOVED_BY_US = 2, + + /* ConfigState encodes whether the object was touched by us at all (CONFIG_STATE_NONE). + * + * Maybe we would only need to track whether we touched the object at all. But we + * track it more in detail what we did: did we add it (CONFIG_STATE_ADDED_BY_US) + * or did we remove it (CONFIG_STATE_REMOVED_BY_US)? + * Finally, we need CONFIG_STATE_OWNED_BY_US, which means that we didn't actively + * add/remove it, but whenever we are about to undo the add/remove, we need to do it. + * In that sense, CONFIG_STATE_OWNED_BY_US is really just a flag that we unconditionally + * force the state next time when necessary. */ + CONFIG_STATE_OWNED_BY_US = 3, +} ConfigState; + +typedef struct { + const NMPObject *obj; + CList obj_lst_head; + + CList by_obj_lst; + + /* indicates whether we configured/removed the object (during sync()). We need that, so + * if the object gets untracked, that we know to remove/restore it. + * + * This makes NMPGlobalTracker stateful (beyond the configuration that indicates + * which objects are tracked). + * After a restart, NetworkManager would no longer remember which objects were added + * by us. + * + * That is partially fixed by NetworkManager taking over the objects that it + * actively configures (see %NMP_GLOBAL_TRACKER_EXTERN_WEAKLY_TRACKED_USER_TAG). */ + ConfigState config_state; +} TrackObjData; + +typedef struct { + gconstpointer user_tag; + CList user_tag_lst_head; +} TrackUserTagData; + +/*****************************************************************************/ + +static void _track_data_untrack(NMPGlobalTracker *self, + TrackData *track_data, + gboolean remove_user_tag_data, + gboolean make_owned_by_us); + +/*****************************************************************************/ + +static CList * +_by_obj_lst_head(NMPGlobalTracker *self, NMPObjectType obj_type) +{ + G_STATIC_ASSERT(G_N_ELEMENTS(self->by_obj_lst_heads) == 4); + + switch (obj_type) { + case NMP_OBJECT_TYPE_IP4_ROUTE: + return &self->by_obj_lst_heads[0]; + case NMP_OBJECT_TYPE_IP6_ROUTE: + return &self->by_obj_lst_heads[1]; + case NMP_OBJECT_TYPE_ROUTING_RULE: + return &self->by_obj_lst_heads[2]; + case NMP_OBJECT_TYPE_MPTCP_ADDR: + return &self->by_obj_lst_heads[3]; + default: + return nm_assert_unreachable_val(NULL); + } +} + +/*****************************************************************************/ + +static void +_track_data_assert(const TrackData *track_data, gboolean linked) +{ + nm_assert(track_data); + nm_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(track_data->obj), + NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_ROUTING_RULE, + NMP_OBJECT_TYPE_MPTCP_ADDR)); + nm_assert(nmp_object_is_visible(track_data->obj)); + nm_assert(track_data->user_tag); + nm_assert(!linked || !c_list_is_empty(&track_data->obj_lst)); + nm_assert(!linked || !c_list_is_empty(&track_data->user_tag_lst)); +} + +static guint +_track_data_hash(gconstpointer data) +{ + const TrackData *track_data = data; + NMHashState h; + + _track_data_assert(track_data, FALSE); + + nm_hash_init(&h, 269297543u); + nmp_object_id_hash_update(track_data->obj, &h); + nm_hash_update_val(&h, track_data->user_tag); + return nm_hash_complete(&h); +} + +static gboolean +_track_data_equal(gconstpointer data_a, gconstpointer data_b) +{ + const TrackData *track_data_a = data_a; + const TrackData *track_data_b = data_b; + + _track_data_assert(track_data_a, FALSE); + _track_data_assert(track_data_b, FALSE); + + return track_data_a->user_tag == track_data_b->user_tag + && nmp_object_id_equal(track_data_a->obj, track_data_b->obj); +} + +static void +_track_data_destroy(gpointer data) +{ + TrackData *track_data = data; + + _track_data_assert(track_data, FALSE); + + c_list_unlink_stale(&track_data->obj_lst); + c_list_unlink_stale(&track_data->user_tag_lst); + nmp_object_unref(track_data->obj); + nm_g_slice_free(track_data); +} + +static const TrackData * +_track_obj_data_get_best_data(TrackObjData *obj_data) +{ + TrackData *track_data; + const TrackData *td_best = NULL; + + c_list_for_each_entry (track_data, &obj_data->obj_lst_head, obj_lst) { + _track_data_assert(track_data, TRUE); + + if (td_best) { + if (td_best->track_priority_val > track_data->track_priority_val) + continue; + if (td_best->track_priority_val == track_data->track_priority_val) { + if (td_best->track_priority_present || !track_data->track_priority_present) { + /* if the priorities are identical, then "present" wins over + * "!present" (absent). */ + continue; + } + } + } + + td_best = track_data; + } + + return td_best; +} + +static guint +_track_obj_data_hash(gconstpointer data) +{ + const TrackObjData *obj_data = data; + + return nmp_object_id_hash(obj_data->obj); +} + +static gboolean +_track_obj_data_equal(gconstpointer data_a, gconstpointer data_b) +{ + const TrackObjData *obj_data_a = data_a; + const TrackObjData *obj_data_b = data_b; + + return nmp_object_id_equal(obj_data_a->obj, obj_data_b->obj); +} + +static void +_track_obj_data_destroy(gpointer data) +{ + TrackObjData *obj_data = data; + + c_list_unlink_stale(&obj_data->obj_lst_head); + c_list_unlink_stale(&obj_data->by_obj_lst); + nmp_object_unref(obj_data->obj); + nm_g_slice_free(obj_data); +} + +static void +_track_user_tag_data_destroy(gpointer data) +{ + TrackUserTagData *user_tag_data = data; + + c_list_unlink_stale(&user_tag_data->user_tag_lst_head); + nm_g_slice_free(user_tag_data); +} + +static TrackData * +_track_data_lookup(GHashTable *by_data, const NMPObject *obj, gconstpointer user_tag) +{ + TrackData track_data_needle = { + .obj = obj, + .user_tag = user_tag, + }; + + return g_hash_table_lookup(by_data, &track_data_needle); +} + +/*****************************************************************************/ + +static const NMPObject * +_obj_stackinit(NMPObject *obj_stack, NMPObjectType obj_type, gconstpointer obj) +{ + nmp_object_stackinit(obj_stack, obj_type, obj); + + if (NM_MORE_ASSERTS > 10) { + if (obj_type == NMP_OBJECT_TYPE_MPTCP_ADDR) { + NMPlatformMptcpAddr *m = NMP_OBJECT_CAST_MPTCP_ADDR(obj_stack); + NMPlatformMptcpAddr m_dummy; + + /* Only certain MPTCP addresses can be added. */ + nm_assert(m->ifindex > 0); + if (nm_platform_mptcp_addr_cmp( + nmp_global_tracker_mptcp_addr_init_for_ifindex(&m_dummy, m->ifindex), + m) + == 0) { + /* This is a dummy instance. We are good. */ + } else { + nm_assert_addr_family(m->addr_family); + nm_assert(m->port == 0); + nm_assert(m->id == 0); + } + } + } + + nm_assert(nmp_object_is_visible(obj_stack)); + return obj_stack; +} + +/** + * nmp_global_tracker_track: + * @self: the #NMPGlobalTracker instance + * @obj_type: the NMPObjectType of @obj that we are tracking. + * @obj: the NMPlatformObject (of type NMPObjectType) to track. Usually + * a #NMPlatformRoutingRule, #NMPlatformIP4Route, #NMPlatformIP6Route + * or #NMPlatformMptcpAddr pointer. + * @track_priority: the priority for tracking the rule. Note that + * negative values indicate a forced absence of the rule. Priorities + * are compared with their absolute values (with higher absolute + * value being more important). For example, if you track the same + * rule twice, once with priority -5 and +10, then the rule is + * present (because the positive number is more important). + * The special value 0 indicates weakly-tracked rules. + * @user_tag: the tag associated with tracking this rule. The same tag + * must be used to untrack the rule later. + * @user_tag_untrack: if not %NULL, at the same time untrack this user-tag + * for the same rule. Note that this is different from a plain nmp_global_tracker_untrack_rule(), + * because it enforces ownership of the now tracked rule. On the other hand, + * a plain nmp_global_tracker_untrack_rule() merely forgets about the tracking. + * The purpose here is to set this to %NMP_GLOBAL_TRACKER_EXTERN_WEAKLY_TRACKED_USER_TAG. + * + * Returns: %TRUE, if something changed. + */ +gboolean +nmp_global_tracker_track(NMPGlobalTracker *self, + NMPObjectType obj_type, + gconstpointer obj, + gint32 track_priority, + gconstpointer user_tag, + gconstpointer user_tag_untrack) +{ + NMPObject obj_stack; + const NMPObject *p_obj_stack; + TrackData *track_data; + TrackObjData *obj_data; + TrackUserTagData *user_tag_data; + gboolean changed = FALSE; + gboolean changed_untrack = FALSE; + guint32 track_priority_val; + gboolean track_priority_present; + + g_return_val_if_fail(NMP_IS_GLOBAL_TRACKER(self), FALSE); + g_return_val_if_fail(obj, FALSE); + g_return_val_if_fail(user_tag, FALSE); + + /* The route must not be tied to an interface. We can only handle here + * blackhole/unreachable/prohibit route types. */ + g_return_val_if_fail( + NM_IN_SET(obj_type, NMP_OBJECT_TYPE_ROUTING_RULE, NMP_OBJECT_TYPE_MPTCP_ADDR) + || (NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE) + && ((const NMPlatformIPRoute *) obj)->ifindex == 0), + FALSE); + + /* only positive track priorities are implemented for MPTCP addrs. */ + nm_assert(obj_type != NMP_OBJECT_TYPE_MPTCP_ADDR || track_priority > 0); + + p_obj_stack = _obj_stackinit(&obj_stack, obj_type, obj); + + if (track_priority >= 0) { + track_priority_val = track_priority; + track_priority_present = TRUE; + } else { + track_priority_val = -track_priority; + track_priority_present = FALSE; + } + + track_data = _track_data_lookup(self->by_data, p_obj_stack, user_tag); + + if (!track_data) { + track_data = g_slice_new(TrackData); + *track_data = (TrackData){ + .obj = nm_dedup_multi_index_obj_intern(nm_platform_get_multi_idx(self->platform), + p_obj_stack), + .user_tag = user_tag, + .track_priority_val = track_priority_val, + .track_priority_present = track_priority_present, + .dirty = FALSE, + }; + g_hash_table_add(self->by_data, track_data); + + obj_data = g_hash_table_lookup(self->by_obj, &track_data->obj); + if (!obj_data) { + obj_data = g_slice_new(TrackObjData); + *obj_data = (TrackObjData){ + .obj = nmp_object_ref(track_data->obj), + .obj_lst_head = C_LIST_INIT(obj_data->obj_lst_head), + .config_state = CONFIG_STATE_NONE, + }; + g_hash_table_add(self->by_obj, obj_data); + c_list_link_tail(_by_obj_lst_head(self, obj_type), &obj_data->by_obj_lst); + } + c_list_link_tail(&obj_data->obj_lst_head, &track_data->obj_lst); + + user_tag_data = g_hash_table_lookup(self->by_user_tag, &track_data->user_tag); + if (!user_tag_data) { + user_tag_data = g_slice_new(TrackUserTagData); + *user_tag_data = (TrackUserTagData){ + .user_tag = user_tag, + .user_tag_lst_head = C_LIST_INIT(user_tag_data->user_tag_lst_head), + }; + g_hash_table_add(self->by_user_tag, user_tag_data); + } + c_list_link_tail(&user_tag_data->user_tag_lst_head, &track_data->user_tag_lst); + changed = TRUE; + } else { + track_data->dirty = FALSE; + if (track_data->track_priority_val != track_priority_val + || track_data->track_priority_present != track_priority_present) { + track_data->track_priority_val = track_priority_val; + track_data->track_priority_present = track_priority_present; + changed = TRUE; + } + } + + if (user_tag_untrack) { + if (user_tag != user_tag_untrack) { + TrackData *track_data_untrack; + + track_data_untrack = _track_data_lookup(self->by_data, p_obj_stack, user_tag_untrack); + if (track_data_untrack) { + _track_data_untrack(self, track_data_untrack, FALSE, TRUE); + changed_untrack = TRUE; + } + } else + nm_assert_not_reached(); + } + + _track_data_assert(track_data, TRUE); + + if (changed) { + char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; + + _LOGD( + "track [" NM_HASH_OBFUSCATE_PTR_FMT ",%s%u] %s \"%s\"", + NM_HASH_OBFUSCATE_PTR(track_data->user_tag), + (track_data->track_priority_val == 0 + ? "" + : (track_data->track_priority_present ? "+" : "-")), + (guint) track_data->track_priority_val, + NMP_OBJECT_GET_CLASS(track_data->obj)->obj_type_name, + nmp_object_to_string(track_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf))); + } + + return changed || changed_untrack; +} + +static void +_track_data_untrack(NMPGlobalTracker *self, + TrackData *track_data, + gboolean remove_user_tag_data, + gboolean make_owned_by_us) +{ + char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; + TrackObjData *obj_data; + + nm_assert(NMP_IS_GLOBAL_TRACKER(self)); + _track_data_assert(track_data, TRUE); + nm_assert(self->by_data); + nm_assert(g_hash_table_lookup(self->by_data, track_data) == track_data); + + _LOGD("untrack [" NM_HASH_OBFUSCATE_PTR_FMT "] %s \"%s\"", + NM_HASH_OBFUSCATE_PTR(track_data->user_tag), + NMP_OBJECT_GET_CLASS(track_data->obj)->obj_type_name, + nmp_object_to_string(track_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf))); + +#if NM_MORE_ASSERTS + { + TrackUserTagData *user_tag_data; + + user_tag_data = g_hash_table_lookup(self->by_user_tag, &track_data->user_tag); + nm_assert(user_tag_data); + nm_assert(c_list_contains(&user_tag_data->user_tag_lst_head, &track_data->user_tag_lst)); + } +#endif + + nm_assert(!c_list_is_empty(&track_data->user_tag_lst)); + + obj_data = g_hash_table_lookup(self->by_obj, &track_data->obj); + nm_assert(obj_data); + nm_assert(c_list_contains(&obj_data->obj_lst_head, &track_data->obj_lst)); + nm_assert(obj_data == g_hash_table_lookup(self->by_obj, &track_data->obj)); + + if (make_owned_by_us) { + if (obj_data->config_state == CONFIG_STATE_NONE) { + /* we need to mark this entry that it requires a touch on the next + * sync. */ + obj_data->config_state = CONFIG_STATE_OWNED_BY_US; + } + } else if (remove_user_tag_data && c_list_length_is(&track_data->user_tag_lst, 1)) + g_hash_table_remove(self->by_user_tag, &track_data->user_tag); + + /* if obj_data is marked to be "added_by_us" or "removed_by_us", we need to keep this entry + * around for the next sync -- so that we can undo what we did earlier. */ + if (obj_data->config_state == CONFIG_STATE_NONE && c_list_length_is(&track_data->obj_lst, 1)) + g_hash_table_remove(self->by_obj, &track_data->obj); + + g_hash_table_remove(self->by_data, track_data); +} + +gboolean +nmp_global_tracker_untrack(NMPGlobalTracker *self, + NMPObjectType obj_type, + gconstpointer obj, + gconstpointer user_tag) +{ + NMPObject obj_stack; + const NMPObject *p_obj_stack; + TrackData *track_data; + gboolean changed = FALSE; + + g_return_val_if_fail(NMP_IS_GLOBAL_TRACKER(self), FALSE); + nm_assert(NM_IN_SET(obj_type, + NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_ROUTING_RULE, + NMP_OBJECT_TYPE_MPTCP_ADDR)); + g_return_val_if_fail(obj, FALSE); + g_return_val_if_fail(user_tag, FALSE); + + p_obj_stack = _obj_stackinit(&obj_stack, obj_type, obj); + + track_data = _track_data_lookup(self->by_data, p_obj_stack, user_tag); + if (track_data) { + _track_data_untrack(self, track_data, TRUE, FALSE); + changed = TRUE; + } + + return changed; +} + +void +nmp_global_tracker_set_dirty(NMPGlobalTracker *self, gconstpointer user_tag) +{ + TrackData *track_data; + TrackUserTagData *user_tag_data; + + g_return_if_fail(NMP_IS_GLOBAL_TRACKER(self)); + g_return_if_fail(user_tag); + + user_tag_data = g_hash_table_lookup(self->by_user_tag, &user_tag); + if (!user_tag_data) + return; + + c_list_for_each_entry (track_data, &user_tag_data->user_tag_lst_head, user_tag_lst) + track_data->dirty = TRUE; +} + +gboolean +nmp_global_tracker_untrack_all(NMPGlobalTracker *self, + gconstpointer user_tag, + gboolean all /* or only dirty */, + gboolean make_survivors_dirty) +{ + TrackData *track_data; + TrackData *track_data_safe; + TrackUserTagData *user_tag_data; + gboolean changed = FALSE; + + g_return_val_if_fail(NMP_IS_GLOBAL_TRACKER(self), FALSE); + g_return_val_if_fail(user_tag, FALSE); + + user_tag_data = g_hash_table_lookup(self->by_user_tag, &user_tag); + if (!user_tag_data) + return FALSE; + + c_list_for_each_entry_safe (track_data, + track_data_safe, + &user_tag_data->user_tag_lst_head, + user_tag_lst) { + if (all || track_data->dirty) { + _track_data_untrack(self, track_data, FALSE, FALSE); + changed = TRUE; + continue; + } + if (make_survivors_dirty) + track_data->dirty = TRUE; + } + if (c_list_is_empty(&user_tag_data->user_tag_lst_head)) + g_hash_table_remove(self->by_user_tag, user_tag_data); + + return changed; +} + +/*****************************************************************************/ + +/* Usually, we track NMPlatformMptcpAddr instances with an ifindex set. + * If we have *any* such instance, we know that the ifindex is fully + * synched (meaning, we will delete all unknown endpoints for that interface). + * However, if we don't have an endpoint on the interface, we may still + * want to track that a certain ifindex is fully managed. + * + * This initializes a dummy instance for exactly that purpose. */ +const NMPlatformMptcpAddr * +nmp_global_tracker_mptcp_addr_init_for_ifindex(NMPlatformMptcpAddr *addr, int ifindex) +{ + nm_assert(addr); + nm_assert(ifindex > 0); + + *addr = (NMPlatformMptcpAddr){ + .ifindex = ifindex, + .addr_family = AF_UNSPEC, + }; + + return addr; +} + +/*****************************************************************************/ + +typedef struct { + TrackObjData *obj_data; + const TrackData *td_best; +} MptcpSyncData; + +static int +_mptcp_entries_cmp(gconstpointer a, gconstpointer b, gpointer user_data) +{ + const MptcpSyncData *d_a = a; + const MptcpSyncData *d_b = b; + + /* 1) prefer addresses based on the priority (highest priority + * sorted first). */ + NM_CMP_FIELD(d_b->td_best, d_a->td_best, track_priority_val); + + /* Finally, we only care about the order in which they were tracked. + * Rely on the stable sort to get that right. */ + return 0; +} + +void +nmp_global_tracker_sync_mptcp_addrs(NMPGlobalTracker *self, gboolean reapply) +{ + char sbuf[64 + NM_UTILS_TO_STRING_BUFFER_SIZE]; + gs_unref_ptrarray GPtrArray *kaddrs_arr = NULL; + gs_unref_hashtable GHashTable *kaddrs_idx = NULL; + TrackObjData *obj_data; + TrackObjData *obj_data_safe; + CList *by_obj_lst_head; + const TrackData *td_best; + gs_unref_hashtable GHashTable *handled_ifindexes = NULL; + gs_unref_array GArray *entries = NULL; + gs_unref_hashtable GHashTable *entries_hash_by_addr = NULL; + gs_unref_hashtable GHashTable *entries_to_delete = NULL; + guint i; + guint j; + + g_return_if_fail(NMP_IS_GLOBAL_TRACKER(self)); + + _LOGD("sync mptcp-addr%s", reapply ? " (reapply)" : ""); + + /* Iterate over the tracked objects and construct @handled_ifindexes, @entries + * and @entries_to_delete. + * - @handled_ifindexes is a hash with all managed interfaces (their ifindex). + * - @entries are the MptcpSyncData instances for the tracked objects. + * - @entries_to_delete are the NMPObject which we added earlier, but now not + * anymore (and which we shall delete). */ + by_obj_lst_head = _by_obj_lst_head(self, NMP_OBJECT_TYPE_MPTCP_ADDR); + c_list_for_each_entry_safe (obj_data, obj_data_safe, by_obj_lst_head, by_obj_lst) { + const NMPlatformMptcpAddr *mptcp_addr = NMP_OBJECT_CAST_MPTCP_ADDR(obj_data->obj); + NMPlatformMptcpAddr xtst; + + nm_assert(mptcp_addr->port == 0); + nm_assert(mptcp_addr->ifindex > 0); + nm_assert(mptcp_addr->id == 0); + nm_assert_addr_family_or_unspec(mptcp_addr->addr_family); + + /* AF_UNSPEC means this is the dummy object. We only care about it to make the + * ifindex as managed via @handled_ifindexes. */ + nm_assert( + (mptcp_addr->addr_family == AF_UNSPEC) + == (nm_platform_mptcp_addr_cmp( + mptcp_addr, + nmp_global_tracker_mptcp_addr_init_for_ifindex(&xtst, mptcp_addr->ifindex)) + == 0)); + + /* We need to know which ifindexes are managed/handled by us. Build an index + * for that. */ + if (!handled_ifindexes) + handled_ifindexes = g_hash_table_new(nm_direct_hash, NULL); + g_hash_table_add(handled_ifindexes, GINT_TO_POINTER(mptcp_addr->ifindex)); + + td_best = _track_obj_data_get_best_data(obj_data); + + if (!td_best) { + nm_assert(obj_data->config_state == CONFIG_STATE_ADDED_BY_US); + + /* This entry is a tombstone, that tells us that added the object earlier. + * We can delete the MPTCP address (if it's still configured). + * + * Then we can drop the tombstone. */ + + if (mptcp_addr->addr_family != AF_UNSPEC) { + if (!reapply) { + if (!entries_to_delete) { + entries_to_delete = g_hash_table_new_full((GHashFunc) nmp_object_id_hash, + (GEqualFunc) nmp_object_id_equal, + (GDestroyNotify) nmp_object_unref, + NULL); + } + g_hash_table_add(entries_to_delete, (gpointer) nmp_object_ref(obj_data->obj)); + } + } + + /* We can forget about this entry now. */ + g_hash_table_remove(self->by_obj, obj_data); + continue; + } + + /* negative and zero track priorities are not implemented (and make no sense?). */ + nm_assert(td_best->track_priority_val > 0); + nm_assert(td_best->track_priority_present); + + if (mptcp_addr->addr_family == AF_UNSPEC) { + /* This is a nmp_global_tracker_mptcp_addr_init_for_ifindex() dummy entry. + * It only exists so we can add the @handled_ifindexes entry above + * and handle addresses on this interface. */ + obj_data->config_state = CONFIG_STATE_ADDED_BY_US; + continue; + } + + if (!entries) + entries = g_array_new(FALSE, FALSE, sizeof(MptcpSyncData)); + + g_array_append_val(entries, + ((const MptcpSyncData){ + .obj_data = obj_data, + .td_best = td_best, + })); + } + /* We collected all the entires we want to configure. Now, sort them by + * priority, and drop all the duplicates (preferring the entries that + * appear first, where first means "older"). In kernel, we can only configure an IP + * address (without port) as endpoint once. If two interfaces provide the same IP + * address, we can only configure one. We need to select one and filter out duplicates. + * While there is no solution, the idea is to select the preferred address + * somewhat consistently. + * + * Also, create a lookup index @entries_hash_by_addr to lookup by address. */ + if (entries) { + /* First we sort the entries by priority, to prefer the ones with higher + * priority. In case of equal priority, we rely on the stable sort to + * preserve the order in which things got tracked. */ + g_array_sort_with_data(entries, _mptcp_entries_cmp, NULL); + + entries_hash_by_addr = g_hash_table_new(nm_platform_mptcp_addr_index_addr_cmp, + nm_platform_mptcp_addr_index_addr_equal); + + /* Now, drop all duplicates addresses. Only keep the first one. */ + for (i = 0, j = 0; i < entries->len; i++) { + const MptcpSyncData *d = nm_g_array_index_p(entries, MptcpSyncData, i); + const NMPlatformMptcpAddr *mptcp_addr = NMP_OBJECT_CAST_MPTCP_ADDR(d->obj_data->obj); + + obj_data = g_hash_table_lookup(entries_hash_by_addr, (gpointer) mptcp_addr); + if (obj_data) { + /* This object is shadowed. We ignore it. + * + * However, we first propagate the config_state. For MPTCP addrs, it can only be + * NONE or ADDED_BY_US. */ + nm_assert(NM_IN_SET(d->obj_data->config_state, + CONFIG_STATE_NONE, + CONFIG_STATE_ADDED_BY_US)); + nm_assert( + NM_IN_SET(obj_data->config_state, CONFIG_STATE_NONE, CONFIG_STATE_ADDED_BY_US)); + + if (d->obj_data->config_state == CONFIG_STATE_ADDED_BY_US) { + obj_data->config_state = CONFIG_STATE_ADDED_BY_US; + d->obj_data->config_state = CONFIG_STATE_NONE; + } + continue; + } + + if (!g_hash_table_insert(entries_hash_by_addr, (gpointer) mptcp_addr, d->obj_data)) + nm_assert_not_reached(); + + if (i != j) + *(nm_g_array_index_p(entries, MptcpSyncData, j)) = *d; + j++; + + if (j >= MPTCP_PM_ADDR_MAX) { + /* Kernel limits the number of addresses we can configure. + * It's hard-coded here, taken from current kernel. Hopefully + * it matches the running kernel. + * + * It's worse. There might be other addresses already configured + * on other interfaces (or with a port). Our sync method will leave + * them alone, as they were not added by us. So the actual limit + * is possibly smaller, and kernel fails with EINVAL. + * + * Still, we definitely need to truncate the list here. Imagine + * during an earlier sync we added MAX addresses on one interface. + * Now, another interface activates, and wants to configure one + * address. That address will get a higher priority (chosen by NML3Cfg), + * so that part is good. However, it means we must drop the last from + * the other MAX addresses. We achieve that by truncating the list + * to MPTCP_PM_ADDR_MAX. + */ + break; + } + } + g_array_set_size(entries, j); + } + + /* Get the list of currently (in kernel) configured MPTCP endpoints. */ + kaddrs_arr = nm_platform_mptcp_addrs_dump(self->platform); + + /* First, delete all kaddrs which we no longer want... */ + if (kaddrs_arr) { + for (i = 0; i < kaddrs_arr->len; i++) { + const NMPObject *obj = kaddrs_arr->pdata[i]; + const NMPlatformMptcpAddr *mptcp_addr = NMP_OBJECT_CAST_MPTCP_ADDR(obj); + gboolean add_to_kaddr_idx = FALSE; + + if (mptcp_addr->port != 0 || mptcp_addr->ifindex <= 0) { + /* We ignore all endpoints that have a port or no ifindex. + * Those were never created by us, let the user who created + * them handle them. */ + goto keep_and_next; + } + + if (!nm_g_hash_table_contains(handled_ifindexes, + GINT_TO_POINTER(mptcp_addr->ifindex))) { + /* This endpoint is on an interface we don't manage. Ignore (and keep) it. */ + goto keep_and_next; + } + + /* We have the object in the delete-list. However, we might still also want + * to add it back. Check for that too. */ + obj_data = nm_g_hash_table_lookup(entries_hash_by_addr, mptcp_addr); + if (obj_data) { + const NMPlatformMptcpAddr *mptcp_addr2 = NMP_OBJECT_CAST_MPTCP_ADDR(obj_data->obj); + + if (mptcp_addr->flags == mptcp_addr2->flags + && mptcp_addr->ifindex == mptcp_addr2->ifindex) { + /* We want to add this address and it's already configured. Keep it + * and remember that we already have it. */ + add_to_kaddr_idx = TRUE; + goto keep_and_next; + } + + /* We want to configure a similar address mptcp_addr2) as the one that is already configured + * (mptcp_addr). However, the ifindex or flag differs. Delete this one to add the + * right one blow. */ + } else { + /* We don't want to configure this address (anymore). */ + if (reapply) { + /* in reapply mode, we delete the extra address. */ + } else { + /* Otherwise, we only delete it, if we remember that we added this one + * before. */ + if (!nm_g_hash_table_contains(entries_to_delete, obj)) { + /* This address was not added by us. Keep it. */ + goto keep_and_next; + } + } + } + + if (!nm_platform_object_delete(self->platform, obj)) { + /* We failed to delete it. It's unclear what is the matter with this + * object. Ignore the failure. */ + } + + continue; + +keep_and_next: + _LOGt("keep: %s \"%s\"%s", + NMP_OBJECT_GET_CLASS(obj)->obj_type_name, + nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)), + add_to_kaddr_idx ? " (index)" : ""); + if (add_to_kaddr_idx) { + if (!kaddrs_idx) { + kaddrs_idx = g_hash_table_new((GHashFunc) nmp_object_id_hash, + (GEqualFunc) nmp_object_id_equal); + } + g_hash_table_add(kaddrs_idx, (gpointer) obj); + } + } + } + + if (entries) { + for (i = 0; i < entries->len; i++) { + const MptcpSyncData *d = nm_g_array_index_p(entries, MptcpSyncData, i); + const NMPlatformMptcpAddr *mptcp_addr = NMP_OBJECT_CAST_MPTCP_ADDR(d->obj_data->obj); + const NMPObject *kobj; + + nm_assert(mptcp_addr->port == 0); + nm_assert(mptcp_addr->ifindex > 0); + + d->obj_data->config_state = CONFIG_STATE_ADDED_BY_US; + + kobj = nm_g_hash_table_lookup(kaddrs_idx, d->obj_data->obj); + if (kobj && kobj->mptcp_addr.flags == mptcp_addr->flags) { + /* This address is already added with the right flags. We can + * skip it. */ + continue; + } + + /* Kernel actually only allows us to add a small number of addresses. + * Also, if we have a conflicting address on another interface, the + * request will be rejected. + * + * Don't try to handle that. Just attempt to add the address, and if + * we fail, there is nothing we can do about it. */ + nm_platform_mptcp_addr_update(self->platform, TRUE, mptcp_addr); + } + } +} + +void +nmp_global_tracker_sync(NMPGlobalTracker *self, NMPObjectType obj_type, gboolean keep_deleted) +{ + char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; + const NMDedupMultiHeadEntry *pl_head_entry; + const NMPObject *plobj; + gs_unref_ptrarray GPtrArray *objs_to_delete = NULL; + TrackObjData *obj_data; + TrackObjData *obj_data_safe; + CList *by_obj_lst_head; + guint i; + const TrackData *td_best; + + g_return_if_fail(NMP_IS_GLOBAL_TRACKER(self)); + g_return_if_fail(NM_IN_SET(obj_type, + NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE, + NMP_OBJECT_TYPE_ROUTING_RULE)); + + _LOGD("sync %s%s", + nmp_class_from_type(obj_type)->obj_type_name, + keep_deleted ? " (don't remove any)" : ""); + + if (obj_type == NMP_OBJECT_TYPE_ROUTING_RULE) + pl_head_entry = nm_platform_lookup_obj_type(self->platform, obj_type); + else + pl_head_entry = nm_platform_lookup_object(self->platform, obj_type, 0); + + if (pl_head_entry) { + NMDedupMultiIter pl_iter; + + nmp_cache_iter_for_each (&pl_iter, pl_head_entry, &plobj) { + obj_data = g_hash_table_lookup(self->by_obj, &plobj); + + if (!obj_data) { + /* this obj is not tracked. It was externally added, hence we + * ignore it. */ + continue; + } + + td_best = _track_obj_data_get_best_data(obj_data); + if (td_best) { + if (td_best->track_priority_present) { + if (obj_data->config_state == CONFIG_STATE_OWNED_BY_US) + obj_data->config_state = CONFIG_STATE_ADDED_BY_US; + continue; + } + if (td_best->track_priority_val == 0) { + if (!NM_IN_SET(obj_data->config_state, + CONFIG_STATE_ADDED_BY_US, + CONFIG_STATE_OWNED_BY_US)) { + obj_data->config_state = CONFIG_STATE_NONE; + continue; + } + obj_data->config_state = CONFIG_STATE_NONE; + } + } + + if (keep_deleted) { + _LOGD("forget/leak object added by us: %s \"%s\"", + NMP_OBJECT_GET_CLASS(plobj)->obj_type_name, + nmp_object_to_string(plobj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf))); + continue; + } + + if (!objs_to_delete) + objs_to_delete = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); + + g_ptr_array_add(objs_to_delete, (gpointer) nmp_object_ref(plobj)); + + obj_data->config_state = CONFIG_STATE_REMOVED_BY_US; + } + } + + if (objs_to_delete) { + for (i = 0; i < objs_to_delete->len; i++) + nm_platform_object_delete(self->platform, objs_to_delete->pdata[i]); + } + + by_obj_lst_head = _by_obj_lst_head(self, obj_type); + + c_list_for_each_entry_safe (obj_data, obj_data_safe, by_obj_lst_head, by_obj_lst) { + nm_assert(NMP_OBJECT_GET_TYPE(obj_data->obj) == obj_type); + + td_best = _track_obj_data_get_best_data(obj_data); + + if (!td_best) { + g_hash_table_remove(self->by_obj, obj_data); + continue; + } + + if (!td_best->track_priority_present) { + if (obj_data->config_state == CONFIG_STATE_OWNED_BY_US) + obj_data->config_state = CONFIG_STATE_REMOVED_BY_US; + continue; + } + if (td_best->track_priority_val == 0) { + if (!NM_IN_SET(obj_data->config_state, + CONFIG_STATE_REMOVED_BY_US, + CONFIG_STATE_OWNED_BY_US)) { + obj_data->config_state = CONFIG_STATE_NONE; + continue; + } + obj_data->config_state = CONFIG_STATE_NONE; + } + + plobj = + nm_platform_lookup_obj(self->platform, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj_data->obj); + if (plobj) { + int c; + + switch (obj_type) { + case NMP_OBJECT_TYPE_ROUTING_RULE: + c = nm_platform_routing_rule_cmp(NMP_OBJECT_CAST_ROUTING_RULE(obj_data->obj), + NMP_OBJECT_CAST_ROUTING_RULE(plobj), + NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY); + break; + case NMP_OBJECT_TYPE_IP4_ROUTE: + c = nm_platform_ip4_route_cmp(NMP_OBJECT_CAST_IP4_ROUTE(obj_data->obj), + NMP_OBJECT_CAST_IP4_ROUTE(plobj), + NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY); + break; + case NMP_OBJECT_TYPE_IP6_ROUTE: + c = nm_platform_ip6_route_cmp(NMP_OBJECT_CAST_IP6_ROUTE(obj_data->obj), + NMP_OBJECT_CAST_IP6_ROUTE(plobj), + NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY); + break; + default: + c = nm_assert_unreachable_val(0); + break; + } + if (c == 0) + continue; + nm_platform_object_delete(self->platform, plobj); + } + + obj_data->config_state = CONFIG_STATE_ADDED_BY_US; + + if (obj_type == NMP_OBJECT_TYPE_ROUTING_RULE) { + nm_platform_routing_rule_add(self->platform, + NMP_NLM_FLAG_ADD, + NMP_OBJECT_CAST_ROUTING_RULE(obj_data->obj)); + } else + nm_platform_ip_route_add(self->platform, NMP_NLM_FLAG_APPEND, obj_data->obj); + } +} + +/*****************************************************************************/ + +void +nmp_global_tracker_track_rule_from_platform(NMPGlobalTracker *self, + NMPlatform *platform, + int addr_family, + gint32 tracking_priority, + gconstpointer user_tag) +{ + NMPLookup lookup; + const NMDedupMultiHeadEntry *head_entry; + NMDedupMultiIter iter; + const NMPObject *o; + + g_return_if_fail(NMP_IS_GLOBAL_TRACKER(self)); + + if (!platform) + platform = self->platform; + else + g_return_if_fail(NM_IS_PLATFORM(platform)); + + nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6)); + + nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_ROUTING_RULE); + head_entry = nm_platform_lookup(platform, &lookup); + nmp_cache_iter_for_each (&iter, head_entry, &o) { + const NMPlatformRoutingRule *rr = NMP_OBJECT_CAST_ROUTING_RULE(o); + + if (addr_family != AF_UNSPEC && rr->addr_family != addr_family) + continue; + + nmp_global_tracker_track_rule(self, rr, tracking_priority, user_tag, NULL); + } +} + +/*****************************************************************************/ + +void +nmp_global_tracker_track_rule_default(NMPGlobalTracker *self, + int addr_family, + gint32 track_priority, + gconstpointer user_tag) +{ + g_return_if_fail(NMP_IS_GLOBAL_TRACKER(self)); + + nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6)); + + /* track the default rules. See also `man ip-rule`. */ + + if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET)) { + nmp_global_tracker_track_rule(self, + &((NMPlatformRoutingRule){ + .addr_family = AF_INET, + .priority = 0, + .table = RT_TABLE_LOCAL, + .action = FR_ACT_TO_TBL, + .protocol = RTPROT_KERNEL, + }), + track_priority, + user_tag, + NULL); + nmp_global_tracker_track_rule(self, + &((NMPlatformRoutingRule){ + .addr_family = AF_INET, + .priority = 32766, + .table = RT_TABLE_MAIN, + .action = FR_ACT_TO_TBL, + .protocol = RTPROT_KERNEL, + }), + track_priority, + user_tag, + NULL); + nmp_global_tracker_track_rule(self, + &((NMPlatformRoutingRule){ + .addr_family = AF_INET, + .priority = 32767, + .table = RT_TABLE_DEFAULT, + .action = FR_ACT_TO_TBL, + .protocol = RTPROT_KERNEL, + }), + track_priority, + user_tag, + NULL); + } + if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)) { + nmp_global_tracker_track_rule(self, + &((NMPlatformRoutingRule){ + .addr_family = AF_INET6, + .priority = 0, + .table = RT_TABLE_LOCAL, + .action = FR_ACT_TO_TBL, + .protocol = RTPROT_KERNEL, + }), + track_priority, + user_tag, + NULL); + nmp_global_tracker_track_rule(self, + &((NMPlatformRoutingRule){ + .addr_family = AF_INET6, + .priority = 32766, + .table = RT_TABLE_MAIN, + .action = FR_ACT_TO_TBL, + .protocol = RTPROT_KERNEL, + }), + track_priority, + user_tag, + NULL); + } +} + +/*****************************************************************************/ + +NMPGlobalTracker * +nmp_global_tracker_new(NMPlatform *platform) +{ + NMPGlobalTracker *self; + + g_return_val_if_fail(NM_IS_PLATFORM(platform), NULL); + + G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(TrackUserTagData, user_tag) == 0); + + self = g_slice_new(NMPGlobalTracker); + *self = (NMPGlobalTracker){ + .ref_count = 1, + .platform = g_object_ref(platform), + .by_data = + g_hash_table_new_full(_track_data_hash, _track_data_equal, NULL, _track_data_destroy), + .by_obj = g_hash_table_new_full(_track_obj_data_hash, + _track_obj_data_equal, + NULL, + _track_obj_data_destroy), + .by_user_tag = g_hash_table_new_full(nm_pdirect_hash, + nm_pdirect_equal, + NULL, + _track_user_tag_data_destroy), + .by_obj_lst_heads[0] = C_LIST_INIT(self->by_obj_lst_heads[0]), + .by_obj_lst_heads[1] = C_LIST_INIT(self->by_obj_lst_heads[1]), + .by_obj_lst_heads[2] = C_LIST_INIT(self->by_obj_lst_heads[2]), + .by_obj_lst_heads[3] = C_LIST_INIT(self->by_obj_lst_heads[3]), + }; + return self; +} + +NMPGlobalTracker * +nmp_global_tracker_ref(NMPGlobalTracker *self) +{ + g_return_val_if_fail(NMP_IS_GLOBAL_TRACKER(self), NULL); + + self->ref_count++; + return self; +} + +void +nmp_global_tracker_unref(NMPGlobalTracker *self) +{ + g_return_if_fail(NMP_IS_GLOBAL_TRACKER(self)); + + if (--self->ref_count > 0) + return; + + g_hash_table_destroy(self->by_user_tag); + g_hash_table_destroy(self->by_obj); + g_hash_table_destroy(self->by_data); + nm_assert(c_list_is_empty(&self->by_obj_lst_heads[0])); + nm_assert(c_list_is_empty(&self->by_obj_lst_heads[1])); + nm_assert(c_list_is_empty(&self->by_obj_lst_heads[2])); + nm_assert(c_list_is_empty(&self->by_obj_lst_heads[3])); + g_object_unref(self->platform); + nm_g_slice_free(self); +} diff --git a/src/libnm-platform/nmp-global-tracker.h b/src/libnm-platform/nmp-global-tracker.h new file mode 100644 index 00000000..08a4d85f --- /dev/null +++ b/src/libnm-platform/nmp-global-tracker.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#ifndef __NMP_GLOBAL_TRACKER_H__ +#define __NMP_GLOBAL_TRACKER_H__ + +#include "nm-platform.h" + +/*****************************************************************************/ + +#define NMP_GLOBAL_TRACKER_EXTERN_WEAKLY_TRACKED_USER_TAG ((const void *) nmp_global_tracker_new) + +typedef struct _NMPGlobalTracker NMPGlobalTracker; + +NMPGlobalTracker *nmp_global_tracker_new(NMPlatform *platform); + +NMPGlobalTracker *nmp_global_tracker_ref(NMPGlobalTracker *self); +void nmp_global_tracker_unref(NMPGlobalTracker *self); + +#define nm_auto_unref_global_tracker nm_auto(_nmp_global_tracker_unref) +NM_AUTO_DEFINE_FCN0(NMPGlobalTracker *, _nmp_global_tracker_unref, nmp_global_tracker_unref); + +gboolean nmp_global_tracker_track(NMPGlobalTracker *self, + NMPObjectType obj_type, + gconstpointer obj, + gint32 track_priority, + gconstpointer user_tag, + gconstpointer user_tag_untrack); + +static inline gboolean +nmp_global_tracker_track_rule(NMPGlobalTracker *self, + const NMPlatformRoutingRule *routing_rule, + gint32 track_priority, + gconstpointer user_tag, + gconstpointer user_tag_untrack) +{ + return nmp_global_tracker_track(self, + NMP_OBJECT_TYPE_ROUTING_RULE, + routing_rule, + track_priority, + user_tag, + user_tag_untrack); +} + +void nmp_global_tracker_track_rule_default(NMPGlobalTracker *self, + int addr_family, + gint32 track_priority, + gconstpointer user_tag); + +void nmp_global_tracker_track_rule_from_platform(NMPGlobalTracker *self, + NMPlatform *platform, + int addr_family, + gint32 tracking_priority, + gconstpointer user_tag); + +gboolean nmp_global_tracker_untrack(NMPGlobalTracker *self, + NMPObjectType obj_type, + gconstpointer obj, + gconstpointer user_tag); + +static inline gboolean +nmp_global_tracker_untrack_rule(NMPGlobalTracker *self, + const NMPlatformRoutingRule *routing_rule, + gconstpointer user_tag) +{ + return nmp_global_tracker_untrack(self, NMP_OBJECT_TYPE_ROUTING_RULE, routing_rule, user_tag); +} + +void nmp_global_tracker_set_dirty(NMPGlobalTracker *self, gconstpointer user_tag); + +gboolean nmp_global_tracker_untrack_all(NMPGlobalTracker *self, + gconstpointer user_tag, + gboolean all /* or only dirty */, + gboolean make_survivors_dirty); + +void nmp_global_tracker_sync(NMPGlobalTracker *self, NMPObjectType obj_type, gboolean keep_deleted); + +void nmp_global_tracker_sync_mptcp_addrs(NMPGlobalTracker *self, gboolean reapply); + +/*****************************************************************************/ + +const NMPlatformMptcpAddr *nmp_global_tracker_mptcp_addr_init_for_ifindex(NMPlatformMptcpAddr *addr, + int ifindex); + +#endif /* __NMP_GLOBAL_TRACKER_H__ */ diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c index 6c177b4c..d06aa9cd 100644 --- a/src/libnm-platform/nmp-object.c +++ b/src/libnm-platform/nmp-object.c @@ -20,25 +20,26 @@ /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_PLATFORM -#define _NMLOG(level, obj, ...) \ - G_STMT_START \ - { \ - const NMLogLevel __level = (level); \ - \ - if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \ - const NMPObject *const __obj = (obj); \ - \ - _nm_log(__level, \ - _NMLOG_DOMAIN, \ - 0, \ - NULL, \ - NULL, \ - "nmp-object[%p/%s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - __obj, \ - (__obj ? NMP_OBJECT_GET_CLASS(__obj)->obj_type_name \ - : "???") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ +#define _NMLOG(level, obj, ...) \ + G_STMT_START \ + { \ + const NMLogLevel __level = (level); \ + \ + if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \ + const NMPObject *const __obj = (obj); \ + \ + _nm_log(__level, \ + _NMLOG_DOMAIN, \ + 0, \ + NULL, \ + NULL, \ + "nmp-object[" NM_HASH_OBFUSCATE_PTR_FMT "" \ + "/%s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + NM_HASH_OBFUSCATE_PTR(__obj), \ + (__obj ? NMP_OBJECT_GET_CLASS(__obj)->obj_type_name \ + : "???") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ G_STMT_END /*****************************************************************************/ @@ -380,7 +381,8 @@ _idx_obj_part(const DedupMultiIdxType *idx_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE, NMP_OBJECT_TYPE_QDISC, - NMP_OBJECT_TYPE_TFILTER) + NMP_OBJECT_TYPE_TFILTER, + NMP_OBJECT_TYPE_MPTCP_ADDR) || !nmp_object_is_visible(obj_a)) { if (h) nm_hash_update_val(h, obj_a); @@ -805,13 +807,9 @@ _nmp_object_stackinit_from_class(NMPObject *obj, const NMPClass *klass) nm_assert(obj); nm_assert(klass); - *obj = (NMPObject){ - .parent = - { - .klass = (const NMDedupMultiObjClass *) klass, - ._ref_count = NM_OBJ_REF_COUNT_STACKINIT, - }, - }; + memset(obj, 0, sizeof(NMPObject)); + obj->_class = klass; + obj->parent._ref_count = NM_OBJ_REF_COUNT_STACKINIT; return obj; } @@ -844,6 +842,17 @@ nmp_object_stackinit_id(NMPObject *obj, const NMPObject *src) _nmp_object_stackinit_from_class(obj, klass); if (klass->cmd_plobj_id_copy) klass->cmd_plobj_id_copy(&obj->object, &src->object); + else { + /* This object must not implement cmd_obj_copy(). + * If it would, it would mean that we require a deep copy + * of the data. As @obj is stack-allocated, it cannot track + * ownership. The caller must not use nmp_object_stackinit_id() + * with an object of such a type. */ + nm_assert(!klass->cmd_obj_copy); + + /* plain memcpy of the public part suffices. */ + memcpy(&obj->object, &src->object, klass->sizeof_data); + } return obj; } @@ -904,7 +913,7 @@ nmp_object_to_string(const NMPObject *obj, switch (to_string_mode) { case NMP_OBJECT_TO_STRING_ID: if (!klass->cmd_plobj_to_string_id) { - g_snprintf(buf, buf_size, "%p", obj); + g_snprintf(buf, buf_size, NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(obj)); return buf; } return klass->cmd_plobj_to_string_id(&obj->object, buf, buf_size); @@ -912,9 +921,9 @@ nmp_object_to_string(const NMPObject *obj, g_snprintf( buf, buf_size, - "[%s,%p,%u,%calive,%cvisible; %s]", + "[%s," NM_HASH_OBFUSCATE_PTR_FMT ",%u,%calive,%cvisible; %s]", klass->obj_type_name, - obj, + NM_HASH_OBFUSCATE_PTR(obj), obj->parent._ref_count, nmp_object_is_alive(obj) ? '+' : '-', nmp_object_is_visible(obj) ? '+' : '-', @@ -943,14 +952,15 @@ _vt_cmd_obj_to_string_link(const NMPObject *obj, case NMP_OBJECT_TO_STRING_ALL: nm_strbuf_append(&b, &buf_size, - "[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; ", + "[%s," NM_HASH_OBFUSCATE_PTR_FMT + ",%u,%calive,%cvisible,%cin-nl," NM_HASH_OBFUSCATE_PTR_FMT "; ", klass->obj_type_name, - obj, + NM_HASH_OBFUSCATE_PTR(obj), obj->parent._ref_count, nmp_object_is_alive(obj) ? '+' : '-', nmp_object_is_visible(obj) ? '+' : '-', obj->_link.netlink.is_in_netlink ? '+' : '-', - obj->_link.udev.device); + NM_HASH_OBFUSCATE_PTR(obj->_link.udev.device)); NMP_OBJECT_GET_CLASS(obj)->cmd_plobj_to_string(&obj->object, b, buf_size); nm_strbuf_seek_end(&b, &buf_size); if (obj->_link.netlink.lnk) { @@ -988,15 +998,15 @@ _vt_cmd_obj_to_string_lnk_vlan(const NMPObject *obj, switch (to_string_mode) { case NMP_OBJECT_TO_STRING_ID: - g_snprintf(buf, buf_size, "%p", obj); + g_snprintf(buf, buf_size, NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(obj)); return buf; case NMP_OBJECT_TO_STRING_ALL: g_snprintf(buf, buf_size, - "[%s,%p,%u,%calive,%cvisible; %s]", + "[%s," NM_HASH_OBFUSCATE_PTR_FMT ",%u,%calive,%cvisible; %s]", klass->obj_type_name, - obj, + NM_HASH_OBFUSCATE_PTR(obj), obj->parent._ref_count, nmp_object_is_alive(obj) ? '+' : '-', nmp_object_is_visible(obj) ? '+' : '-', @@ -1052,17 +1062,17 @@ _vt_cmd_obj_to_string_lnk_wireguard(const NMPObject *obj, switch (to_string_mode) { case NMP_OBJECT_TO_STRING_ID: - g_snprintf(buf, buf_size, "%p", obj); + g_snprintf(buf, buf_size, NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(obj)); return buf; case NMP_OBJECT_TO_STRING_ALL: b = buf; nm_strbuf_append(&b, &buf_size, - "[%s,%p,%u,%calive,%cvisible; %s" + "[%s," NM_HASH_OBFUSCATE_PTR_FMT ",%u,%calive,%cvisible; %s" "%s", klass->obj_type_name, - obj, + NM_HASH_OBFUSCATE_PTR(obj), obj->parent._ref_count, nmp_object_is_alive(obj) ? '+' : '-', nmp_object_is_visible(obj) ? '+' : '-', @@ -1153,10 +1163,7 @@ _vt_cmd_obj_hash_update_link(const NMPObject *obj, NMHashState *h) nm_assert(NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_LINK); nm_platform_link_hash_update(&obj->link, h); - nm_hash_update_vals(h, - obj->_link.netlink.is_in_netlink, - obj->_link.wireguard_family_id, - obj->_link.udev.device); + nm_hash_update_vals(h, obj->_link.netlink.is_in_netlink, obj->_link.udev.device); if (obj->_link.netlink.lnk) nmp_object_hash_update(obj->_link.netlink.lnk, h); } @@ -1236,7 +1243,6 @@ _vt_cmd_obj_cmp_link(const NMPObject *obj1, const NMPObject *obj2) NM_CMP_RETURN(nm_platform_link_cmp(&obj1->link, &obj2->link)); NM_CMP_DIRECT(obj1->_link.netlink.is_in_netlink, obj2->_link.netlink.is_in_netlink); NM_CMP_RETURN(nmp_object_cmp(obj1->_link.netlink.lnk, obj2->_link.netlink.lnk)); - NM_CMP_DIRECT(obj1->_link.wireguard_family_id, obj2->_link.wireguard_family_id); if (obj1->_link.udev.device != obj2->_link.udev.device) { if (!obj1->_link.udev.device) @@ -1428,21 +1434,6 @@ _vt_cmd_plobj_id_copy(ip6_address, NMPlatformIP6Address, { dst->address = src->address; }); -_vt_cmd_plobj_id_copy(ip4_route, NMPlatformIP4Route, { - *dst = *src; - nm_assert(nm_platform_ip4_route_cmp(dst, src, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) == 0); -}); - -_vt_cmd_plobj_id_copy(ip6_route, NMPlatformIP6Route, { - *dst = *src; - nm_assert(nm_platform_ip6_route_cmp(dst, src, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) == 0); -}); - -_vt_cmd_plobj_id_copy(routing_rule, NMPlatformRoutingRule, { - *dst = *src; - nm_assert(nm_platform_routing_rule_cmp(dst, src, NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID) == 0); -}); - /* Uses internally nmp_object_copy(), hence it also violates the const * promise for @obj. * */ @@ -1561,6 +1552,37 @@ _vt_cmd_plobj_id_cmp_routing_rule(const NMPlatformObject *obj1, const NMPlatform NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID); } +_vt_cmd_plobj_id_cmp(mptcp_addr, NMPlatformMptcpAddr, { + /* The primary key of an MPTCP endpoint is only the address:port@ifindex. + * + * Which does not fully correspond to kernel's view. Kernel's view is determined + * by the question whether you can add two objects that only differ by one + * attribute. If you can, the attribute is part of the ID otherwise it isn't. + * + * Note that for kernel, the "ifindex" is not part of the identity. + * That is, you cannot two add two endpoints that only differ by + * ifindex. However, for our purpose, it is very useful to make + * the "ifindex" part of the identity. For example, NMPGlobalTracker will use + * this to track MPTCP addresses from independent callers (NML3Cfg). + * It would be bad, if objects that differ by "ifindex" would be + * combined. + * + * The "id" is intentionally not part of the identity for us. Note however, that kernel + * does not allow configuring duplicates "id" -- so the "id" could be a primary key + * as far as kernel is concerned. However, when we track MPTCP endpoints that + * we want to configure, the "id" is left undefined (and we let kernel choose it). + * If the "id" would be part of the NMPObject's ID, we could not lookup + * an object unless we know the "id" -- which we often don't. + */ + NM_CMP_FIELD(obj1, obj2, ifindex); + NM_CMP_FIELD(obj1, obj2, addr_family); + NM_CMP_FIELD_MEMCMP_LEN(obj1, + obj2, + addr, + nm_utils_addr_family_to_size_untrusted(obj1->addr_family)); + NM_CMP_FIELD(obj1, obj2, port); +}); + void nmp_object_id_hash_update(const NMPObject *obj, NMHashState *h) { @@ -1646,6 +1668,12 @@ _vt_cmd_plobj_id_hash_update(tfilter, NMPlatformTfilter, { nm_hash_update_vals(h, obj->ifindex, obj->handle); }); +_vt_cmd_plobj_id_hash_update(mptcp_addr, NMPlatformMptcpAddr, { + /* See the corresponding ID cmp function for details. */ + nm_hash_update_vals(h, obj->addr_family, obj->port, obj->ifindex); + nm_hash_update(h, &obj->addr, nm_utils_addr_family_to_size_untrusted(obj->addr_family)); +}); + static void _vt_cmd_plobj_hash_update_ip4_route(const NMPlatformObject *obj, NMHashState *h) { @@ -1754,6 +1782,12 @@ _vt_cmd_obj_is_alive_tfilter(const NMPObject *obj) return NMP_OBJECT_CAST_TFILTER(obj)->ifindex > 0; } +static gboolean +_vt_cmd_obj_is_alive_mptcp_addr(const NMPObject *obj) +{ + return NM_IN_SET(obj->mptcp_addr.addr_family, AF_INET, AF_INET6, AF_UNSPEC); +} + gboolean nmp_object_is_visible(const NMPObject *obj) { @@ -2099,6 +2133,7 @@ nmp_lookup_init_obj_type(NMPLookup *lookup, NMPObjectType obj_type) case NMP_OBJECT_TYPE_ROUTING_RULE: case NMP_OBJECT_TYPE_QDISC: case NMP_OBJECT_TYPE_TFILTER: + case NMP_OBJECT_TYPE_MPTCP_ADDR: _nmp_object_stackinit_from_type(&lookup->selector_obj, obj_type); lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_TYPE; return _L(lookup); @@ -2122,7 +2157,7 @@ nmp_lookup_init_link_by_ifname(NMPLookup *lookup, const char *ifname) } const NMPLookup * -nmp_lookup_init_object(NMPLookup *lookup, NMPObjectType obj_type, int ifindex) +nmp_lookup_init_object_by_ifindex(NMPLookup *lookup, NMPObjectType obj_type, int ifindex) { NMPObject *o; @@ -2133,19 +2168,11 @@ nmp_lookup_init_object(NMPLookup *lookup, NMPObjectType obj_type, int ifindex) NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE, NMP_OBJECT_TYPE_QDISC, - NMP_OBJECT_TYPE_TFILTER)); - - if (G_UNLIKELY( - (ifindex < 0) - || (ifindex == 0 - && !NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)))) { - /* This function used to have a fallback that meant to lookup all objects, if - * ifindex is non-positive. As routes can have a zero ifindex, that fallback is - * confusing and no longer supported. Only have this code, to catch accidental bugs - * after the API change. */ - nm_assert_not_reached(); - return nmp_lookup_init_obj_type(lookup, obj_type); - } + NMP_OBJECT_TYPE_TFILTER, + NMP_OBJECT_TYPE_MPTCP_ADDR)); + nm_assert(ifindex > 0 + || (ifindex == 0 + && NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE))); o = _nmp_object_stackinit_from_type(&lookup->selector_obj, obj_type); o->obj_with_ifindex.ifindex = ifindex; @@ -3183,7 +3210,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .signal_type = NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, .supported_cache_ids = _supported_cache_ids_ipx_route, .cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route, - .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_route, .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip4_route, .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_ip4_route, .cmd_plobj_to_string_id = (CmdPlobjToStringIdFunc) nm_platform_ip4_route_to_string, @@ -3204,7 +3230,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .signal_type = NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, .supported_cache_ids = _supported_cache_ids_ipx_route, .cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route, - .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_route, .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip6_route, .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_ip6_route, .cmd_plobj_to_string_id = (CmdPlobjToStringIdFunc) nm_platform_ip6_route_to_string, @@ -3224,7 +3249,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .signal_type = NM_PLATFORM_SIGNAL_ROUTING_RULE_CHANGED, .supported_cache_ids = _supported_cache_ids_routing_rules, .cmd_obj_is_alive = _vt_cmd_obj_is_alive_routing_rule, - .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_routing_rule, .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_routing_rule, .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_routing_rule, .cmd_plobj_to_string_id = (CmdPlobjToStringIdFunc) nm_platform_routing_rule_to_string, @@ -3485,4 +3509,32 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_wireguard_hash_update, .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_wireguard_cmp, }, + [NMP_OBJECT_TYPE_LNK_BOND - 1] = + { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_LNK_BOND, + .sizeof_data = sizeof(NMPObjectLnkBond), + .sizeof_public = sizeof(NMPlatformLnkBond), + .obj_type_name = "bond", + .lnk_link_type = NM_LINK_TYPE_BOND, + .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_bond_to_string, + .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_bond_hash_update, + .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_bond_cmp, + }, + [NMP_OBJECT_TYPE_MPTCP_ADDR - 1] = + { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_MPTCP_ADDR, + .sizeof_data = sizeof(NMPObjectMptcpAddr), + .sizeof_public = sizeof(NMPlatformMptcpAddr), + .obj_type_name = "mptcp-addr", + .supported_cache_ids = _supported_cache_ids_object, + .cmd_obj_is_alive = _vt_cmd_obj_is_alive_mptcp_addr, + .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_mptcp_addr, + .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_mptcp_addr, + .cmd_plobj_to_string_id = (CmdPlobjToStringIdFunc) nm_platform_mptcp_addr_to_string, + .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_mptcp_addr_to_string, + .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_mptcp_addr_hash_update, + .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_mptcp_addr_cmp, + }, }; diff --git a/src/libnm-platform/nmp-object.h b/src/libnm-platform/nmp-object.h index d6b88ba2..4958404a 100644 --- a/src/libnm-platform/nmp-object.h +++ b/src/libnm-platform/nmp-object.h @@ -238,17 +238,16 @@ typedef struct { /* Auxiliary data object for Wi-Fi and WPAN */ GObject *ext_data; - - /* FIXME: not every NMPObjectLink should pay the price for tracking - * the wireguard family id. This should be tracked via ext_data, which - * would be exactly the right place. */ - int wireguard_family_id; } NMPObjectLink; typedef struct { NMPlatformLnkBridge _public; } NMPObjectLnkBridge; +typedef struct { + NMPlatformLnkBond _public; +} NMPObjectLnkBond; + typedef struct { NMPlatformLnkGre _public; } NMPObjectLnkGre; @@ -336,6 +335,10 @@ typedef struct { NMPlatformTfilter _public; } NMPObjectTfilter; +typedef struct { + NMPlatformMptcpAddr _public; +} NMPObjectMptcpAddr; + struct _NMPObject { union { NMDedupMultiObj parent; @@ -352,6 +355,9 @@ struct _NMPObject { NMPlatformLnkBridge lnk_bridge; NMPObjectLnkBridge _lnk_bridge; + NMPlatformLnkBond lnk_bond; + NMPObjectLnkBond _lnk_bond; + NMPlatformLnkGre lnk_gre; NMPObjectLnkGre _lnk_gre; @@ -409,6 +415,9 @@ struct _NMPObject { NMPObjectQdisc _qdisc; NMPlatformTfilter tfilter; NMPObjectTfilter _tfilter; + + NMPlatformMptcpAddr mptcp_addr; + NMPObjectMptcpAddr _mptcp_addr; }; }; @@ -493,6 +502,7 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX(NMPObjectType obj_type) case NMP_OBJECT_TYPE_TFILTER: case NMP_OBJECT_TYPE_LNK_BRIDGE: + case NMP_OBJECT_TYPE_LNK_BOND: case NMP_OBJECT_TYPE_LNK_GRE: case NMP_OBJECT_TYPE_LNK_GRETAP: case NMP_OBJECT_TYPE_LNK_INFINIBAND: @@ -509,6 +519,8 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX(NMPObjectType obj_type) case NMP_OBJECT_TYPE_LNK_VRF: case NMP_OBJECT_TYPE_LNK_VXLAN: case NMP_OBJECT_TYPE_LNK_WIREGUARD: + + case NMP_OBJECT_TYPE_MPTCP_ADDR: return TRUE; case NMP_OBJECT_TYPE_ROUTING_RULE: @@ -570,6 +582,8 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX(NMPObjectType obj_type) _NMP_OBJECT_CAST(obj, lnk_wireguard, NMP_OBJECT_TYPE_LNK_WIREGUARD) #define NMP_OBJECT_CAST_LNK_BRIDGE(obj) \ _NMP_OBJECT_CAST(obj, lnk_bridge, NMP_OBJECT_TYPE_LNK_BRIDGE) +#define NMP_OBJECT_CAST_MPTCP_ADDR(obj) \ + _NMP_OBJECT_CAST(obj, mptcp_addr, NMP_OBJECT_TYPE_MPTCP_ADDR) static inline int NMP_OBJECT_TYPE_TO_ADDR_FAMILY(NMPObjectType obj_type) @@ -792,7 +806,8 @@ nmp_cache_lookup(const NMPCache *cache, const NMPLookup *lookup) const NMPLookup *nmp_lookup_init_obj_type(NMPLookup *lookup, NMPObjectType obj_type); const NMPLookup *nmp_lookup_init_link_by_ifname(NMPLookup *lookup, const char *ifname); -const NMPLookup *nmp_lookup_init_object(NMPLookup *lookup, NMPObjectType obj_type, int ifindex); +const NMPLookup * +nmp_lookup_init_object_by_ifindex(NMPLookup *lookup, NMPObjectType obj_type, int ifindex); const NMPLookup *nmp_lookup_init_route_default(NMPLookup *lookup, NMPObjectType obj_type); const NMPLookup *nmp_lookup_init_route_by_weak_id(NMPLookup *lookup, const NMPObject *obj); const NMPLookup *nmp_lookup_init_ip4_route_by_weak_id(NMPLookup *lookup, @@ -1019,7 +1034,7 @@ nm_platform_lookup_object(NMPlatform *platform, NMPObjectType obj_type, int ifin { NMPLookup lookup; - nmp_lookup_init_object(&lookup, obj_type, ifindex); + nmp_lookup_init_object_by_ifindex(&lookup, obj_type, ifindex); return nm_platform_lookup(platform, &lookup); } @@ -1032,7 +1047,7 @@ nm_platform_lookup_object_clone(NMPlatform *platform, { NMPLookup lookup; - nmp_lookup_init_object(&lookup, obj_type, ifindex); + nmp_lookup_init_object_by_ifindex(&lookup, obj_type, ifindex); return nm_platform_lookup_clone(platform, &lookup, predicate, user_data); } diff --git a/src/libnm-platform/nmp-route-manager.c b/src/libnm-platform/nmp-route-manager.c deleted file mode 100644 index 842301b1..00000000 --- a/src/libnm-platform/nmp-route-manager.c +++ /dev/null @@ -1,844 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "libnm-glib-aux/nm-default-glib-i18n-lib.h" - -#include "nmp-route-manager.h" - -#include -#include - -#include "libnm-log-core/nm-logging.h" -#include "libnm-std-aux/c-list-util.h" -#include "nmp-object.h" - -/*****************************************************************************/ - -struct _NMPRouteManager { - NMPlatform *platform; - GHashTable *by_obj; - GHashTable *by_user_tag; - GHashTable *by_data; - CList by_obj_lst_heads[3]; - guint ref_count; -}; - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_PLATFORM -#define _NMLOG_PREFIX_NAME "route-manager" - -#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, LOGD_PLATFORM, _NMLOG_PREFIX_NAME, __VA_ARGS__) - -/*****************************************************************************/ - -static gboolean -NMP_IS_ROUTE_MANAGER(gpointer self) -{ - return self && ((NMPRouteManager *) self)->ref_count > 0 - && NM_IS_PLATFORM(((NMPRouteManager *) self)->platform); -} - -/*****************************************************************************/ - -typedef struct { - const NMPObject *obj; - gconstpointer user_tag; - CList obj_lst; - CList user_tag_lst; - - /* track_priority_val zero is special: those are weakly tracked rules. - * That means: NetworkManager will restore them only if it removed them earlier. - * But it will not remove or add them otherwise. - * - * Otherwise, the track_priority_val goes together with track_priority_present. - * In case of one rule being tracked multiple times (with different priorities), - * the one with higher priority wins. See _track_obj_data_get_best_data(). - * Then, the winning present state either enforces that the rule is present - * or absent. - * - * If a rules is not tracked at all, it is ignored by NetworkManager. Assuming - * that it was added externally by the user. But unlike weakly tracked rules, - * NM will *not* restore such rules if NetworkManager themself removed them. */ - guint32 track_priority_val; - bool track_priority_present : 1; - - bool dirty : 1; -} TrackData; - -typedef enum { - CONFIG_STATE_NONE = 0, - CONFIG_STATE_ADDED_BY_US = 1, - CONFIG_STATE_REMOVED_BY_US = 2, - - /* ConfigState encodes whether the rule was touched by us at all (CONFIG_STATE_NONE). - * - * Maybe we would only need to track whether we touched the rule at all. But we - * track it more in detail what we did: did we add it (CONFIG_STATE_ADDED_BY_US) - * or did we remove it (CONFIG_STATE_REMOVED_BY_US)? - * Finally, we need CONFIG_STATE_OWNED_BY_US, which means that we didn't actively - * add/remove it, but whenever we are about to undo the add/remove, we need to do it. - * In that sense, CONFIG_STATE_OWNED_BY_US is really just a flag that we unconditionally - * force the state next time when necessary. */ - CONFIG_STATE_OWNED_BY_US = 3, -} ConfigState; - -typedef struct { - const NMPObject *obj; - CList obj_lst_head; - - CList by_obj_lst; - - /* indicates whether we configured/removed the rule (during sync()). We need that, so - * if the rule gets untracked, that we know to remove/restore it. - * - * This makes NMPRouteManager stateful (beyond the configuration that indicates - * which rules are tracked). - * After a restart, NetworkManager would no longer remember which rules were added - * by us. - * - * That is partially fixed by NetworkManager taking over the rules that it - * actively configures (see %NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG). */ - ConfigState config_state; -} TrackObjData; - -typedef struct { - gconstpointer user_tag; - CList user_tag_lst_head; -} TrackUserTagData; - -/*****************************************************************************/ - -static void _track_data_untrack(NMPRouteManager *self, - TrackData *track_data, - gboolean remove_user_tag_data, - gboolean make_owned_by_us); - -/*****************************************************************************/ - -static CList * -_by_obj_lst_head(NMPRouteManager *self, NMPObjectType obj_type) -{ - G_STATIC_ASSERT(G_N_ELEMENTS(self->by_obj_lst_heads) == 3); - - switch (obj_type) { - case NMP_OBJECT_TYPE_IP4_ROUTE: - return &self->by_obj_lst_heads[0]; - case NMP_OBJECT_TYPE_IP6_ROUTE: - return &self->by_obj_lst_heads[1]; - case NMP_OBJECT_TYPE_ROUTING_RULE: - return &self->by_obj_lst_heads[2]; - default: - return nm_assert_unreachable_val(NULL); - } -} - -/*****************************************************************************/ - -static void -_track_data_assert(const TrackData *track_data, gboolean linked) -{ - nm_assert(track_data); - nm_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(track_data->obj), - NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE, - NMP_OBJECT_TYPE_ROUTING_RULE)); - nm_assert(nmp_object_is_visible(track_data->obj)); - nm_assert(track_data->user_tag); - nm_assert(!linked || !c_list_is_empty(&track_data->obj_lst)); - nm_assert(!linked || !c_list_is_empty(&track_data->user_tag_lst)); -} - -static guint -_track_data_hash(gconstpointer data) -{ - const TrackData *track_data = data; - NMHashState h; - - _track_data_assert(track_data, FALSE); - - nm_hash_init(&h, 269297543u); - nmp_object_id_hash_update(track_data->obj, &h); - nm_hash_update_val(&h, track_data->user_tag); - return nm_hash_complete(&h); -} - -static gboolean -_track_data_equal(gconstpointer data_a, gconstpointer data_b) -{ - const TrackData *track_data_a = data_a; - const TrackData *track_data_b = data_b; - - _track_data_assert(track_data_a, FALSE); - _track_data_assert(track_data_b, FALSE); - - return track_data_a->user_tag == track_data_b->user_tag - && nmp_object_id_equal(track_data_a->obj, track_data_b->obj); -} - -static void -_track_data_destroy(gpointer data) -{ - TrackData *track_data = data; - - _track_data_assert(track_data, FALSE); - - c_list_unlink_stale(&track_data->obj_lst); - c_list_unlink_stale(&track_data->user_tag_lst); - nmp_object_unref(track_data->obj); - nm_g_slice_free(track_data); -} - -static const TrackData * -_track_obj_data_get_best_data(TrackObjData *obj_data) -{ - TrackData *track_data; - const TrackData *td_best = NULL; - - c_list_for_each_entry (track_data, &obj_data->obj_lst_head, obj_lst) { - _track_data_assert(track_data, TRUE); - - if (td_best) { - if (td_best->track_priority_val > track_data->track_priority_val) - continue; - if (td_best->track_priority_val == track_data->track_priority_val) { - if (td_best->track_priority_present || !track_data->track_priority_present) { - /* if the priorities are identical, then "present" wins over - * "!present" (absent). */ - continue; - } - } - } - - td_best = track_data; - } - - return td_best; -} - -static guint -_track_obj_data_hash(gconstpointer data) -{ - const TrackObjData *obj_data = data; - - return nmp_object_id_hash(obj_data->obj); -} - -static gboolean -_track_obj_data_equal(gconstpointer data_a, gconstpointer data_b) -{ - const TrackObjData *obj_data_a = data_a; - const TrackObjData *obj_data_b = data_b; - - return nmp_object_id_equal(obj_data_a->obj, obj_data_b->obj); -} - -static void -_track_obj_data_destroy(gpointer data) -{ - TrackObjData *obj_data = data; - - c_list_unlink_stale(&obj_data->obj_lst_head); - c_list_unlink_stale(&obj_data->by_obj_lst); - nmp_object_unref(obj_data->obj); - nm_g_slice_free(obj_data); -} - -static void -_track_user_tag_data_destroy(gpointer data) -{ - TrackUserTagData *user_tag_data = data; - - c_list_unlink_stale(&user_tag_data->user_tag_lst_head); - nm_g_slice_free(user_tag_data); -} - -static TrackData * -_track_data_lookup(GHashTable *by_data, const NMPObject *obj, gconstpointer user_tag) -{ - TrackData track_data_needle = { - .obj = obj, - .user_tag = user_tag, - }; - - return g_hash_table_lookup(by_data, &track_data_needle); -} - -/*****************************************************************************/ - -/** - * nmp_route_manager_track: - * @self: the #NMPRouteManager instance - * @obj_type: the NMPObjectType of @obj that we are tracking. - * @obj: the NMPlatformObject (of type NMPObjectType) to track. Usually - * a #NMPlatformRoutingRule, #NMPlatformIP4Route or #NMPlatformIP6Route - * pointer. - * @track_priority: the priority for tracking the rule. Note that - * negative values indicate a forced absence of the rule. Priorities - * are compared with their absolute values (with higher absolute - * value being more important). For example, if you track the same - * rule twice, once with priority -5 and +10, then the rule is - * present (because the positive number is more important). - * The special value 0 indicates weakly-tracked rules. - * @user_tag: the tag associated with tracking this rule. The same tag - * must be used to untrack the rule later. - * @user_tag_untrack: if not %NULL, at the same time untrack this user-tag - * for the same rule. Note that this is different from a plain nmp_route_manager_untrack_rule(), - * because it enforces ownership of the now tracked rule. On the other hand, - * a plain nmp_route_manager_untrack_rule() merely forgets about the tracking. - * The purpose here is to set this to %NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG. - * - * Returns: %TRUE, if something changed. - */ -gboolean -nmp_route_manager_track(NMPRouteManager *self, - NMPObjectType obj_type, - gconstpointer obj, - gint32 track_priority, - gconstpointer user_tag, - gconstpointer user_tag_untrack) -{ - NMPObject obj_stack; - const NMPObject *p_obj_stack; - TrackData *track_data; - TrackObjData *obj_data; - TrackUserTagData *user_tag_data; - gboolean changed = FALSE; - gboolean changed_untrack = FALSE; - guint32 track_priority_val; - gboolean track_priority_present; - - g_return_val_if_fail(NMP_IS_ROUTE_MANAGER(self), FALSE); - g_return_val_if_fail(obj, FALSE); - g_return_val_if_fail(user_tag, FALSE); - - /* The route must not be tied to an interface. We can only handle here - * blackhole/unreachable/prohibit route types. */ - g_return_val_if_fail( - obj_type == NMP_OBJECT_TYPE_ROUTING_RULE - || (NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE) - && ((const NMPlatformIPRoute *) obj)->ifindex == 0), - FALSE); - - nm_assert(track_priority != G_MININT32); - - p_obj_stack = nmp_object_stackinit(&obj_stack, obj_type, obj); - - nm_assert(nmp_object_is_visible(p_obj_stack)); - - if (track_priority >= 0) { - track_priority_val = track_priority; - track_priority_present = TRUE; - } else { - track_priority_val = -track_priority; - track_priority_present = FALSE; - } - - track_data = _track_data_lookup(self->by_data, p_obj_stack, user_tag); - - if (!track_data) { - track_data = g_slice_new(TrackData); - *track_data = (TrackData){ - .obj = nm_dedup_multi_index_obj_intern(nm_platform_get_multi_idx(self->platform), - p_obj_stack), - .user_tag = user_tag, - .track_priority_val = track_priority_val, - .track_priority_present = track_priority_present, - .dirty = FALSE, - }; - g_hash_table_add(self->by_data, track_data); - - obj_data = g_hash_table_lookup(self->by_obj, &track_data->obj); - if (!obj_data) { - obj_data = g_slice_new(TrackObjData); - *obj_data = (TrackObjData){ - .obj = nmp_object_ref(track_data->obj), - .obj_lst_head = C_LIST_INIT(obj_data->obj_lst_head), - .config_state = CONFIG_STATE_NONE, - }; - g_hash_table_add(self->by_obj, obj_data); - c_list_link_tail(_by_obj_lst_head(self, obj_type), &obj_data->by_obj_lst); - } - c_list_link_tail(&obj_data->obj_lst_head, &track_data->obj_lst); - - user_tag_data = g_hash_table_lookup(self->by_user_tag, &track_data->user_tag); - if (!user_tag_data) { - user_tag_data = g_slice_new(TrackUserTagData); - *user_tag_data = (TrackUserTagData){ - .user_tag = user_tag, - .user_tag_lst_head = C_LIST_INIT(user_tag_data->user_tag_lst_head), - }; - g_hash_table_add(self->by_user_tag, user_tag_data); - } - c_list_link_tail(&user_tag_data->user_tag_lst_head, &track_data->user_tag_lst); - changed = TRUE; - } else { - track_data->dirty = FALSE; - if (track_data->track_priority_val != track_priority_val - || track_data->track_priority_present != track_priority_present) { - track_data->track_priority_val = track_priority_val; - track_data->track_priority_present = track_priority_present; - changed = TRUE; - } - } - - if (user_tag_untrack) { - if (user_tag != user_tag_untrack) { - TrackData *track_data_untrack; - - track_data_untrack = _track_data_lookup(self->by_data, p_obj_stack, user_tag_untrack); - if (track_data_untrack) { - _track_data_untrack(self, track_data_untrack, FALSE, TRUE); - changed_untrack = TRUE; - } - } else - nm_assert_not_reached(); - } - - _track_data_assert(track_data, TRUE); - - if (changed) { - char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; - - _LOGD( - "track [" NM_HASH_OBFUSCATE_PTR_FMT ",%s%u] %s \"%s\"", - NM_HASH_OBFUSCATE_PTR(track_data->user_tag), - (track_data->track_priority_val == 0 - ? "" - : (track_data->track_priority_present ? "+" : "-")), - (guint) track_data->track_priority_val, - NMP_OBJECT_GET_CLASS(track_data->obj)->obj_type_name, - nmp_object_to_string(track_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf))); - } - - return changed || changed_untrack; -} - -static void -_track_data_untrack(NMPRouteManager *self, - TrackData *track_data, - gboolean remove_user_tag_data, - gboolean make_owned_by_us) -{ - char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; - TrackObjData *obj_data; - - nm_assert(NMP_IS_ROUTE_MANAGER(self)); - _track_data_assert(track_data, TRUE); - nm_assert(self->by_data); - nm_assert(g_hash_table_lookup(self->by_data, track_data) == track_data); - - _LOGD("untrack [" NM_HASH_OBFUSCATE_PTR_FMT "] %s \"%s\"", - NM_HASH_OBFUSCATE_PTR(track_data->user_tag), - NMP_OBJECT_GET_CLASS(track_data->obj)->obj_type_name, - nmp_object_to_string(track_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf))); - -#if NM_MORE_ASSERTS - { - TrackUserTagData *user_tag_data; - - user_tag_data = g_hash_table_lookup(self->by_user_tag, &track_data->user_tag); - nm_assert(user_tag_data); - nm_assert(c_list_contains(&user_tag_data->user_tag_lst_head, &track_data->user_tag_lst)); - } -#endif - - nm_assert(!c_list_is_empty(&track_data->user_tag_lst)); - - obj_data = g_hash_table_lookup(self->by_obj, &track_data->obj); - nm_assert(obj_data); - nm_assert(c_list_contains(&obj_data->obj_lst_head, &track_data->obj_lst)); - nm_assert(obj_data == g_hash_table_lookup(self->by_obj, &track_data->obj)); - - if (make_owned_by_us) { - if (obj_data->config_state == CONFIG_STATE_NONE) { - /* we need to mark this entry that it requires a touch on the next - * sync. */ - obj_data->config_state = CONFIG_STATE_OWNED_BY_US; - } - } else if (remove_user_tag_data && c_list_length_is(&track_data->user_tag_lst, 1)) - g_hash_table_remove(self->by_user_tag, &track_data->user_tag); - - /* if obj_data is marked to be "added_by_us" or "removed_by_us", we need to keep this entry - * around for the next sync -- so that we can undo what we did earlier. */ - if (obj_data->config_state == CONFIG_STATE_NONE && c_list_length_is(&track_data->obj_lst, 1)) - g_hash_table_remove(self->by_obj, &track_data->obj); - - g_hash_table_remove(self->by_data, track_data); -} - -gboolean -nmp_route_manager_untrack(NMPRouteManager *self, - NMPObjectType obj_type, - gconstpointer obj, - gconstpointer user_tag) -{ - NMPObject obj_stack; - const NMPObject *p_obj_stack; - TrackData *track_data; - gboolean changed = FALSE; - - g_return_val_if_fail(NMP_IS_ROUTE_MANAGER(self), FALSE); - nm_assert(NM_IN_SET(obj_type, - NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE, - NMP_OBJECT_TYPE_ROUTING_RULE)); - g_return_val_if_fail(obj, FALSE); - g_return_val_if_fail(user_tag, FALSE); - - p_obj_stack = nmp_object_stackinit(&obj_stack, obj_type, obj); - - nm_assert(nmp_object_is_visible(p_obj_stack)); - - track_data = _track_data_lookup(self->by_data, p_obj_stack, user_tag); - if (track_data) { - _track_data_untrack(self, track_data, TRUE, FALSE); - changed = TRUE; - } - - return changed; -} - -void -nmp_route_manager_set_dirty(NMPRouteManager *self, gconstpointer user_tag) -{ - TrackData *track_data; - TrackUserTagData *user_tag_data; - - g_return_if_fail(NMP_IS_ROUTE_MANAGER(self)); - g_return_if_fail(user_tag); - - user_tag_data = g_hash_table_lookup(self->by_user_tag, &user_tag); - if (!user_tag_data) - return; - - c_list_for_each_entry (track_data, &user_tag_data->user_tag_lst_head, user_tag_lst) - track_data->dirty = TRUE; -} - -gboolean -nmp_route_manager_untrack_all(NMPRouteManager *self, - gconstpointer user_tag, - gboolean all /* or only dirty */, - gboolean make_survivors_dirty) -{ - TrackData *track_data; - TrackData *track_data_safe; - TrackUserTagData *user_tag_data; - gboolean changed = FALSE; - - g_return_val_if_fail(NMP_IS_ROUTE_MANAGER(self), FALSE); - g_return_val_if_fail(user_tag, FALSE); - - user_tag_data = g_hash_table_lookup(self->by_user_tag, &user_tag); - if (!user_tag_data) - return FALSE; - - c_list_for_each_entry_safe (track_data, - track_data_safe, - &user_tag_data->user_tag_lst_head, - user_tag_lst) { - if (all || track_data->dirty) { - _track_data_untrack(self, track_data, FALSE, FALSE); - changed = TRUE; - continue; - } - if (make_survivors_dirty) - track_data->dirty = TRUE; - } - if (c_list_is_empty(&user_tag_data->user_tag_lst_head)) - g_hash_table_remove(self->by_user_tag, user_tag_data); - - return changed; -} - -/*****************************************************************************/ - -void -nmp_route_manager_sync(NMPRouteManager *self, NMPObjectType obj_type, gboolean keep_deleted) -{ - char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; - const NMDedupMultiHeadEntry *pl_head_entry; - NMDedupMultiIter pl_iter; - const NMPObject *plobj; - gs_unref_ptrarray GPtrArray *objs_to_delete = NULL; - TrackObjData *obj_data; - TrackObjData *obj_data_safe; - CList *by_obj_lst_head; - guint i; - const TrackData *td_best; - - g_return_if_fail(NMP_IS_ROUTE_MANAGER(self)); - g_return_if_fail(NM_IN_SET(obj_type, - NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE, - NMP_OBJECT_TYPE_ROUTING_RULE)); - - _LOGD("sync %s%s", - nmp_class_from_type(obj_type)->obj_type_name, - keep_deleted ? " (don't remove any)" : ""); - - if (obj_type == NMP_OBJECT_TYPE_ROUTING_RULE) - pl_head_entry = nm_platform_lookup_obj_type(self->platform, obj_type); - else - pl_head_entry = nm_platform_lookup_object(self->platform, obj_type, 0); - - if (pl_head_entry) { - nmp_cache_iter_for_each (&pl_iter, pl_head_entry, &plobj) { - obj_data = g_hash_table_lookup(self->by_obj, &plobj); - - if (!obj_data) { - /* this obj is not tracked. It was externally added, hence we - * ignore it. */ - continue; - } - - td_best = _track_obj_data_get_best_data(obj_data); - if (td_best) { - if (td_best->track_priority_present) { - if (obj_data->config_state == CONFIG_STATE_OWNED_BY_US) - obj_data->config_state = CONFIG_STATE_ADDED_BY_US; - continue; - } - if (td_best->track_priority_val == 0) { - if (!NM_IN_SET(obj_data->config_state, - CONFIG_STATE_ADDED_BY_US, - CONFIG_STATE_OWNED_BY_US)) { - obj_data->config_state = CONFIG_STATE_NONE; - continue; - } - obj_data->config_state = CONFIG_STATE_NONE; - } - } - - if (keep_deleted) { - _LOGD("forget/leak object added by us: %s \"%s\"", - NMP_OBJECT_GET_CLASS(plobj)->obj_type_name, - nmp_object_to_string(plobj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf))); - continue; - } - - if (!objs_to_delete) - objs_to_delete = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); - - g_ptr_array_add(objs_to_delete, (gpointer) nmp_object_ref(plobj)); - - obj_data->config_state = CONFIG_STATE_REMOVED_BY_US; - } - } - - if (objs_to_delete) { - for (i = 0; i < objs_to_delete->len; i++) - nm_platform_object_delete(self->platform, objs_to_delete->pdata[i]); - } - - by_obj_lst_head = _by_obj_lst_head(self, obj_type); - - c_list_for_each_entry_safe (obj_data, obj_data_safe, by_obj_lst_head, by_obj_lst) { - nm_assert(NMP_OBJECT_GET_TYPE(obj_data->obj) == obj_type); - - td_best = _track_obj_data_get_best_data(obj_data); - - if (!td_best) { - g_hash_table_remove(self->by_obj, obj_data); - continue; - } - - if (!td_best->track_priority_present) { - if (obj_data->config_state == CONFIG_STATE_OWNED_BY_US) - obj_data->config_state = CONFIG_STATE_REMOVED_BY_US; - continue; - } - if (td_best->track_priority_val == 0) { - if (!NM_IN_SET(obj_data->config_state, - CONFIG_STATE_REMOVED_BY_US, - CONFIG_STATE_OWNED_BY_US)) { - obj_data->config_state = CONFIG_STATE_NONE; - continue; - } - obj_data->config_state = CONFIG_STATE_NONE; - } - - plobj = - nm_platform_lookup_obj(self->platform, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj_data->obj); - if (plobj) - continue; - - obj_data->config_state = CONFIG_STATE_ADDED_BY_US; - - if (obj_type == NMP_OBJECT_TYPE_ROUTING_RULE) { - nm_platform_routing_rule_add(self->platform, - NMP_NLM_FLAG_ADD, - NMP_OBJECT_CAST_ROUTING_RULE(obj_data->obj)); - } else - nm_platform_ip_route_add(self->platform, NMP_NLM_FLAG_APPEND, obj_data->obj); - } -} - -/*****************************************************************************/ - -void -nmp_route_manager_track_rule_from_platform(NMPRouteManager *self, - NMPlatform *platform, - int addr_family, - gint32 tracking_priority, - gconstpointer user_tag) -{ - NMPLookup lookup; - const NMDedupMultiHeadEntry *head_entry; - NMDedupMultiIter iter; - const NMPObject *o; - - g_return_if_fail(NMP_IS_ROUTE_MANAGER(self)); - - if (!platform) - platform = self->platform; - else - g_return_if_fail(NM_IS_PLATFORM(platform)); - - nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6)); - - nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_ROUTING_RULE); - head_entry = nm_platform_lookup(platform, &lookup); - nmp_cache_iter_for_each (&iter, head_entry, &o) { - const NMPlatformRoutingRule *rr = NMP_OBJECT_CAST_ROUTING_RULE(o); - - if (addr_family != AF_UNSPEC && rr->addr_family != addr_family) - continue; - - nmp_route_manager_track_rule(self, rr, tracking_priority, user_tag, NULL); - } -} - -/*****************************************************************************/ - -void -nmp_route_manager_track_rule_default(NMPRouteManager *self, - int addr_family, - gint32 track_priority, - gconstpointer user_tag) -{ - g_return_if_fail(NMP_IS_ROUTE_MANAGER(self)); - - nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6)); - - /* track the default rules. See also `man ip-rule`. */ - - if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET)) { - nmp_route_manager_track_rule(self, - &((NMPlatformRoutingRule){ - .addr_family = AF_INET, - .priority = 0, - .table = RT_TABLE_LOCAL, - .action = FR_ACT_TO_TBL, - .protocol = RTPROT_KERNEL, - }), - track_priority, - user_tag, - NULL); - nmp_route_manager_track_rule(self, - &((NMPlatformRoutingRule){ - .addr_family = AF_INET, - .priority = 32766, - .table = RT_TABLE_MAIN, - .action = FR_ACT_TO_TBL, - .protocol = RTPROT_KERNEL, - }), - track_priority, - user_tag, - NULL); - nmp_route_manager_track_rule(self, - &((NMPlatformRoutingRule){ - .addr_family = AF_INET, - .priority = 32767, - .table = RT_TABLE_DEFAULT, - .action = FR_ACT_TO_TBL, - .protocol = RTPROT_KERNEL, - }), - track_priority, - user_tag, - NULL); - } - if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)) { - nmp_route_manager_track_rule(self, - &((NMPlatformRoutingRule){ - .addr_family = AF_INET6, - .priority = 0, - .table = RT_TABLE_LOCAL, - .action = FR_ACT_TO_TBL, - .protocol = RTPROT_KERNEL, - }), - track_priority, - user_tag, - NULL); - nmp_route_manager_track_rule(self, - &((NMPlatformRoutingRule){ - .addr_family = AF_INET6, - .priority = 32766, - .table = RT_TABLE_MAIN, - .action = FR_ACT_TO_TBL, - .protocol = RTPROT_KERNEL, - }), - track_priority, - user_tag, - NULL); - } -} - -/*****************************************************************************/ - -NMPRouteManager * -nmp_route_manager_new(NMPlatform *platform) -{ - NMPRouteManager *self; - - g_return_val_if_fail(NM_IS_PLATFORM(platform), NULL); - - G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(TrackUserTagData, user_tag) == 0); - - self = g_slice_new(NMPRouteManager); - *self = (NMPRouteManager){ - .ref_count = 1, - .platform = g_object_ref(platform), - .by_data = - g_hash_table_new_full(_track_data_hash, _track_data_equal, NULL, _track_data_destroy), - .by_obj = g_hash_table_new_full(_track_obj_data_hash, - _track_obj_data_equal, - NULL, - _track_obj_data_destroy), - .by_user_tag = g_hash_table_new_full(nm_pdirect_hash, - nm_pdirect_equal, - NULL, - _track_user_tag_data_destroy), - .by_obj_lst_heads[0] = C_LIST_INIT(self->by_obj_lst_heads[0]), - .by_obj_lst_heads[1] = C_LIST_INIT(self->by_obj_lst_heads[1]), - .by_obj_lst_heads[2] = C_LIST_INIT(self->by_obj_lst_heads[2]), - }; - return self; -} - -NMPRouteManager * -nmp_route_manager_ref(NMPRouteManager *self) -{ - g_return_val_if_fail(NMP_IS_ROUTE_MANAGER(self), NULL); - - self->ref_count++; - return self; -} - -void -nmp_route_manager_unref(NMPRouteManager *self) -{ - g_return_if_fail(NMP_IS_ROUTE_MANAGER(self)); - - if (--self->ref_count > 0) - return; - - g_hash_table_destroy(self->by_user_tag); - g_hash_table_destroy(self->by_obj); - g_hash_table_destroy(self->by_data); - nm_assert(c_list_is_empty(&self->by_obj_lst_heads[0])); - nm_assert(c_list_is_empty(&self->by_obj_lst_heads[1])); - nm_assert(c_list_is_empty(&self->by_obj_lst_heads[2])); - g_object_unref(self->platform); - nm_g_slice_free(self); -} diff --git a/src/libnm-platform/nmp-route-manager.h b/src/libnm-platform/nmp-route-manager.h deleted file mode 100644 index 97ec3840..00000000 --- a/src/libnm-platform/nmp-route-manager.h +++ /dev/null @@ -1,79 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#ifndef __NMP_ROUTE_MANAGER_H__ -#define __NMP_ROUTE_MANAGER_H__ - -#include "nm-platform.h" - -/*****************************************************************************/ - -#define NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG ((const void *) nmp_route_manager_new) - -typedef struct _NMPRouteManager NMPRouteManager; - -NMPRouteManager *nmp_route_manager_new(NMPlatform *platform); - -NMPRouteManager *nmp_route_manager_ref(NMPRouteManager *self); -void nmp_route_manager_unref(NMPRouteManager *self); - -#define nm_auto_unref_route_manager nm_auto(_nmp_route_manager_unref) -NM_AUTO_DEFINE_FCN0(NMPRouteManager *, _nmp_route_manager_unref, nmp_route_manager_unref); - -gboolean nmp_route_manager_track(NMPRouteManager *self, - NMPObjectType obj_type, - gconstpointer obj, - gint32 track_priority, - gconstpointer user_tag, - gconstpointer user_tag_untrack); - -static inline gboolean -nmp_route_manager_track_rule(NMPRouteManager *self, - const NMPlatformRoutingRule *routing_rule, - gint32 track_priority, - gconstpointer user_tag, - gconstpointer user_tag_untrack) -{ - return nmp_route_manager_track(self, - NMP_OBJECT_TYPE_ROUTING_RULE, - routing_rule, - track_priority, - user_tag, - user_tag_untrack); -} - -void nmp_route_manager_track_rule_default(NMPRouteManager *self, - int addr_family, - gint32 track_priority, - gconstpointer user_tag); - -void nmp_route_manager_track_rule_from_platform(NMPRouteManager *self, - NMPlatform *platform, - int addr_family, - gint32 tracking_priority, - gconstpointer user_tag); - -gboolean nmp_route_manager_untrack(NMPRouteManager *self, - NMPObjectType obj_type, - gconstpointer obj, - gconstpointer user_tag); - -static inline gboolean -nmp_route_manager_untrack_rule(NMPRouteManager *self, - const NMPlatformRoutingRule *routing_rule, - gconstpointer user_tag) -{ - return nmp_route_manager_untrack(self, NMP_OBJECT_TYPE_ROUTING_RULE, routing_rule, user_tag); -} - -void nmp_route_manager_set_dirty(NMPRouteManager *self, gconstpointer user_tag); - -gboolean nmp_route_manager_untrack_all(NMPRouteManager *self, - gconstpointer user_tag, - gboolean all /* or only dirty */, - gboolean make_survivors_dirty); - -void nmp_route_manager_sync(NMPRouteManager *self, NMPObjectType obj_type, gboolean keep_deleted); - -/*****************************************************************************/ - -#endif /* __NMP_ROUTE_MANAGER_H__ */ diff --git a/src/libnm-platform/tests/test-nm-platform.c b/src/libnm-platform/tests/test-nm-platform.c index 9ac69bde..c351f014 100644 --- a/src/libnm-platform/tests/test-nm-platform.c +++ b/src/libnm-platform/tests/test-nm-platform.c @@ -59,7 +59,7 @@ test_use_symbols(void) (void (*)(void)) genlmsg_valid_hdr, (void (*)(void)) genlmsg_parse, (void (*)(void)) genl_ctrl_resolve, - (void (*)(void)) nl_socket_alloc, + (void (*)(void)) nl_socket_new, (void (*)(void)) nl_socket_free, (void (*)(void)) nl_socket_get_fd, (void (*)(void)) nl_socket_get_local_port, @@ -70,9 +70,6 @@ test_use_symbols(void) (void (*)(void)) nl_socket_set_nonblocking, (void (*)(void)) nl_socket_set_buffer_size, (void (*)(void)) nl_socket_add_memberships, - (void (*)(void)) nl_socket_set_ext_ack, - (void (*)(void)) nl_socket_disable_msg_peek, - (void (*)(void)) nl_connect, (void (*)(void)) nl_wait_for_ack, (void (*)(void)) nl_recvmsgs, (void (*)(void)) nl_sendmsg, diff --git a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c index 475b8a39..37edd928 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c +++ b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c @@ -9,14 +9,13 @@ #include "nm-wifi-utils-nl80211.h" +#include "libnm-std-aux/nm-linux-compat.h" + #include -#include #include #include #include -#include "linux-headers/nl80211-vnd-intel.h" - #include "libnm-log-core/nm-logging.h" #include "libnm-platform/nm-netlink.h" #include "nm-wifi-utils-private.h" @@ -46,9 +45,9 @@ typedef struct { NMWifiUtils parent; struct nl_sock *nl_sock; guint32 *freqs; - int id; int num_freqs; int phy; + guint16 genl_family_id; bool can_wowlan : 1; } NMWifiUtilsNl80211; @@ -59,7 +58,7 @@ typedef struct { G_DEFINE_TYPE(NMWifiUtilsNl80211, nm_wifi_utils_nl80211, NM_TYPE_WIFI_UTILS) static int -ack_handler(struct nl_msg *msg, void *arg) +ack_handler(const struct nl_msg *msg, void *arg) { int *done = arg; *done = 1; @@ -67,7 +66,7 @@ ack_handler(struct nl_msg *msg, void *arg) } static int -finish_handler(struct nl_msg *msg, void *arg) +finish_handler(const struct nl_msg *msg, void *arg) { int *done = arg; *done = 1; @@ -75,7 +74,7 @@ finish_handler(struct nl_msg *msg, void *arg) } static int -error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) +error_handler(const struct sockaddr_nl *nla, const struct nlmsgerr *err, void *arg) { int *done = arg; *done = err->error; @@ -83,12 +82,12 @@ error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) } static struct nl_msg * -_nl80211_alloc_msg(int id, int ifindex, int phy, guint32 cmd, guint32 flags) +_nl80211_alloc_msg(guint16 genl_family_id, int ifindex, int phy, uint8_t cmd, uint16_t flags) { nm_auto_nlmsg struct nl_msg *msg = NULL; msg = nlmsg_alloc(); - genlmsg_put(msg, 0, 0, id, 0, flags, cmd, 0); + genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, genl_family_id, 0, flags, cmd, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); if (phy != -1) NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy); @@ -99,15 +98,15 @@ nla_put_failure: } static struct nl_msg * -nl80211_alloc_msg(NMWifiUtilsNl80211 *self, guint32 cmd, guint32 flags) +nl80211_alloc_msg(NMWifiUtilsNl80211 *self, uint8_t cmd, uint16_t flags) { - return _nl80211_alloc_msg(self->id, self->parent.ifindex, self->phy, cmd, flags); + return _nl80211_alloc_msg(self->genl_family_id, self->parent.ifindex, self->phy, cmd, flags); } static int nl80211_send_and_recv(NMWifiUtilsNl80211 *self, struct nl_msg *msg, - int (*valid_handler)(struct nl_msg *, void *), + int (*valid_handler)(const struct nl_msg *, void *), void *valid_data) { int err; @@ -168,7 +167,7 @@ struct nl80211_iface_info { }; static int -nl80211_iface_info_handler(struct nl_msg *msg, void *arg) +nl80211_iface_info_handler(const struct nl_msg *msg, void *arg) { struct nl80211_iface_info *info = arg; struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); @@ -270,7 +269,7 @@ nla_put_failure: } static int -nl80211_get_wake_on_wlan_handler(struct nl_msg *msg, void *arg) +nl80211_get_wake_on_wlan_handler(const struct nl_msg *msg, void *arg) { _NMSettingWirelessWakeOnWLan *wowl = arg; struct nlattr *attrs[NL80211_ATTR_MAX + 1]; @@ -423,7 +422,7 @@ struct nl80211_station_info { }; static int -nl80211_station_dump_handler(struct nl_msg *msg, void *arg) +nl80211_station_dump_handler(const struct nl_msg *msg, void *arg) { static const struct nla_policy stats_policy[] = { [NL80211_STA_INFO_INACTIVE_TIME] = {.type = NLA_U32}, @@ -577,7 +576,7 @@ struct nl80211_device_info { #define WLAN_CIPHER_SUITE_SMS4 0x00147201 static int -nl80211_wiphy_info_handler(struct nl_msg *msg, void *arg) +nl80211_wiphy_info_handler(const struct nl_msg *msg, void *arg) { static const struct nla_policy freq_policy[] = { [NL80211_FREQUENCY_ATTR_FREQ] = {.type = NLA_U32}, @@ -817,7 +816,7 @@ struct nl80211_csme_conn_info { }; static int -nl80211_csme_conn_event_handler(struct nl_msg *msg, void *arg) +nl80211_csme_conn_event_handler(const struct nl_msg *msg, void *arg) { struct nl80211_csme_conn_info *info = arg; NMPlatformCsmeConnInfo *out_conn_info = info->conn_info; @@ -945,7 +944,7 @@ nm_wifi_utils_nl80211_class_init(NMWifiUtilsNl80211Class *klass) } NMWifiUtils * -nm_wifi_utils_nl80211_new(int ifindex, struct nl_sock *genl) +nm_wifi_utils_nl80211_new(struct nl_sock *genl, guint16 genl_family_id, int ifindex) { gs_unref_object NMWifiUtilsNl80211 *self = NULL; nm_auto_nlmsg struct nl_msg *msg = NULL; @@ -954,16 +953,14 @@ nm_wifi_utils_nl80211_new(int ifindex, struct nl_sock *genl) if (!genl) return NULL; + if (genl_family_id == 0) + return NULL; + self = g_object_new(NM_TYPE_WIFI_UTILS_NL80211, NULL); self->parent.ifindex = ifindex; self->nl_sock = genl; - - self->id = genl_ctrl_resolve(self->nl_sock, "nl80211"); - if (self->id < 0) { - _LOGD("genl_ctrl_resolve: failed to resolve \"nl80211\""); - return NULL; - } + self->genl_family_id = genl_family_id; self->phy = -1; diff --git a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.h b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.h index 4a633307..4783c572 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.h +++ b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.h @@ -24,6 +24,6 @@ GType nm_wifi_utils_nl80211_get_type(void); -NMWifiUtils *nm_wifi_utils_nl80211_new(int ifindex, struct nl_sock *genl); +NMWifiUtils *nm_wifi_utils_nl80211_new(struct nl_sock *genl, guint16 genl_family_id, int ifindex); #endif /* __WIFI_UTILS_NL80211_H__ */ diff --git a/src/libnm-platform/wifi/nm-wifi-utils.c b/src/libnm-platform/wifi/nm-wifi-utils.c index 08a8ec4f..0238b74a 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils.c +++ b/src/libnm-platform/wifi/nm-wifi-utils.c @@ -32,16 +32,16 @@ nm_wifi_utils_class_init(NMWifiUtilsClass *klass) {} NMWifiUtils * -nm_wifi_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan) +nm_wifi_utils_new(struct nl_sock *genl, guint16 genl_family_id, int ifindex, gboolean check_scan) { NMWifiUtils *ret; g_return_val_if_fail(ifindex > 0, NULL); - ret = nm_wifi_utils_nl80211_new(ifindex, genl); + ret = nm_wifi_utils_nl80211_new(genl, genl_family_id, ifindex); #if HAVE_WEXT - if (ret == NULL) + if (!ret) ret = nm_wifi_utils_wext_new(ifindex, check_scan); #endif diff --git a/src/libnm-platform/wifi/nm-wifi-utils.h b/src/libnm-platform/wifi/nm-wifi-utils.h index 0d30c1a1..fd636418 100644 --- a/src/libnm-platform/wifi/nm-wifi-utils.h +++ b/src/libnm-platform/wifi/nm-wifi-utils.h @@ -7,8 +7,6 @@ #ifndef __WIFI_UTILS_H__ #define __WIFI_UTILS_H__ -#include - #include "libnm-platform/nm-netlink.h" #include "libnm-base/nm-base.h" @@ -27,7 +25,8 @@ GType nm_wifi_utils_get_type(void); gboolean nm_wifi_utils_is_wifi(int dirfd, const char *ifname); -NMWifiUtils *nm_wifi_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan); +NMWifiUtils * +nm_wifi_utils_new(struct nl_sock *genl, guint16 genl_family_id, int ifindex, gboolean check_scan); _NMDeviceWifiCapabilities nm_wifi_utils_get_caps(NMWifiUtils *data); diff --git a/src/libnm-platform/wpan/nm-wpan-utils.c b/src/libnm-platform/wpan/nm-wpan-utils.c index d9bbd0f0..675efe5a 100644 --- a/src/libnm-platform/wpan/nm-wpan-utils.c +++ b/src/libnm-platform/wpan/nm-wpan-utils.c @@ -37,9 +37,9 @@ struct NMWpanUtils { GObject parent; - int ifindex; struct nl_sock *nl_sock; - int id; + int ifindex; + guint16 genl_family_id; }; typedef struct { @@ -51,7 +51,7 @@ G_DEFINE_TYPE(NMWpanUtils, nm_wpan_utils, G_TYPE_OBJECT) /*****************************************************************************/ static int -ack_handler(struct nl_msg *msg, void *arg) +ack_handler(const struct nl_msg *msg, void *arg) { int *done = arg; *done = 1; @@ -59,7 +59,7 @@ ack_handler(struct nl_msg *msg, void *arg) } static int -finish_handler(struct nl_msg *msg, void *arg) +finish_handler(const struct nl_msg *msg, void *arg) { int *done = arg; *done = 1; @@ -67,7 +67,7 @@ finish_handler(struct nl_msg *msg, void *arg) } static int -error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) +error_handler(const struct sockaddr_nl *nla, const struct nlmsgerr *err, void *arg) { int *done = arg; *done = err->error; @@ -75,12 +75,13 @@ error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) } static struct nl_msg * -_nl802154_alloc_msg(int id, int ifindex, guint32 cmd, guint32 flags) +_nl802154_alloc_msg(guint16 genl_family_id, int ifindex, uint8_t cmd, uint16_t flags) { nm_auto_nlmsg struct nl_msg *msg = NULL; msg = nlmsg_alloc(); - genlmsg_put(msg, 0, 0, id, 0, flags, cmd, 0); + if (!genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, genl_family_id, 0, flags, cmd, 0)) + goto nla_put_failure; NLA_PUT_U32(msg, NL802154_ATTR_IFINDEX, ifindex); return g_steal_pointer(&msg); @@ -89,15 +90,15 @@ nla_put_failure: } static struct nl_msg * -nl802154_alloc_msg(NMWpanUtils *self, guint32 cmd, guint32 flags) +nl802154_alloc_msg(NMWpanUtils *self, uint8_t cmd, uint16_t flags) { - return _nl802154_alloc_msg(self->id, self->ifindex, cmd, flags); + return _nl802154_alloc_msg(self->genl_family_id, self->ifindex, cmd, flags); } static int nl802154_send_and_recv(NMWpanUtils *self, struct nl_msg *msg, - int (*valid_handler)(struct nl_msg *, void *), + int (*valid_handler)(const struct nl_msg *, void *), void *valid_data) { int err; @@ -143,7 +144,7 @@ struct nl802154_interface { }; static int -nl802154_get_interface_handler(struct nl_msg *msg, void *arg) +nl802154_get_interface_handler(const struct nl_msg *msg, void *arg) { static const struct nla_policy nl802154_policy[] = { [NL802154_ATTR_PAN_ID] = {.type = NLA_U16}, @@ -264,7 +265,7 @@ nm_wpan_utils_class_init(NMWpanUtilsClass *klass) {} NMWpanUtils * -nm_wpan_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan) +nm_wpan_utils_new(struct nl_sock *genl, guint16 genl_family_id, int ifindex, gboolean check_scan) { NMWpanUtils *self; @@ -273,16 +274,13 @@ nm_wpan_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan) if (!genl) return NULL; - self = g_object_new(NM_TYPE_WPAN_UTILS, NULL); - self->ifindex = ifindex; - self->nl_sock = genl; - self->id = genl_ctrl_resolve(genl, "nl802154"); - - if (self->id < 0) { - _LOGD(LOGD_PLATFORM, "genl_ctrl_resolve: failed to resolve \"nl802154\""); - g_object_unref(self); + if (!genl_family_id) return NULL; - } + + self = g_object_new(NM_TYPE_WPAN_UTILS, NULL); + self->ifindex = ifindex; + self->nl_sock = genl; + self->genl_family_id = genl_family_id; return self; } diff --git a/src/libnm-platform/wpan/nm-wpan-utils.h b/src/libnm-platform/wpan/nm-wpan-utils.h index 6130c41e..eea5587d 100644 --- a/src/libnm-platform/wpan/nm-wpan-utils.h +++ b/src/libnm-platform/wpan/nm-wpan-utils.h @@ -6,8 +6,6 @@ #ifndef __WPAN_UTILS_H__ #define __WPAN_UTILS_H__ -#include - #include "libnm-platform/nm-netlink.h" typedef struct NMWpanUtils NMWpanUtils; @@ -23,7 +21,8 @@ typedef struct NMWpanUtils NMWpanUtils; GType nm_wpan_utils_get_type(void); -NMWpanUtils *nm_wpan_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan); +NMWpanUtils * +nm_wpan_utils_new(struct nl_sock *genl, guint16 genl_family_id, int ifindex, gboolean check_scan); guint16 nm_wpan_utils_get_pan_id(NMWpanUtils *self); gboolean nm_wpan_utils_set_pan_id(NMWpanUtils *self, guint16 pan_id); diff --git a/src/libnm-std-aux/c-list-util.c b/src/libnm-std-aux/c-list-util.c index d16bd6b7..12cd5f0f 100644 --- a/src/libnm-std-aux/c-list-util.c +++ b/src/libnm-std-aux/c-list-util.c @@ -182,3 +182,77 @@ c_list_sort(CList *head, CListSortCmp cmp, const void *user_data) c_list_relink(head); } } + +/*****************************************************************************/ + +CList * +c_list_first_unsorted(CList *list, int ascending, CListSortCmp cmp, const void *user_data) +{ + CList *iter_prev = NULL; + CList *iter; + int c; + + /* Returns the first element with the wrong sort order, + * or NULL, if they are all sorted. */ + + c_list_for_each (iter, list) { + if (iter_prev) { + c = cmp(iter_prev, iter, user_data); + if (ascending) { + if (c > 0) + return iter; + } else { + if (c < 0) + return iter; + } + } + iter_prev = iter; + } + + return NULL; +} + +void +c_list_insert_sorted(CList *list, + CList *elem, + int ascending, + int append_equal, + CListSortCmp cmp, + const void *user_data) +{ + CList *iter; + + /* We iterate the list front-to-end, and insert @elem according + * to the sort order @cmp. If @append_equal is TRUE, we will + * skip over equal elements and append afterwards. */ + c_list_for_each (iter, list) { + int c; + + c = cmp(iter, elem, user_data); + + if (ascending) { + if (c < 0) + continue; + if (c > 0 || !append_equal) + goto out; + } else { + if (c > 0) + continue; + if (c < 0 || !append_equal) + goto out; + } + + for (iter = iter->next; iter != list; iter = iter->next) { + c = cmp(iter, elem, user_data); + if (c != 0) { + /* We'd expect that the list is sorted, so @c should be + * greater than 0. But don't enforce that. */ + goto out; + } + } + goto out; + } + +out: + c_list_link_before(iter, elem); +} diff --git a/src/libnm-std-aux/c-list-util.h b/src/libnm-std-aux/c-list-util.h index dbfef0f8..4800a3cc 100644 --- a/src/libnm-std-aux/c-list-util.h +++ b/src/libnm-std-aux/c-list-util.h @@ -53,4 +53,19 @@ c_list_length_is(const CList *list, unsigned long check_len) for (_iter = c_list_entry((_list)->prev, __typeof__(*_iter), _m); &(_iter)->_m != (_list); \ _iter = c_list_entry((_iter)->_m.prev, __typeof__(*_iter), _m)) +CList *c_list_first_unsorted(CList *list, int ascending, CListSortCmp cmp, const void *user_data); + +static inline int +c_list_is_sorted(CList *list, int ascending, CListSortCmp cmp, const void *user_data) +{ + return !c_list_first_unsorted(list, ascending, cmp, user_data); +} + +void c_list_insert_sorted(CList *list, + CList *elem, + int ascending, + int append_equal, + CListSortCmp cmp, + const void *user_data); + #endif /* __C_LIST_UTIL_H__ */ diff --git a/src/libnm-std-aux/nm-default-std.h b/src/libnm-std-aux/nm-default-std.h index 23f5fc60..45c0d153 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-linux-compat.h b/src/libnm-std-aux/nm-linux-compat.h index 7ca7ec78..2675393d 100644 --- a/src/libnm-std-aux/nm-linux-compat.h +++ b/src/libnm-std-aux/nm-linux-compat.h @@ -21,5 +21,7 @@ #include "linux-headers/ethtool.h" #include "linux-headers/nl802154.h" +#include "linux-headers/nl80211-vnd-intel.h" +#include "linux-headers/mptcp.h" #endif /* __NM_LINUX_COMPAT_H__ */ diff --git a/src/libnm-std-aux/nm-std-aux.h b/src/libnm-std-aux/nm-std-aux.h index c44bcc72..77243ab1 100644 --- a/src/libnm-std-aux/nm-std-aux.h +++ b/src/libnm-std-aux/nm-std-aux.h @@ -487,6 +487,23 @@ nm_streq0(const char *s1, const char *s2) return (s1 == s2) || (s1 && s2 && strcmp(s1, s2) == 0); } +static inline int +nm_memcmp(const void *s1, const void *s2, size_t n) +{ + /* Workaround undefined behavior in memcmp() with NULL pointers. */ + if (n == 0) + return 0; + nm_assert(s1); + nm_assert(s2); + return memcmp(s1, s2, n); +} + +static inline bool +nm_memeq(const void *s1, const void *s2, size_t len) +{ + return nm_memcmp(s1, s2, len) == 0; +} + /* * Very similar to g_str_has_prefix() with the obvious meaning. * Differences: @@ -642,169 +659,170 @@ nm_streq0(const char *s1, const char *s2) /*****************************************************************************/ /* clang-format off */ -#define _NM_VA_ARGS_FOREACH_0(prefix, postfix, sep, op) -#define _NM_VA_ARGS_FOREACH_1(prefix, postfix, sep, op, x) prefix _NM_MACRO_CALL2(op, x, 0 ) postfix -#define _NM_VA_ARGS_FOREACH_2(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 1 ) postfix sep _NM_VA_ARGS_FOREACH_1(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_3(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 2 ) postfix sep _NM_VA_ARGS_FOREACH_2(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_4(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 3 ) postfix sep _NM_VA_ARGS_FOREACH_3(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_5(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 4 ) postfix sep _NM_VA_ARGS_FOREACH_4(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_6(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 5 ) postfix sep _NM_VA_ARGS_FOREACH_5(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_7(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 6 ) postfix sep _NM_VA_ARGS_FOREACH_6(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_8(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 7 ) postfix sep _NM_VA_ARGS_FOREACH_7(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_9(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 8 ) postfix sep _NM_VA_ARGS_FOREACH_8(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_10(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 9 ) postfix sep _NM_VA_ARGS_FOREACH_9(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_11(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 10 ) postfix sep _NM_VA_ARGS_FOREACH_10(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_12(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 11 ) postfix sep _NM_VA_ARGS_FOREACH_11(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_13(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 12 ) postfix sep _NM_VA_ARGS_FOREACH_12(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_14(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 13 ) postfix sep _NM_VA_ARGS_FOREACH_13(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_15(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 14 ) postfix sep _NM_VA_ARGS_FOREACH_14(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_16(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 15 ) postfix sep _NM_VA_ARGS_FOREACH_15(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_17(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 16 ) postfix sep _NM_VA_ARGS_FOREACH_16(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_18(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 17 ) postfix sep _NM_VA_ARGS_FOREACH_17(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_19(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 18 ) postfix sep _NM_VA_ARGS_FOREACH_18(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_20(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 19 ) postfix sep _NM_VA_ARGS_FOREACH_19(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_21(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 20 ) postfix sep _NM_VA_ARGS_FOREACH_20(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_22(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 21 ) postfix sep _NM_VA_ARGS_FOREACH_21(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_23(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 22 ) postfix sep _NM_VA_ARGS_FOREACH_22(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_24(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 23 ) postfix sep _NM_VA_ARGS_FOREACH_23(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_25(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 24 ) postfix sep _NM_VA_ARGS_FOREACH_24(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_26(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 25 ) postfix sep _NM_VA_ARGS_FOREACH_25(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_27(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 26 ) postfix sep _NM_VA_ARGS_FOREACH_26(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_28(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 27 ) postfix sep _NM_VA_ARGS_FOREACH_27(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_29(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 28 ) postfix sep _NM_VA_ARGS_FOREACH_28(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_30(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 29 ) postfix sep _NM_VA_ARGS_FOREACH_29(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_31(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 30 ) postfix sep _NM_VA_ARGS_FOREACH_30(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_32(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 31 ) postfix sep _NM_VA_ARGS_FOREACH_31(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_33(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 32 ) postfix sep _NM_VA_ARGS_FOREACH_32(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_34(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 33 ) postfix sep _NM_VA_ARGS_FOREACH_33(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_35(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 34 ) postfix sep _NM_VA_ARGS_FOREACH_34(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_36(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 35 ) postfix sep _NM_VA_ARGS_FOREACH_35(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_37(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 36 ) postfix sep _NM_VA_ARGS_FOREACH_36(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_38(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 37 ) postfix sep _NM_VA_ARGS_FOREACH_37(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_39(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 38 ) postfix sep _NM_VA_ARGS_FOREACH_38(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_40(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 39 ) postfix sep _NM_VA_ARGS_FOREACH_39(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_41(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 40 ) postfix sep _NM_VA_ARGS_FOREACH_40(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_42(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 41 ) postfix sep _NM_VA_ARGS_FOREACH_41(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_43(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 42 ) postfix sep _NM_VA_ARGS_FOREACH_42(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_44(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 43 ) postfix sep _NM_VA_ARGS_FOREACH_43(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_45(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 44 ) postfix sep _NM_VA_ARGS_FOREACH_44(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_46(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 45 ) postfix sep _NM_VA_ARGS_FOREACH_45(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_47(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 46 ) postfix sep _NM_VA_ARGS_FOREACH_46(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_48(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 47 ) postfix sep _NM_VA_ARGS_FOREACH_47(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_49(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 48 ) postfix sep _NM_VA_ARGS_FOREACH_48(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_50(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 49 ) postfix sep _NM_VA_ARGS_FOREACH_49(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_51(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 50 ) postfix sep _NM_VA_ARGS_FOREACH_50(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_52(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 51 ) postfix sep _NM_VA_ARGS_FOREACH_51(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_53(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 52 ) postfix sep _NM_VA_ARGS_FOREACH_52(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_54(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 53 ) postfix sep _NM_VA_ARGS_FOREACH_53(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_55(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 54 ) postfix sep _NM_VA_ARGS_FOREACH_54(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_56(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 55 ) postfix sep _NM_VA_ARGS_FOREACH_55(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_57(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 56 ) postfix sep _NM_VA_ARGS_FOREACH_56(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_58(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 57 ) postfix sep _NM_VA_ARGS_FOREACH_57(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_59(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 58 ) postfix sep _NM_VA_ARGS_FOREACH_58(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_60(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 59 ) postfix sep _NM_VA_ARGS_FOREACH_59(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_61(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 10 ) postfix sep _NM_VA_ARGS_FOREACH_60(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_62(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 61 ) postfix sep _NM_VA_ARGS_FOREACH_61(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_63(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 62 ) postfix sep _NM_VA_ARGS_FOREACH_62(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_64(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 63 ) postfix sep _NM_VA_ARGS_FOREACH_63(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_65(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 64 ) postfix sep _NM_VA_ARGS_FOREACH_64(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_66(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 65 ) postfix sep _NM_VA_ARGS_FOREACH_65(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_67(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 66 ) postfix sep _NM_VA_ARGS_FOREACH_66(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_68(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 67 ) postfix sep _NM_VA_ARGS_FOREACH_67(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_69(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 68 ) postfix sep _NM_VA_ARGS_FOREACH_68(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_70(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 69 ) postfix sep _NM_VA_ARGS_FOREACH_69(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_71(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 70 ) postfix sep _NM_VA_ARGS_FOREACH_70(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_72(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 71 ) postfix sep _NM_VA_ARGS_FOREACH_71(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_73(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 72 ) postfix sep _NM_VA_ARGS_FOREACH_72(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_74(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 73 ) postfix sep _NM_VA_ARGS_FOREACH_73(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_75(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 74 ) postfix sep _NM_VA_ARGS_FOREACH_74(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_76(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 75 ) postfix sep _NM_VA_ARGS_FOREACH_75(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_77(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 76 ) postfix sep _NM_VA_ARGS_FOREACH_76(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_78(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 77 ) postfix sep _NM_VA_ARGS_FOREACH_77(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_79(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 78 ) postfix sep _NM_VA_ARGS_FOREACH_78(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_80(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 79 ) postfix sep _NM_VA_ARGS_FOREACH_79(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_81(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 80 ) postfix sep _NM_VA_ARGS_FOREACH_80(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_82(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 81 ) postfix sep _NM_VA_ARGS_FOREACH_81(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_83(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 82 ) postfix sep _NM_VA_ARGS_FOREACH_82(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_84(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 83 ) postfix sep _NM_VA_ARGS_FOREACH_83(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_85(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 84 ) postfix sep _NM_VA_ARGS_FOREACH_84(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_86(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 85 ) postfix sep _NM_VA_ARGS_FOREACH_85(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_87(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 86 ) postfix sep _NM_VA_ARGS_FOREACH_86(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_88(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 87 ) postfix sep _NM_VA_ARGS_FOREACH_87(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_89(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 88 ) postfix sep _NM_VA_ARGS_FOREACH_88(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_90(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 89 ) postfix sep _NM_VA_ARGS_FOREACH_89(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_91(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 90 ) postfix sep _NM_VA_ARGS_FOREACH_90(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_92(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 91 ) postfix sep _NM_VA_ARGS_FOREACH_91(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_93(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 92 ) postfix sep _NM_VA_ARGS_FOREACH_92(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_94(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 93 ) postfix sep _NM_VA_ARGS_FOREACH_93(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_95(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 94 ) postfix sep _NM_VA_ARGS_FOREACH_94(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_96(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 95 ) postfix sep _NM_VA_ARGS_FOREACH_95(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_97(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 96 ) postfix sep _NM_VA_ARGS_FOREACH_96(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_98(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 97 ) postfix sep _NM_VA_ARGS_FOREACH_97(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_99(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 98 ) postfix sep _NM_VA_ARGS_FOREACH_98(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_100(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 99 ) postfix sep _NM_VA_ARGS_FOREACH_99(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_101(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 100) postfix sep _NM_VA_ARGS_FOREACH_100(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_102(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 101) postfix sep _NM_VA_ARGS_FOREACH_101(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_103(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 102) postfix sep _NM_VA_ARGS_FOREACH_102(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_104(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 103) postfix sep _NM_VA_ARGS_FOREACH_103(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_105(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 104) postfix sep _NM_VA_ARGS_FOREACH_104(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_106(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 105) postfix sep _NM_VA_ARGS_FOREACH_105(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_107(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 106) postfix sep _NM_VA_ARGS_FOREACH_106(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_108(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 107) postfix sep _NM_VA_ARGS_FOREACH_107(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_109(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 108) postfix sep _NM_VA_ARGS_FOREACH_108(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_110(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 109) postfix sep _NM_VA_ARGS_FOREACH_109(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_111(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 100) postfix sep _NM_VA_ARGS_FOREACH_110(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_112(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 111) postfix sep _NM_VA_ARGS_FOREACH_111(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_113(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 112) postfix sep _NM_VA_ARGS_FOREACH_112(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_114(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 113) postfix sep _NM_VA_ARGS_FOREACH_113(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_115(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 114) postfix sep _NM_VA_ARGS_FOREACH_114(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_116(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 115) postfix sep _NM_VA_ARGS_FOREACH_115(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_117(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 116) postfix sep _NM_VA_ARGS_FOREACH_116(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_118(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 117) postfix sep _NM_VA_ARGS_FOREACH_117(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_119(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 118) postfix sep _NM_VA_ARGS_FOREACH_118(prefix, postfix, sep, op, __VA_ARGS__) -#define _NM_VA_ARGS_FOREACH_120(prefix, postfix, sep, op, x, ...) prefix _NM_MACRO_CALL2(op, x, 119) postfix sep _NM_VA_ARGS_FOREACH_119(prefix, postfix, sep, op, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_0( prefix, postfix, sep, op, op_arg) +#define _NM_VA_ARGS_FOREACH_1( prefix, postfix, sep, op, op_arg, x) prefix _NM_MACRO_CALL2(op, x, 0, op_arg) postfix +#define _NM_VA_ARGS_FOREACH_2( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 1, op_arg) postfix sep _NM_VA_ARGS_FOREACH_1( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_3( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 2, op_arg) postfix sep _NM_VA_ARGS_FOREACH_2( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_4( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 3, op_arg) postfix sep _NM_VA_ARGS_FOREACH_3( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_5( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 4, op_arg) postfix sep _NM_VA_ARGS_FOREACH_4( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_6( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 5, op_arg) postfix sep _NM_VA_ARGS_FOREACH_5( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_7( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 6, op_arg) postfix sep _NM_VA_ARGS_FOREACH_6( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_8( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 7, op_arg) postfix sep _NM_VA_ARGS_FOREACH_7( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_9( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 8, op_arg) postfix sep _NM_VA_ARGS_FOREACH_8( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_10( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 9, op_arg) postfix sep _NM_VA_ARGS_FOREACH_9( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_11( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 10, op_arg) postfix sep _NM_VA_ARGS_FOREACH_10( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_12( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 11, op_arg) postfix sep _NM_VA_ARGS_FOREACH_11( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_13( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 12, op_arg) postfix sep _NM_VA_ARGS_FOREACH_12( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_14( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 13, op_arg) postfix sep _NM_VA_ARGS_FOREACH_13( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_15( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 14, op_arg) postfix sep _NM_VA_ARGS_FOREACH_14( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_16( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 15, op_arg) postfix sep _NM_VA_ARGS_FOREACH_15( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_17( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 16, op_arg) postfix sep _NM_VA_ARGS_FOREACH_16( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_18( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 17, op_arg) postfix sep _NM_VA_ARGS_FOREACH_17( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_19( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 18, op_arg) postfix sep _NM_VA_ARGS_FOREACH_18( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_20( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 19, op_arg) postfix sep _NM_VA_ARGS_FOREACH_19( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_21( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 20, op_arg) postfix sep _NM_VA_ARGS_FOREACH_20( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_22( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 21, op_arg) postfix sep _NM_VA_ARGS_FOREACH_21( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_23( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 22, op_arg) postfix sep _NM_VA_ARGS_FOREACH_22( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_24( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 23, op_arg) postfix sep _NM_VA_ARGS_FOREACH_23( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_25( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 24, op_arg) postfix sep _NM_VA_ARGS_FOREACH_24( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_26( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 25, op_arg) postfix sep _NM_VA_ARGS_FOREACH_25( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_27( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 26, op_arg) postfix sep _NM_VA_ARGS_FOREACH_26( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_28( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 27, op_arg) postfix sep _NM_VA_ARGS_FOREACH_27( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_29( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 28, op_arg) postfix sep _NM_VA_ARGS_FOREACH_28( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_30( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 29, op_arg) postfix sep _NM_VA_ARGS_FOREACH_29( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_31( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 30, op_arg) postfix sep _NM_VA_ARGS_FOREACH_30( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_32( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 31, op_arg) postfix sep _NM_VA_ARGS_FOREACH_31( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_33( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 32, op_arg) postfix sep _NM_VA_ARGS_FOREACH_32( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_34( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 33, op_arg) postfix sep _NM_VA_ARGS_FOREACH_33( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_35( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 34, op_arg) postfix sep _NM_VA_ARGS_FOREACH_34( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_36( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 35, op_arg) postfix sep _NM_VA_ARGS_FOREACH_35( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_37( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 36, op_arg) postfix sep _NM_VA_ARGS_FOREACH_36( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_38( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 37, op_arg) postfix sep _NM_VA_ARGS_FOREACH_37( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_39( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 38, op_arg) postfix sep _NM_VA_ARGS_FOREACH_38( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_40( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 39, op_arg) postfix sep _NM_VA_ARGS_FOREACH_39( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_41( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 40, op_arg) postfix sep _NM_VA_ARGS_FOREACH_40( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_42( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 41, op_arg) postfix sep _NM_VA_ARGS_FOREACH_41( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_43( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 42, op_arg) postfix sep _NM_VA_ARGS_FOREACH_42( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_44( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 43, op_arg) postfix sep _NM_VA_ARGS_FOREACH_43( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_45( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 44, op_arg) postfix sep _NM_VA_ARGS_FOREACH_44( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_46( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 45, op_arg) postfix sep _NM_VA_ARGS_FOREACH_45( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_47( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 46, op_arg) postfix sep _NM_VA_ARGS_FOREACH_46( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_48( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 47, op_arg) postfix sep _NM_VA_ARGS_FOREACH_47( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_49( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 48, op_arg) postfix sep _NM_VA_ARGS_FOREACH_48( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_50( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 49, op_arg) postfix sep _NM_VA_ARGS_FOREACH_49( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_51( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 50, op_arg) postfix sep _NM_VA_ARGS_FOREACH_50( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_52( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 51, op_arg) postfix sep _NM_VA_ARGS_FOREACH_51( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_53( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 52, op_arg) postfix sep _NM_VA_ARGS_FOREACH_52( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_54( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 53, op_arg) postfix sep _NM_VA_ARGS_FOREACH_53( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_55( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 54, op_arg) postfix sep _NM_VA_ARGS_FOREACH_54( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_56( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 55, op_arg) postfix sep _NM_VA_ARGS_FOREACH_55( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_57( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 56, op_arg) postfix sep _NM_VA_ARGS_FOREACH_56( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_58( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 57, op_arg) postfix sep _NM_VA_ARGS_FOREACH_57( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_59( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 58, op_arg) postfix sep _NM_VA_ARGS_FOREACH_58( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_60( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 59, op_arg) postfix sep _NM_VA_ARGS_FOREACH_59( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_61( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 10, op_arg) postfix sep _NM_VA_ARGS_FOREACH_60( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_62( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 61, op_arg) postfix sep _NM_VA_ARGS_FOREACH_61( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_63( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 62, op_arg) postfix sep _NM_VA_ARGS_FOREACH_62( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_64( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 63, op_arg) postfix sep _NM_VA_ARGS_FOREACH_63( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_65( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 64, op_arg) postfix sep _NM_VA_ARGS_FOREACH_64( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_66( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 65, op_arg) postfix sep _NM_VA_ARGS_FOREACH_65( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_67( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 66, op_arg) postfix sep _NM_VA_ARGS_FOREACH_66( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_68( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 67, op_arg) postfix sep _NM_VA_ARGS_FOREACH_67( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_69( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 68, op_arg) postfix sep _NM_VA_ARGS_FOREACH_68( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_70( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 69, op_arg) postfix sep _NM_VA_ARGS_FOREACH_69( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_71( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 70, op_arg) postfix sep _NM_VA_ARGS_FOREACH_70( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_72( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 71, op_arg) postfix sep _NM_VA_ARGS_FOREACH_71( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_73( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 72, op_arg) postfix sep _NM_VA_ARGS_FOREACH_72( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_74( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 73, op_arg) postfix sep _NM_VA_ARGS_FOREACH_73( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_75( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 74, op_arg) postfix sep _NM_VA_ARGS_FOREACH_74( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_76( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 75, op_arg) postfix sep _NM_VA_ARGS_FOREACH_75( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_77( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 76, op_arg) postfix sep _NM_VA_ARGS_FOREACH_76( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_78( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 77, op_arg) postfix sep _NM_VA_ARGS_FOREACH_77( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_79( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 78, op_arg) postfix sep _NM_VA_ARGS_FOREACH_78( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_80( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 79, op_arg) postfix sep _NM_VA_ARGS_FOREACH_79( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_81( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 80, op_arg) postfix sep _NM_VA_ARGS_FOREACH_80( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_82( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 81, op_arg) postfix sep _NM_VA_ARGS_FOREACH_81( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_83( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 82, op_arg) postfix sep _NM_VA_ARGS_FOREACH_82( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_84( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 83, op_arg) postfix sep _NM_VA_ARGS_FOREACH_83( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_85( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 84, op_arg) postfix sep _NM_VA_ARGS_FOREACH_84( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_86( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 85, op_arg) postfix sep _NM_VA_ARGS_FOREACH_85( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_87( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 86, op_arg) postfix sep _NM_VA_ARGS_FOREACH_86( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_88( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 87, op_arg) postfix sep _NM_VA_ARGS_FOREACH_87( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_89( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 88, op_arg) postfix sep _NM_VA_ARGS_FOREACH_88( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_90( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 89, op_arg) postfix sep _NM_VA_ARGS_FOREACH_89( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_91( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 90, op_arg) postfix sep _NM_VA_ARGS_FOREACH_90( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_92( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 91, op_arg) postfix sep _NM_VA_ARGS_FOREACH_91( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_93( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 92, op_arg) postfix sep _NM_VA_ARGS_FOREACH_92( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_94( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 93, op_arg) postfix sep _NM_VA_ARGS_FOREACH_93( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_95( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 94, op_arg) postfix sep _NM_VA_ARGS_FOREACH_94( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_96( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 95, op_arg) postfix sep _NM_VA_ARGS_FOREACH_95( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_97( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 96, op_arg) postfix sep _NM_VA_ARGS_FOREACH_96( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_98( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 97, op_arg) postfix sep _NM_VA_ARGS_FOREACH_97( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_99( prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 98, op_arg) postfix sep _NM_VA_ARGS_FOREACH_98( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_100(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 99, op_arg) postfix sep _NM_VA_ARGS_FOREACH_99( prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_101(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 100, op_arg) postfix sep _NM_VA_ARGS_FOREACH_100(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_102(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 101, op_arg) postfix sep _NM_VA_ARGS_FOREACH_101(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_103(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 102, op_arg) postfix sep _NM_VA_ARGS_FOREACH_102(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_104(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 103, op_arg) postfix sep _NM_VA_ARGS_FOREACH_103(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_105(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 104, op_arg) postfix sep _NM_VA_ARGS_FOREACH_104(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_106(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 105, op_arg) postfix sep _NM_VA_ARGS_FOREACH_105(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_107(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 106, op_arg) postfix sep _NM_VA_ARGS_FOREACH_106(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_108(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 107, op_arg) postfix sep _NM_VA_ARGS_FOREACH_107(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_109(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 108, op_arg) postfix sep _NM_VA_ARGS_FOREACH_108(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_110(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 109, op_arg) postfix sep _NM_VA_ARGS_FOREACH_109(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_111(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 100, op_arg) postfix sep _NM_VA_ARGS_FOREACH_110(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_112(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 111, op_arg) postfix sep _NM_VA_ARGS_FOREACH_111(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_113(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 112, op_arg) postfix sep _NM_VA_ARGS_FOREACH_112(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_114(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 113, op_arg) postfix sep _NM_VA_ARGS_FOREACH_113(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_115(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 114, op_arg) postfix sep _NM_VA_ARGS_FOREACH_114(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_116(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 115, op_arg) postfix sep _NM_VA_ARGS_FOREACH_115(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_117(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 116, op_arg) postfix sep _NM_VA_ARGS_FOREACH_116(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_118(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 117, op_arg) postfix sep _NM_VA_ARGS_FOREACH_117(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_119(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 118, op_arg) postfix sep _NM_VA_ARGS_FOREACH_118(prefix, postfix, sep, op, op_arg, __VA_ARGS__) +#define _NM_VA_ARGS_FOREACH_120(prefix, postfix, sep, op, op_arg, x, ...) prefix _NM_MACRO_CALL2(op, x, 119, op_arg) postfix sep _NM_VA_ARGS_FOREACH_119(prefix, postfix, sep, op, op_arg, __VA_ARGS__) /* clang-format on */ -#define NM_VA_ARGS_FOREACH(prefix, postfix, sep, op, ...) \ +#define NM_VA_ARGS_FOREACH(prefix, postfix, sep, op, op_arg, ...) \ _NM_MACRO_CALL(NM_PASTE(_NM_VA_ARGS_FOREACH_, NM_NARG(__VA_ARGS__)), \ prefix, \ postfix, \ sep, \ op, \ + op_arg, \ ##__VA_ARGS__) /*****************************************************************************/ -#define NM_VA_ARGS_JOIN(sep, ...) NM_VA_ARGS_FOREACH(, , sep, _NM_MACRO_SELECT_FIRST, __VA_ARGS__) +#define NM_VA_ARGS_JOIN(sep, ...) NM_VA_ARGS_FOREACH(, , sep, _NM_MACRO_SELECT_FIRST, , __VA_ARGS__) /*****************************************************************************/ -#define _NM_IN_SET_OP(x, idx) ((int) (_x == (x))) -#define _NM_IN_SET(op, type, x, ...) \ - ({ \ - type _x = (x); \ - \ - /* trigger a -Wenum-compare warning */ \ - nm_assert(true || _x == (x)); \ - \ - !!(NM_VA_ARGS_FOREACH(, , op, _NM_IN_SET_OP, __VA_ARGS__)); \ +#define _NM_IN_SET_OP(x, idx, uniq) ((int) (NM_UNIQ_T(xx, uniq) == (x))) +#define _NM_IN_SET(uniq, op, type, x, ...) \ + ({ \ + type NM_UNIQ_T(xx, uniq) = (x); \ + \ + /* trigger a -Wenum-compare warning */ \ + nm_assert(true || NM_UNIQ_T(xx, uniq) == (x)); \ + \ + !!(NM_VA_ARGS_FOREACH(, , op, _NM_IN_SET_OP, uniq, __VA_ARGS__)); \ }) /* Beware that this does short-circuit evaluation (use "||" instead of "|") * which has a possibly unexpected non-function-like behavior. * Use NM_IN_SET_SE if you need all arguments to be evaluated. */ -#define NM_IN_SET(x, ...) _NM_IN_SET(||, typeof(x), x, __VA_ARGS__) +#define NM_IN_SET(x, ...) _NM_IN_SET(NM_UNIQ, ||, typeof(x), x, __VA_ARGS__) /* "SE" stands for "side-effect". Contrary to NM_IN_SET(), this does not do * short-circuit evaluation, which can make a difference if the arguments have * side-effects. */ -#define NM_IN_SET_SE(x, ...) _NM_IN_SET(|, typeof(x), x, __VA_ARGS__) +#define NM_IN_SET_SE(x, ...) _NM_IN_SET(NM_UNIQ, |, typeof(x), x, __VA_ARGS__) /* the *_TYPED forms allow to explicitly select the type of "x". This is useful * if "x" doesn't support typeof (bitfields) or you want to gracefully convert * a type using automatic type conversion rules (but not forcing the conversion * with a cast). */ -#define NM_IN_SET_TYPED(type, x, ...) _NM_IN_SET(||, type, x, __VA_ARGS__) -#define NM_IN_SET_SE_TYPED(type, x, ...) _NM_IN_SET(|, type, x, __VA_ARGS__) +#define NM_IN_SET_TYPED(type, x, ...) _NM_IN_SET(NM_UNIQ, ||, type, x, __VA_ARGS__) +#define NM_IN_SET_SE_TYPED(type, x, ...) _NM_IN_SET(NM_UNIQ, |, type, x, __VA_ARGS__) /*****************************************************************************/ @@ -814,14 +832,14 @@ _NM_IN_STRSET_EVAL_op_streq(const char *x1, const char *x) return x && nm_streq(x1, x); } -#define _NM_IN_STRSET_EVAL_OP_NULL(x, idx) ((int) (((const char *) NULL) == (x))) -#define _NM_IN_STRSET_EVAL_OP_STREQ(x, idx) _NM_IN_STRSET_EVAL_op_streq(_x1, x) -#define _NM_IN_STRSET_EVAL(op, eval_op, x1, ...) \ - ({ \ - const char *const _x1 = (x1); \ - \ - !!(_x1 ? (NM_VA_ARGS_FOREACH(, , op, eval_op, __VA_ARGS__)) \ - : (NM_VA_ARGS_FOREACH(, , op, _NM_IN_STRSET_EVAL_OP_NULL, __VA_ARGS__))); \ +#define _NM_IN_STRSET_EVAL_OP_NULL(x, idx, op_arg) ((int) (((const char *) NULL) == (x))) +#define _NM_IN_STRSET_EVAL_OP_STREQ(x, idx, op_arg) _NM_IN_STRSET_EVAL_op_streq(_x1, x) +#define _NM_IN_STRSET_EVAL(op, eval_op, x1, ...) \ + ({ \ + const char *const _x1 = (x1); \ + \ + !!(_x1 ? (NM_VA_ARGS_FOREACH(, , op, eval_op, , __VA_ARGS__)) \ + : (NM_VA_ARGS_FOREACH(, , op, _NM_IN_STRSET_EVAL_OP_NULL, , __VA_ARGS__))); \ }) /* Beware that this does short-circuit evaluation (use "||" instead of "|") @@ -1106,15 +1124,20 @@ nm_ptr_to_uintptr(const void *p) #define NM_CMP_RETURN(c) \ do { \ const int _cc = (c); \ + \ if (_cc) \ return _cc < 0 ? -1 : 1; \ } while (0) -#define NM_CMP_RETURN_DIRECT(c) \ - do { \ - const int _cc = (c); \ - if (_cc) \ - return _cc; \ +#define NM_CMP_RETURN_DIRECT(c) \ + /* Usually we want that our CMP functions return strictly + * -1, 0, or 1. NM_CMP_RETURN_DIRECT() is like NM_CMP_RETURN(), + * except, it does not clamp the integer value. */ \ + do { \ + const int _cc = (c); \ + \ + if (_cc) \ + return _cc; \ } while (0) #define NM_CMP_SELF(a, b) \ @@ -1130,6 +1153,8 @@ nm_ptr_to_uintptr(const void *p) return 1; \ } while (0) +/*****************************************************************************/ + #define NM_CMP_DIRECT(a, b) \ do { \ typeof(a) _a = (a); \ @@ -1139,10 +1164,13 @@ nm_ptr_to_uintptr(const void *p) return (_a < _b) ? -1 : 1; \ } while (0) -#define NM_CMP_DIRECT_UNSAFE(a, b) \ - do { \ - if ((a) != (b)) \ - return ((a) < (b)) ? -1 : 1; \ +#define NM_CMP_DIRECT_UNSAFE(a, b) \ + /* This variant is "unsafe", because it evaluates the arguments more then once. + * This is only useful for bitfields, for which typeof() doesn't work. + * Don't use otherwise. */ \ + do { \ + if ((a) != (b)) \ + return ((a) < (b)) ? -1 : 1; \ } while (0) /* In the general case, direct pointer comparison is undefined behavior in C. @@ -1151,57 +1179,59 @@ nm_ptr_to_uintptr(const void *p) * between pointers (that can otherwise not be compared). */ #define NM_CMP_DIRECT_PTR(a, b) NM_CMP_DIRECT(nm_ptr_to_uintptr(a), nm_ptr_to_uintptr(b)) -#define NM_CMP_DIRECT_MEMCMP(a, b, size) NM_CMP_RETURN(memcmp((a), (b), (size))) +#define NM_CMP_DIRECT_BOOL(a, b) NM_CMP_DIRECT(!!(a), !!(b)) + +#define NM_CMP_DIRECT_MEMCMP(a, b, size) NM_CMP_RETURN(nm_memcmp((a), (b), (size))) #define NM_CMP_DIRECT_STRCMP(a, b) NM_CMP_RETURN_DIRECT(strcmp((a), (b))) #define NM_CMP_DIRECT_STRCMP0(a, b) NM_CMP_RETURN_DIRECT(nm_strcmp0((a), (b))) +#define NM_CMP_DIRECT_STR_INTERNED(a, b) \ + /* This is interned strings, which are first checked for equality only using pointer + * comparison. Only in case of differences, the sort order is still determined by strcmp(). */ \ + do { \ + const char *const _a = (a); \ + const char *const _b = (b); \ + \ + if (_a != _b) \ + NM_CMP_RETURN_DIRECT(nm_strcmp0(_a, _b)); \ + } while (0) + #define NM_CMP_DIRECT_IN6ADDR(a, b) \ do { \ const struct in6_addr *const _a = (a); \ const struct in6_addr *const _b = (b); \ + \ NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \ } while (0) +/*****************************************************************************/ + #define NM_CMP_FIELD(a, b, field) NM_CMP_DIRECT(((a)->field), ((b)->field)) -#define NM_CMP_FIELD_UNSAFE(a, b, field) \ - do { \ - /* it's unsafe, because it evaluates the arguments more then once. - * This is necessary for bitfields, for which typeof() doesn't work. */ \ - if (((a)->field) != ((b)->field)) \ - return ((a)->field < ((b)->field)) ? -1 : 1; \ - } while (0) +#define NM_CMP_FIELD_UNSAFE(a, b, field) \ + /* This variant is "unsafe", because it evaluates the arguments more then once. + * This is only useful for bitfields, for which typeof() doesn't work. + * Don't use otherwise. */ \ + NM_CMP_DIRECT_UNSAFE(((a)->field), ((b)->field)) -#define NM_CMP_FIELD_BOOL(a, b, field) NM_CMP_DIRECT(!!((a)->field), !!((b)->field)) +#define NM_CMP_FIELD_BOOL(a, b, field) NM_CMP_DIRECT_BOOL(((a)->field), ((b)->field)) -#define NM_CMP_FIELD_STR(a, b, field) NM_CMP_RETURN(strcmp(((a)->field), ((b)->field))) +#define NM_CMP_FIELD_STR(a, b, field) NM_CMP_DIRECT_STRCMP(((a)->field), ((b)->field)) -#define NM_CMP_FIELD_STR_INTERNED(a, b, field) \ - do { \ - const char *_a = ((a)->field); \ - const char *_b = ((b)->field); \ - \ - if (_a != _b) { \ - NM_CMP_RETURN_DIRECT(nm_strcmp0(_a, _b)); \ - } \ - } while (0) +#define NM_CMP_FIELD_STR0(a, b, field) NM_CMP_DIRECT_STRCMP0(((a)->field), ((b)->field)) -#define NM_CMP_FIELD_STR0(a, b, field) NM_CMP_RETURN_DIRECT(nm_strcmp0(((a)->field), ((b)->field))) +#define NM_CMP_FIELD_STR_INTERNED(a, b, field) \ + NM_CMP_DIRECT_STR_INTERNED(((a)->field), ((b)->field)) #define NM_CMP_FIELD_MEMCMP_LEN(a, b, field, len) \ - NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), NM_MIN(len, sizeof((a)->field)))) + NM_CMP_DIRECT_MEMCMP(&((a)->field), &((b)->field), NM_MIN(len, sizeof((a)->field))) #define NM_CMP_FIELD_MEMCMP(a, b, field) \ - NM_CMP_RETURN(memcmp(&((a)->field), &((b)->field), sizeof((a)->field))) + NM_CMP_DIRECT_MEMCMP(&((a)->field), &((b)->field), sizeof((a)->field)) -#define NM_CMP_FIELD_IN6ADDR(a, b, field) \ - do { \ - const struct in6_addr *const _a = &((a)->field); \ - const struct in6_addr *const _b = &((b)->field); \ - NM_CMP_RETURN(memcmp(_a, _b, sizeof(struct in6_addr))); \ - } while (0) +#define NM_CMP_FIELD_IN6ADDR(a, b, field) NM_CMP_DIRECT_IN6ADDR(&((a)->field), &((b)->field)) /*****************************************************************************/ @@ -1277,6 +1307,28 @@ nm_utils_addr_family_to_size(int addr_family) return nm_assert_unreachable_val(0); } +static inline size_t +nm_utils_addr_family_to_size_untrusted(int addr_family) +{ + /* This is almost the same as nm_utils_addr_family_to_size(). + * The difference is that nm_utils_addr_family_to_size() requires that + * addr_family is either AF_INET or AF_INET6 (it asserts against that). + * + * This variant accepts any addr_family, but returns zero for any unknown + * family. + * + * Use this, if the address family is untrusted or not guaranteed to be valid. + * Of course, then you also need to handle that this function potentially returns + * zero. */ + switch (addr_family) { + case NM_AF_INET: + return NM_AF_INET_SIZE; + case NM_AF_INET6: + return NM_AF_INET6_SIZE; + } + return 0; +} + static inline int nm_utils_addr_family_from_size(size_t len) { diff --git a/src/libnm-std-aux/nm-std-utils.h b/src/libnm-std-aux/nm-std-utils.h index 76d49d2f..6aa787eb 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 8bbc02a7..70293a61 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,7 +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-dhcp.c', 'sd-adapt-core/nm-sd-adapt-core.c', ), include_directories: [ 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 13c75055..00000000 --- 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 6487a90d..00000000 --- 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 9978a159..b512e3fc 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 421f5372..79bc5031 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 c8a73111..00000000 --- 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 -#include -#include - -#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 b66a81bf..00000000 --- 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 -#include - -#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-identifier.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c index f2d94214..2636d796 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c @@ -13,7 +13,6 @@ #include "netif-util.h" #include "siphash24.h" #include "sparse-endian.h" -#include "stat-util.h" #include "string-table.h" #include "udev-util.h" @@ -67,20 +66,26 @@ int dhcp_validate_duid_len(DUIDType duid_type, size_t duid_len, bool strict) { } #if 0 /* NM_IGNORED */ -static int dhcp_identifier_set_duid_llt(const uint8_t *addr, size_t addr_len, uint16_t arp_type, usec_t t, struct duid *ret_duid, size_t *ret_len) { +static int dhcp_identifier_set_duid_llt( + const struct hw_addr_data *hw_addr, + uint16_t arp_type, + usec_t t, + struct duid *ret_duid, + size_t *ret_len) { + uint16_t time_from_2000y; - assert(addr); + assert(hw_addr); assert(ret_duid); assert(ret_len); - if (addr_len == 0) + if (hw_addr->length == 0) return -EOPNOTSUPP; if (arp_type == ARPHRD_ETHER) - assert_return(addr_len == ETH_ALEN, -EINVAL); + assert_return(hw_addr->length == ETH_ALEN, -EINVAL); else if (arp_type == ARPHRD_INFINIBAND) - assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL); else return -EOPNOTSUPP; @@ -92,33 +97,38 @@ static int dhcp_identifier_set_duid_llt(const uint8_t *addr, size_t addr_len, ui unaligned_write_be16(&ret_duid->type, DUID_TYPE_LLT); unaligned_write_be16(&ret_duid->llt.htype, arp_type); unaligned_write_be32(&ret_duid->llt.time, time_from_2000y); - memcpy(ret_duid->llt.haddr, addr, addr_len); + memcpy(ret_duid->llt.haddr, hw_addr->bytes, hw_addr->length); - *ret_len = offsetof(struct duid, llt.haddr) + addr_len; + *ret_len = offsetof(struct duid, llt.haddr) + hw_addr->length; return 0; } -static int dhcp_identifier_set_duid_ll(const uint8_t *addr, size_t addr_len, uint16_t arp_type, struct duid *ret_duid, size_t *ret_len) { - assert(addr); +static int dhcp_identifier_set_duid_ll( + const struct hw_addr_data *hw_addr, + uint16_t arp_type, + struct duid *ret_duid, + size_t *ret_len) { + + assert(hw_addr); assert(ret_duid); assert(ret_len); - if (addr_len == 0) + if (hw_addr->length == 0) return -EOPNOTSUPP; if (arp_type == ARPHRD_ETHER) - assert_return(addr_len == ETH_ALEN, -EINVAL); + assert_return(hw_addr->length == ETH_ALEN, -EINVAL); else if (arp_type == ARPHRD_INFINIBAND) - assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL); else return -EOPNOTSUPP; unaligned_write_be16(&ret_duid->type, DUID_TYPE_LL); unaligned_write_be16(&ret_duid->ll.htype, arp_type); - memcpy(ret_duid->ll.haddr, addr, addr_len); + memcpy(ret_duid->ll.haddr, hw_addr->bytes, hw_addr->length); - *ret_len = offsetof(struct duid, ll.haddr) + addr_len; + *ret_len = offsetof(struct duid, ll.haddr) + hw_addr->length; return 0; } @@ -180,8 +190,7 @@ static int dhcp_identifier_set_duid_uuid(struct duid *ret_duid, size_t *ret_len) int dhcp_identifier_set_duid( DUIDType duid_type, - const uint8_t *addr, - size_t addr_len, + const struct hw_addr_data *hw_addr, uint16_t arp_type, usec_t llt_time, bool test_mode, @@ -190,11 +199,11 @@ int dhcp_identifier_set_duid( switch (duid_type) { case DUID_TYPE_LLT: - return dhcp_identifier_set_duid_llt(addr, addr_len, arp_type, llt_time, ret_duid, ret_len); + return dhcp_identifier_set_duid_llt(hw_addr, arp_type, llt_time, ret_duid, ret_len); case DUID_TYPE_EN: return dhcp_identifier_set_duid_en(test_mode, ret_duid, ret_len); case DUID_TYPE_LL: - return dhcp_identifier_set_duid_ll(addr, addr_len, arp_type, ret_duid, ret_len); + return dhcp_identifier_set_duid_ll(hw_addr, arp_type, ret_duid, ret_len); case DUID_TYPE_UUID: return dhcp_identifier_set_duid_uuid(ret_duid, ret_len); default: @@ -205,8 +214,7 @@ int dhcp_identifier_set_duid( int dhcp_identifier_set_iaid( int ifindex, - const uint8_t *mac, - size_t mac_len, + const struct hw_addr_data *hw_addr, bool legacy_unstable_byteorder, bool use_mac, void *ret) { @@ -220,7 +228,11 @@ int dhcp_identifier_set_iaid( uint64_t id; int r; - if (path_is_read_only_fs("/sys") <= 0 && !use_mac) { + assert(ifindex > 0); + assert(hw_addr); + assert(ret); + + if (udev_available() && !use_mac) { /* udev should be around */ r = sd_device_new_from_ifindex(&device, ifindex); @@ -248,7 +260,7 @@ int dhcp_identifier_set_iaid( id = siphash24(name, strlen(name), HASH_KEY.bytes); else /* fall back to MAC address if no predictable name available */ - id = siphash24(mac, mac_len, HASH_KEY.bytes); + id = siphash24(hw_addr->bytes, hw_addr->length, HASH_KEY.bytes); id32 = (id & 0xffffffff) ^ (id >> 32); diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h index 697ba3bf..8acb8c32 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h @@ -3,6 +3,7 @@ #include "sd-id128.h" +#include "ether-addr-util.h" #include "macro.h" #include "sparse-endian.h" #include "time-util.h" @@ -58,8 +59,7 @@ int dhcp_validate_duid_len(DUIDType duid_type, size_t duid_len, bool strict); int dhcp_identifier_set_duid_en(bool test_mode, struct duid *ret_duid, size_t *ret_len); int dhcp_identifier_set_duid( DUIDType duid_type, - const uint8_t *addr, - size_t addr_len, + const struct hw_addr_data *hw_addr, uint16_t arp_type, usec_t llt_time, bool test_mode, @@ -67,8 +67,7 @@ int dhcp_identifier_set_duid( size_t *ret_len); int dhcp_identifier_set_iaid( int ifindex, - const uint8_t *mac, - size_t mac_len, + const struct hw_addr_data *hw_addr, bool legacy_unstable_byteorder, bool use_mac, void *ret); 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 466d8e4b..00000000 --- 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 -#include -#include - -#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 c67e9511..00000000 --- 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 1c5f3427..00000000 --- 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#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(ð_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(ð_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(ð_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, - ð_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 712f6097..00000000 --- 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 -#include -#include - -#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, ¤t_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, ¤t_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 25a69a61..00000000 --- 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 -#include -#include -#include - -#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 dd54bcf6..00000000 --- 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 -#include -#include - -#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/dhcp6-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h index 0d7813f6..65f6cb05 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h @@ -64,13 +64,14 @@ struct sd_dhcp6_client { struct duid duid; size_t duid_len; be16_t *req_opts; - size_t req_opts_len; + size_t n_req_opts; char *fqdn; char *mudurl; char **user_class; char **vendor_class; OrderedHashmap *extra_options; OrderedSet *vendor_options; + bool rapid_commit; struct sd_dhcp6_lease *lease; diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c index 03d56371..05f2a383 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c @@ -53,18 +53,20 @@ bool dhcp6_option_can_request(uint16_t option) { return false; case SD_DHCP6_OPTION_SIP_SERVER_DOMAIN_NAME: case SD_DHCP6_OPTION_SIP_SERVER_ADDRESS: - case SD_DHCP6_OPTION_DNS_SERVERS: - case SD_DHCP6_OPTION_DOMAIN_LIST: + case SD_DHCP6_OPTION_DNS_SERVER: + case SD_DHCP6_OPTION_DOMAIN: return true; case SD_DHCP6_OPTION_IA_PD: case SD_DHCP6_OPTION_IA_PD_PREFIX: return false; - case SD_DHCP6_OPTION_NIS_SERVERS: - case SD_DHCP6_OPTION_NISP_SERVERS: + case SD_DHCP6_OPTION_NIS_SERVER: + case SD_DHCP6_OPTION_NISP_SERVER: case SD_DHCP6_OPTION_NIS_DOMAIN_NAME: case SD_DHCP6_OPTION_NISP_DOMAIN_NAME: - case SD_DHCP6_OPTION_SNTP_SERVERS: + case SD_DHCP6_OPTION_SNTP_SERVER: + return true; case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME: + return false; /* This is automatically set when sending INFORMATION_REQUEST message. */ case SD_DHCP6_OPTION_BCMCS_SERVER_D: case SD_DHCP6_OPTION_BCMCS_SERVER_A: case SD_DHCP6_OPTION_GEOCONF_CIVIC: @@ -126,9 +128,9 @@ bool dhcp6_option_can_request(uint16_t option) { case SD_DHCP6_OPTION_CLIENT_LINKLAYER_ADDR: case SD_DHCP6_OPTION_LINK_ADDRESS: case SD_DHCP6_OPTION_RADIUS: + case SD_DHCP6_OPTION_SOL_MAX_RT: /* Automatically set when sending SOLICIT message. */ + case SD_DHCP6_OPTION_INF_MAX_RT: /* Automatically set when sending INFORMATION_REQUEST message. */ return false; - case SD_DHCP6_OPTION_SOL_MAX_RT: - case SD_DHCP6_OPTION_INF_MAX_RT: case SD_DHCP6_OPTION_ADDRSEL: case SD_DHCP6_OPTION_ADDRSEL_TABLE: case SD_DHCP6_OPTION_V6_PCP_SERVER: @@ -508,7 +510,7 @@ int dhcp6_option_parse( if (buflen < offsetof(DHCP6Option, data)) return -EBADMSG; - if (*offset >= buflen - offsetof(DHCP6Option, data)) + if (*offset > buflen - offsetof(DHCP6Option, data)) return -EBADMSG; len = unaligned_read_be16(buf + *offset + offsetof(DHCP6Option, len)); @@ -518,14 +520,14 @@ int dhcp6_option_parse( *ret_option_code = unaligned_read_be16(buf + *offset + offsetof(DHCP6Option, code)); *ret_option_data_len = len; - *ret_option_data = buf + *offset + offsetof(DHCP6Option, data); + *ret_option_data = len == 0 ? NULL : buf + *offset + offsetof(DHCP6Option, data); *offset += offsetof(DHCP6Option, data) + len; return 0; } int dhcp6_option_parse_status(const uint8_t *data, size_t data_len, char **ret_status_message) { - assert(data); + assert(data || data_len == 0); if (data_len < sizeof(uint16_t)) return -EBADMSG; @@ -803,7 +805,7 @@ int dhcp6_option_parse_addresses( struct in6_addr **addrs, size_t *count) { - assert(optval); + assert(optval || optlen == 0); assert(addrs); assert(count); @@ -826,8 +828,8 @@ static int parse_domain(const uint8_t **data, size_t *len, char **ret) { int r; assert(data); - assert(*data); assert(len); + assert(*data || *len == 0); assert(ret); optval = *data; @@ -891,7 +893,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, size_t optlen, char **r _cleanup_free_ char *domain = NULL; int r; - assert(optval); + assert(optval || optlen == 0); assert(ret); r = parse_domain(&optval, &optlen, &domain); @@ -910,7 +912,7 @@ int dhcp6_option_parse_domainname_list(const uint8_t *optval, size_t optlen, cha _cleanup_strv_free_ char **names = NULL; int r; - assert(optval); + assert(optval || optlen == 0); assert(ret); if (optlen <= 1) diff --git a/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c b/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c index f56929ad..d4aec944 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c +++ b/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c @@ -118,6 +118,9 @@ sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n) { sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size) { sd_lldp_neighbor *n; + if (raw_size > SIZE_MAX - ALIGN(sizeof(sd_lldp_neighbor))) + return NULL; + n = malloc0(ALIGN(sizeof(sd_lldp_neighbor)) + raw_size); if (!n) return NULL; @@ -651,7 +654,8 @@ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t ra if (!n) return -ENOMEM; - memcpy(LLDP_NEIGHBOR_RAW(n), raw, raw_size); + memcpy_safe(LLDP_NEIGHBOR_RAW(n), raw, raw_size); + r = lldp_neighbor_parse(n); if (r < 0) return r; 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 60ce47ea..00000000 --- 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 -#include -#include - -#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 5aa225e9..00000000 --- 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 -#include - -#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 d56978ad..00000000 --- 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 -#include -#include -#include -#include -#include -#include - -#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 5f83fa66..00000000 --- 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 -#include -#include -#include -#include -#include - -#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/libsystemd-network/sd-dhcp6-client.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c index 4394ef49..fbe15f00 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c @@ -29,16 +29,10 @@ #include "io-util.h" #include "random-util.h" #include "socket-util.h" +#include "sort-util.h" #include "strv.h" #include "web-util.h" -static const uint16_t default_req_opts[] = { - SD_DHCP6_OPTION_DNS_SERVERS, - SD_DHCP6_OPTION_DOMAIN_LIST, - SD_DHCP6_OPTION_NTP_SERVER, - SD_DHCP6_OPTION_SNTP_SERVERS, -}; - #define DHCP6_CLIENT_DONT_DESTROY(client) \ _cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client) @@ -128,9 +122,8 @@ int sd_dhcp6_client_set_mac( return 0; } - memcpy(client->hw_addr.bytes, addr, addr_len); - client->hw_addr.length = addr_len; client->arp_type = arp_type; + hw_addr_set(&client->hw_addr, addr, addr_len); return 0; } @@ -229,8 +222,8 @@ static int dhcp6_client_set_duid_internal( } else { #if 0 /* NM_IGNORED */ - r = dhcp_identifier_set_duid(duid_type, client->hw_addr.bytes, client->hw_addr.length, - client->arp_type, llt_time, client->test_mode, &client->duid, &client->duid_len); + r = dhcp_identifier_set_duid(duid_type, &client->hw_addr, client->arp_type, llt_time, + client->test_mode, &client->duid, &client->duid_len); if (r == -EOPNOTSUPP) return log_dhcp6_client_errno(client, r, "Failed to set %s. MAC address is not set or " @@ -316,7 +309,7 @@ static int client_ensure_iaid(sd_dhcp6_client *client) { if (client->iaid_set) return 0; - r = dhcp_identifier_set_iaid(client->ifindex, client->hw_addr.bytes, client->hw_addr.length, + r = dhcp_identifier_set_iaid(client->ifindex, &client->hw_addr, /* legacy_unstable_byteorder = */ true, /* use_mac = */ client->test_mode, &iaid); @@ -381,8 +374,12 @@ int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enable return 0; } +static int be16_compare_func(const be16_t *a, const be16_t *b) { + return CMP(be16toh(*a), be16toh(*b)); +} + int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) { - size_t t; + be16_t opt; assert_return(client, -EINVAL); assert_return(!sd_dhcp6_client_is_running(client), -EBUSY); @@ -390,15 +387,17 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) if (!dhcp6_option_can_request(option)) return -EINVAL; - for (t = 0; t < client->req_opts_len; t++) - if (client->req_opts[t] == htobe16(option)) - return -EEXIST; + opt = htobe16(option); + if (typesafe_bsearch(&opt, client->req_opts, client->n_req_opts, be16_compare_func)) + return -EEXIST; - if (!GREEDY_REALLOC(client->req_opts, client->req_opts_len + 1)) + if (!GREEDY_REALLOC(client->req_opts, client->n_req_opts + 1)) return -ENOMEM; - client->req_opts[client->req_opts_len++] = htobe16(option); + client->req_opts[client->n_req_opts++] = opt; + /* Sort immediately to make the above binary search will work for the next time. */ + typesafe_qsort(client->req_opts, client->n_req_opts, be16_compare_func); return 0; } @@ -501,6 +500,14 @@ int dhcp6_client_set_transaction_id(sd_dhcp6_client *client, uint32_t transactio return 0; } +int sd_dhcp6_client_set_rapid_commit(sd_dhcp6_client *client, int enable) { + assert_return(client, -EINVAL); + assert_return(!sd_dhcp6_client_is_running(client), -EBUSY); + + client->rapid_commit = enable; + return 0; +} + int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) { assert_return(client, -EINVAL); @@ -645,6 +652,51 @@ static DHCP6MessageType client_message_type_from_state(sd_dhcp6_client *client) } } +static int client_append_oro(sd_dhcp6_client *client, uint8_t **opt, size_t *optlen) { + _cleanup_free_ be16_t *buf = NULL; + be16_t *req_opts; + size_t n; + + assert(client); + assert(opt); + assert(optlen); + + switch (client->state) { + case DHCP6_STATE_INFORMATION_REQUEST: + n = client->n_req_opts; + buf = new(be16_t, n + 2); + if (!buf) + return -ENOMEM; + + memcpy_safe(buf, client->req_opts, n * sizeof(be16_t)); + buf[n++] = htobe16(SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME); /* RFC 8415 section 21.23 */ + buf[n++] = htobe16(SD_DHCP6_OPTION_INF_MAX_RT); /* RFC 8415 section 21.25 */ + + typesafe_qsort(buf, n, be16_compare_func); + req_opts = buf; + break; + + case DHCP6_STATE_SOLICITATION: + n = client->n_req_opts; + buf = new(be16_t, n + 1); + if (!buf) + return -ENOMEM; + + memcpy_safe(buf, client->req_opts, n * sizeof(be16_t)); + buf[n++] = htobe16(SD_DHCP6_OPTION_SOL_MAX_RT); /* RFC 8415 section 21.24 */ + + typesafe_qsort(buf, n, be16_compare_func); + req_opts = buf; + break; + + default: + n = client->n_req_opts; + req_opts = client->req_opts; + } + + return dhcp6_option_append(opt, optlen, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts); +} + int dhcp6_client_send_message(sd_dhcp6_client *client) { _cleanup_free_ DHCP6Message *message = NULL; struct in6_addr all_servers = @@ -679,9 +731,11 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) { break; case DHCP6_STATE_SOLICITATION: - r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_RAPID_COMMIT, 0, NULL); - if (r < 0) - return r; + if (client->rapid_commit) { + r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_RAPID_COMMIT, 0, NULL); + if (r < 0) + return r; + } r = client_append_common_options_in_managed_mode(client, &opt, &optlen, &client->ia_na, &client->ia_pd); @@ -722,9 +776,7 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) { return r; } - r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ORO, - client->req_opts_len * sizeof(be16_t), - client->req_opts); + r = client_append_oro(client, &opt, &optlen); if (r < 0) return r; @@ -1127,6 +1179,10 @@ static int client_process_advertise_or_rapid_commit_reply( if (message->type == DHCP6_MESSAGE_REPLY) { bool rapid_commit; + if (!client->rapid_commit) + return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), + "Received unexpected reply message, even we sent a solicit message without the rapid commit option, ignoring."); + r = dhcp6_lease_get_rapid_commit(lease, &rapid_commit); if (r < 0) return r; @@ -1311,13 +1367,10 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { if (client->fd < 0) { r = dhcp6_network_bind_udp_socket(client->ifindex, &client->local_address); - if (r < 0) { - _cleanup_free_ char *p = NULL; - - (void) in6_addr_to_string(&client->local_address, &p); + if (r < 0) return log_dhcp6_client_errno(client, r, - "Failed to bind to UDP socket at address %s: %m", strna(p)); - } + "Failed to bind to UDP socket at address %s: %m", + IN6_ADDR_TO_STRING(&client->local_address)); client->fd = r; } @@ -1351,7 +1404,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { } log_dhcp6_client(client, "Starting in %s mode", - client->information_request ? "Information request" : "Managed"); + client->information_request ? "Information request" : "Solicit"); return client_start_transaction(client, state); } @@ -1423,18 +1476,9 @@ DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_client, sd_dhcp6_client, dhcp6_client_fre int sd_dhcp6_client_new(sd_dhcp6_client **ret) { _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL; - _cleanup_free_ be16_t *req_opts = NULL; - size_t t; assert_return(ret, -EINVAL); - req_opts = new(be16_t, ELEMENTSOF(default_req_opts)); - if (!req_opts) - return -ENOMEM; - - for (t = 0; t < ELEMENTSOF(default_req_opts); t++) - req_opts[t] = htobe16(default_req_opts[t]); - client = new(sd_dhcp6_client, 1); if (!client) return -ENOMEM; @@ -1446,8 +1490,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) { .ifindex = -1, .request_ia = DHCP6_REQUEST_IA_NA | DHCP6_REQUEST_IA_PD, .fd = -1, - .req_opts_len = ELEMENTSOF(default_req_opts), - .req_opts = TAKE_PTR(req_opts), + .rapid_commit = true, }; *ret = TAKE_PTR(client); diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c index fd47cb73..55c7d627 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c @@ -469,7 +469,9 @@ static int dhcp6_lease_parse_message( r = dhcp6_option_parse(message->options, len, &offset, &optcode, &optlen, &optval); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, + "Failed to parse option header at offset %zu of total length %zu: %m", + offset, len); switch (optcode) { case SD_DHCP6_OPTION_CLIENTID: @@ -479,7 +481,7 @@ static int dhcp6_lease_parse_message( r = dhcp6_lease_set_clientid(lease, optval, optlen); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to set client ID: %m"); break; @@ -490,17 +492,17 @@ static int dhcp6_lease_parse_message( r = dhcp6_lease_set_serverid(lease, optval, optlen); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to set server ID: %m"); break; case SD_DHCP6_OPTION_PREFERENCE: if (optlen != 1) - return -EINVAL; + return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "Received invalid length for preference."); r = dhcp6_lease_set_preference(lease, optval[0]); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to set preference: %m"); break; @@ -509,7 +511,7 @@ static int dhcp6_lease_parse_message( r = dhcp6_option_parse_status(optval, optlen, &msg); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to parse status code: %m"); if (r > 0) return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), @@ -529,9 +531,11 @@ static int dhcp6_lease_parse_message( r = dhcp6_option_parse_ia(client, client->ia_na.header.id, optcode, optlen, optval, &ia); if (r == -ENOMEM) - return r; - if (r < 0) + return log_oom_debug(); + if (r < 0) { + log_dhcp6_client_errno(client, r, "Failed to parse IA_NA option, ignoring: %m"); continue; + } if (lease->ia_na) { log_dhcp6_client(client, "Received duplicate matching IA_NA option, ignoring."); @@ -552,9 +556,11 @@ static int dhcp6_lease_parse_message( r = dhcp6_option_parse_ia(client, client->ia_pd.header.id, optcode, optlen, optval, &ia); if (r == -ENOMEM) - return r; - if (r < 0) + return log_oom_debug(); + if (r < 0) { + log_dhcp6_client_errno(client, r, "Failed to parse IA_PD option, ignoring: %m"); continue; + } if (lease->ia_pd) { log_dhcp6_client(client, "Received duplicate matching IA_PD option, ignoring."); @@ -566,20 +572,23 @@ static int dhcp6_lease_parse_message( break; } case SD_DHCP6_OPTION_RAPID_COMMIT: + if (optlen != 0) + log_dhcp6_client(client, "Received rapid commit option with an invalid length (%zu), ignoring.", optlen); + r = dhcp6_lease_set_rapid_commit(lease); if (r < 0) - return r; + return log_dhcp6_client_errno(client, r, "Failed to set rapid commit flag: %m"); break; - case SD_DHCP6_OPTION_DNS_SERVERS: + case SD_DHCP6_OPTION_DNS_SERVER: r = dhcp6_lease_add_dns(lease, optval, optlen); if (r < 0) log_dhcp6_client_errno(client, r, "Failed to parse DNS server option, ignoring: %m"); break; - case SD_DHCP6_OPTION_DOMAIN_LIST: + case SD_DHCP6_OPTION_DOMAIN: r = dhcp6_lease_add_domains(lease, optval, optlen); if (r < 0) log_dhcp6_client_errno(client, r, "Failed to parse domain list option, ignoring: %m"); @@ -593,7 +602,7 @@ static int dhcp6_lease_parse_message( break; - case SD_DHCP6_OPTION_SNTP_SERVERS: + case SD_DHCP6_OPTION_SNTP_SERVER: r = dhcp6_lease_add_sntp(lease, optval, optlen); if (r < 0) log_dhcp6_client_errno(client, r, "Failed to parse SNTP server option, ignoring: %m"); @@ -609,7 +618,8 @@ static int dhcp6_lease_parse_message( case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME: if (optlen != 4) - return -EINVAL; + return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), + "Received information refresh time option with an invalid length (%zu).", optlen); irt = unaligned_read_be32((be32_t *) optval) * USEC_PER_SEC; break; diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c index 6e3c2ce9..ebbd4422 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c @@ -111,20 +111,6 @@ int event_reset_time_relative( return event_reset_time(e, s, clock, usec_add(usec_now, usec), accuracy, callback, userdata, priority, description, force_reset); } -int event_source_disable(sd_event_source *s) { - if (!s) - return 0; - - return sd_event_source_set_enabled(s, SD_EVENT_OFF); -} - -int event_source_is_enabled(sd_event_source *s) { - if (!s) - return false; - - return sd_event_source_get_enabled(s, NULL); -} - #if 0 /* NM_IGNORED */ int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata) { _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h index abd043bd..c1855844 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h +++ b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h @@ -27,7 +27,8 @@ int event_reset_time_relative( int64_t priority, const char *description, bool force_reset); -int event_source_disable(sd_event_source *s); -int event_source_is_enabled(sd_event_source *s); +static inline int event_source_disable(sd_event_source *s) { + return sd_event_source_set_enabled(s, SD_EVENT_OFF); +} int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata); diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c index 240476e6..8b2c554c 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c @@ -15,6 +15,7 @@ #include "event-source.h" #include "fd-util.h" #include "fs-util.h" +#include "glyph-util.h" #include "hashmap.h" #include "list.h" #include "macro.h" @@ -50,19 +51,19 @@ static bool event_source_is_offline(sd_event_source *s) { } static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = { - [SOURCE_IO] = "io", - [SOURCE_TIME_REALTIME] = "realtime", - [SOURCE_TIME_BOOTTIME] = "bootime", - [SOURCE_TIME_MONOTONIC] = "monotonic", + [SOURCE_IO] = "io", + [SOURCE_TIME_REALTIME] = "realtime", + [SOURCE_TIME_BOOTTIME] = "bootime", + [SOURCE_TIME_MONOTONIC] = "monotonic", [SOURCE_TIME_REALTIME_ALARM] = "realtime-alarm", [SOURCE_TIME_BOOTTIME_ALARM] = "boottime-alarm", - [SOURCE_SIGNAL] = "signal", - [SOURCE_CHILD] = "child", - [SOURCE_DEFER] = "defer", - [SOURCE_POST] = "post", - [SOURCE_EXIT] = "exit", - [SOURCE_WATCHDOG] = "watchdog", - [SOURCE_INOTIFY] = "inotify", + [SOURCE_SIGNAL] = "signal", + [SOURCE_CHILD] = "child", + [SOURCE_DEFER] = "defer", + [SOURCE_POST] = "post", + [SOURCE_EXIT] = "exit", + [SOURCE_WATCHDOG] = "watchdog", + [SOURCE_INOTIFY] = "inotify", }; DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(event_source_type, int); @@ -125,10 +126,10 @@ struct sd_event { Hashmap *inotify_data; /* indexed by priority */ /* A list of inode structures that still have an fd open, that we need to close before the next loop iteration */ - LIST_HEAD(struct inode_data, inode_data_to_close); + LIST_HEAD(struct inode_data, inode_data_to_close_list); /* A list of inotify objects that already have events buffered which aren't processed yet */ - LIST_HEAD(struct inotify_data, inotify_data_buffered); + LIST_HEAD(struct inotify_data, buffered_inotify_data_list); pid_t original_pid; @@ -407,7 +408,8 @@ _public_ int sd_event_new(sd_event** ret) { e->epoll_fd = fd_move_above_stdio(e->epoll_fd); if (secure_getenv("SD_EVENT_PROFILE_DELAYS")) { - log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 … 2^63 us will be logged every 5s."); + log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 %s 2^63 us will be logged every 5s.", + special_glyph(SPECIAL_GLYPH_ELLIPSIS)); e->profile_delays = true; } @@ -420,6 +422,8 @@ fail: } DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_event, sd_event, event_free); +#define PROTECT_EVENT(e) \ + _unused_ _cleanup_(sd_event_unrefp) sd_event *_ref = sd_event_ref(e); _public_ sd_event_source* sd_event_source_disable_unref(sd_event_source *s) { if (s) @@ -708,6 +712,9 @@ static void event_unmask_signal_data(sd_event *e, struct signal_data *d, int sig return; } + if (event_pid_changed(e)) + return; + assert(d->fd >= 0); if (signalfd(d->fd, &d->sigset, SFD_NONBLOCK|SFD_CLOEXEC) < 0) @@ -853,6 +860,9 @@ static void source_disconnect(sd_event_source *s) { break; case SOURCE_CHILD: + if (event_pid_changed(s->event)) + s->child.process_owned = false; + if (s->child.pid > 0) { if (event_source_is_online(s)) { assert(s->event->n_online_child_sources > 0); @@ -1429,7 +1439,6 @@ _public_ int sd_event_add_child( return -ENOMEM; s->wakeup = WAKEUP_EVENT_SOURCE; - s->child.pid = pid; s->child.options = options; s->child.callback = callback; s->userdata = userdata; @@ -1439,7 +1448,7 @@ _public_ int sd_event_add_child( * pin the PID, and make regular waitid() handling race-free. */ if (shall_use_pidfd()) { - s->child.pidfd = pidfd_open(s->child.pid, 0); + s->child.pidfd = pidfd_open(pid, 0); if (s->child.pidfd < 0) { /* Propagate errors unless the syscall is not supported or blocked */ if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) @@ -1449,10 +1458,6 @@ _public_ int sd_event_add_child( } else s->child.pidfd = -1; - r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s); - if (r < 0) - return r; - if (EVENT_SOURCE_WATCH_PIDFD(s)) { /* We have a pidfd and we only want to watch for exit */ r = source_child_pidfd_register(s, s->enabled); @@ -1468,6 +1473,12 @@ _public_ int sd_event_add_child( e->need_process_child = true; } + r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s); + if (r < 0) + return r; + + /* These must be done after everything succeeds. */ + s->child.pid = pid; e->n_online_child_sources++; if (ret) @@ -1687,7 +1698,7 @@ static void event_free_inotify_data(sd_event *e, struct inotify_data *d) { assert(hashmap_isempty(d->wd)); if (d->buffer_filled > 0) - LIST_REMOVE(buffered, e->inotify_data_buffered, d); + LIST_REMOVE(buffered, e->buffered_inotify_data_list, d); hashmap_free(d->inodes); hashmap_free(d->wd); @@ -1695,7 +1706,8 @@ static void event_free_inotify_data(sd_event *e, struct inotify_data *d) { assert_se(hashmap_remove(e->inotify_data, &d->priority) == d); if (d->fd >= 0) { - if (epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, d->fd, NULL) < 0) + if (!event_pid_changed(e) && + epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, d->fd, NULL) < 0) log_debug_errno(errno, "Failed to remove inotify fd from epoll, ignoring: %m"); safe_close(d->fd); @@ -1798,14 +1810,14 @@ static void event_free_inode_data( assert(!d->event_sources); if (d->fd >= 0) { - LIST_REMOVE(to_close, e->inode_data_to_close, d); + LIST_REMOVE(to_close, e->inode_data_to_close_list, d); safe_close(d->fd); } if (d->inotify_data) { if (d->wd >= 0) { - if (d->inotify_data->fd >= 0) { + if (d->inotify_data->fd >= 0 && !event_pid_changed(e)) { /* So here's a problem. At the time this runs the watch descriptor might already be * invalidated, because an IN_IGNORED event might be queued right the moment we enter * the syscall. Hence, whenever we get EINVAL, ignore it entirely, since it's a very @@ -2060,7 +2072,7 @@ static int event_add_inotify_fd_internal( } } - LIST_PREPEND(to_close, e->inode_data_to_close, inode_data); + LIST_PREPEND(to_close, e->inode_data_to_close_list, inode_data); } /* Link our event source to the inode data object */ @@ -2133,12 +2145,9 @@ static sd_event_source* event_source_free(sd_event_source *s) { * we still retain a valid event source object after * the callback. */ - if (s->dispatching) { - if (s->type == SOURCE_IO) - source_io_unregister(s); - + if (s->dispatching) source_disconnect(s); - } else + else source_free(s); return NULL; @@ -2347,7 +2356,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) goto fail; } - LIST_PREPEND(to_close, s->event->inode_data_to_close, new_inode_data); + LIST_PREPEND(to_close, s->event->inode_data_to_close_list, new_inode_data); } /* Move the event source to the new inode data structure */ @@ -2407,6 +2416,10 @@ fail: } _public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) { + /* Quick mode: the event source doesn't exist and we only want to query boolean enablement state. */ + if (!s && !ret) + return false; + assert_return(s, -EINVAL); assert_return(!event_pid_changed(s->event), -ECHILD); @@ -2584,8 +2597,13 @@ static int event_source_online( _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { int r; - assert_return(s, -EINVAL); assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL); + + /* Quick mode: if the source doesn't exist, SD_EVENT_OFF is a noop. */ + if (m == SD_EVENT_OFF && !s) + return 0; + + assert_return(s, -EINVAL); assert_return(!event_pid_changed(s->event), -ECHILD); /* If we are dead anyway, we are fine with turning off sources, but everything else needs to fail. */ @@ -3222,23 +3240,16 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori e->need_process_child = false; - /* - So, this is ugly. We iteratively invoke waitid() with P_PID - + WNOHANG for each PID we wait for, instead of using - P_ALL. This is because we only want to get child - information of very specific child processes, and not all - of them. We might not have processed the SIGCHLD even of a - previous invocation and we don't want to maintain a - unbounded *per-child* event queue, hence we really don't - want anything flushed out of the kernel's queue that we - don't care about. Since this is O(n) this means that if you - have a lot of processes you probably want to handle SIGCHLD - yourself. - - We do not reap the children here (by using WNOWAIT), this - is only done after the event source is dispatched so that - the callback still sees the process as a zombie. - */ + /* So, this is ugly. We iteratively invoke waitid() with P_PID + WNOHANG for each PID we wait + * for, instead of using P_ALL. This is because we only want to get child information of very + * specific child processes, and not all of them. We might not have processed the SIGCHLD event + * of a previous invocation and we don't want to maintain a unbounded *per-child* event queue, + * hence we really don't want anything flushed out of the kernel's queue that we don't care + * about. Since this is O(n) this means that if you have a lot of processes you probably want + * to handle SIGCHLD yourself. + * + * We do not reap the children here (by using WNOWAIT), this is only done after the event + * source is dispatched so that the callback still sees the process as a zombie. */ HASHMAP_FOREACH(s, e->child_sources) { assert(s->type == SOURCE_CHILD); @@ -3255,7 +3266,9 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori if (s->child.exited) continue; - if (EVENT_SOURCE_WATCH_PIDFD(s)) /* There's a usable pidfd known for this event source? then don't waitid() for it here */ + if (EVENT_SOURCE_WATCH_PIDFD(s)) + /* There's a usable pidfd known for this event source? Then don't waitid() for + * it here */ continue; zero(s->child.siginfo); @@ -3270,10 +3283,9 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori s->child.exited = true; if (!zombie && (s->child.options & WEXITED)) { - /* If the child isn't dead then let's - * immediately remove the state change - * from the queue, since there's no - * benefit in leaving it queued */ + /* If the child isn't dead then let's immediately remove the state + * change from the queue, since there's no benefit in leaving it + * queued. */ assert(s->child.options & (WSTOPPED|WCONTINUED)); (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED))); @@ -3328,19 +3340,16 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events, i assert_return(events == EPOLLIN, -EIO); assert(min_priority); - /* If there's a signal queued on this priority and SIGCHLD is - on this priority too, then make sure to recheck the - children we watch. This is because we only ever dequeue - the first signal per priority, and if we dequeue one, and - SIGCHLD might be enqueued later we wouldn't know, but we - might have higher priority children we care about hence we - need to check that explicitly. */ + /* If there's a signal queued on this priority and SIGCHLD is on this priority too, then make + * sure to recheck the children we watch. This is because we only ever dequeue the first signal + * per priority, and if we dequeue one, and SIGCHLD might be enqueued later we wouldn't know, + * but we might have higher priority children we care about hence we need to check that + * explicitly. */ if (sigismember(&d->sigset, SIGCHLD)) e->need_process_child = true; - /* If there's already an event source pending for this - * priority we don't read another */ + /* If there's already an event source pending for this priority we don't read another */ if (d->current) return 0; @@ -3413,7 +3422,7 @@ static int event_inotify_data_read(sd_event *e, struct inotify_data *d, uint32_t assert(n > 0); d->buffer_filled = (size_t) n; - LIST_PREPEND(buffered, e->inotify_data_buffered, d); + LIST_PREPEND(buffered, e->buffered_inotify_data_list, d); return 1; } @@ -3431,7 +3440,7 @@ static void event_inotify_data_drop(sd_event *e, struct inotify_data *d, size_t d->buffer_filled -= sz; if (d->buffer_filled == 0) - LIST_REMOVE(buffered, e->inotify_data_buffered, d); + LIST_REMOVE(buffered, e->buffered_inotify_data_list, d); } static int event_inotify_data_process(sd_event *e, struct inotify_data *d) { @@ -3524,7 +3533,7 @@ static int process_inotify(sd_event *e) { assert(e); - LIST_FOREACH(buffered, d, e->inotify_data_buffered) { + LIST_FOREACH(buffered, d, e->buffered_inotify_data_list) { r = event_inotify_data_process(e, d); if (r < 0) return r; @@ -3536,8 +3545,8 @@ static int process_inotify(sd_event *e) { } static int source_dispatch(sd_event_source *s) { - _cleanup_(sd_event_unrefp) sd_event *saved_event = NULL; EventSourceType saved_type; + sd_event *saved_event; int r = 0; assert(s); @@ -3549,7 +3558,8 @@ static int source_dispatch(sd_event_source *s) { /* Similarly, store a reference to the event loop object, so that we can still access it after the * callback might have invalidated/disconnected the event source. */ - saved_event = sd_event_ref(s->event); + saved_event = s->event; + PROTECT_EVENT(saved_event); /* Check if we hit the ratelimit for this event source, and if so, let's disable it. */ assert(!s->ratelimited); @@ -3750,7 +3760,7 @@ static int dispatch_exit(sd_event *e) { return 0; } - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + PROTECT_EVENT(e); e->iteration++; e->state = SD_EVENT_EXITING; r = source_dispatch(p); @@ -3821,11 +3831,11 @@ static void event_close_inode_data_fds(sd_event *e) { * for the inode). Hence, let's close them when entering the first iteration after they were added, as a * compromise. */ - while ((d = e->inode_data_to_close)) { + while ((d = e->inode_data_to_close_list)) { assert(d->fd >= 0); d->fd = safe_close(d->fd); - LIST_REMOVE(to_close, e->inode_data_to_close, d); + LIST_REMOVE(to_close, e->inode_data_to_close_list, d); } } @@ -3844,7 +3854,7 @@ _public_ int sd_event_prepare(sd_event *e) { assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO); /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */ - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + PROTECT_EVENT(e); if (e->exit_requested) goto pending; @@ -3879,7 +3889,7 @@ _public_ int sd_event_prepare(sd_event *e) { event_close_inode_data_fds(e); - if (event_next_pending(e) || e->need_process_child) + if (event_next_pending(e) || e->need_process_child || e->buffered_inotify_data_list) goto pending; e->state = SD_EVENT_ARMED; @@ -3959,7 +3969,7 @@ static int process_epoll(sd_event *e, usec_t timeout, int64_t threshold, int64_t n_event_max = MALLOC_ELEMENTSOF(e->event_queue); /* If we still have inotify data buffered, then query the other fds, but don't wait on it */ - if (e->inotify_data_buffered) + if (e->buffered_inotify_data_list) timeout = 0; for (;;) { @@ -4174,7 +4184,7 @@ _public_ int sd_event_dispatch(sd_event *e) { p = event_next_pending(e); if (p) { - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + PROTECT_EVENT(e); e->state = SD_EVENT_RUNNING; r = source_dispatch(p); @@ -4226,7 +4236,7 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { } /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */ - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + PROTECT_EVENT(e); r = sd_event_prepare(e); if (r == 0) @@ -4256,7 +4266,7 @@ _public_ int sd_event_loop(sd_event *e) { assert_return(!event_pid_changed(e), -ECHILD); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + PROTECT_EVENT(e); while (e->state != SD_EVENT_FINISHED) { r = sd_event_run(e, UINT64_MAX); diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c index f1a3a42e..66247fd1 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c @@ -28,9 +28,9 @@ bool id128_is_valid(const char *s) { for (i = 0; i < l; i++) { char c = s[i]; - if (!(c >= '0' && c <= '9') && - !(c >= 'a' && c <= 'z') && - !(c >= 'A' && c <= 'Z')) + if (!ascii_isdigit(c) && + !(c >= 'a' && c <= 'f') && + !(c >= 'A' && c <= 'F')) return false; } @@ -45,9 +45,9 @@ bool id128_is_valid(const char *s) { if (c != '-') return false; } else { - if (!(c >= '0' && c <= '9') && - !(c >= 'a' && c <= 'z') && - !(c >= 'A' && c <= 'Z')) + if (!ascii_isdigit(c) && + !(c >= 'a' && c <= 'f') && + !(c >= 'A' && c <= 'F')) return false; } } @@ -211,20 +211,4 @@ int id128_get_product(sd_id128_t *ret) { *ret = uuid; return 0; } - -int id128_equal_string(const char *s, sd_id128_t id) { - sd_id128_t parsed; - int r; - - if (!s) - return false; - - /* Checks if the specified string matches a valid string representation of the specified 128 bit ID/uuid */ - - r = sd_id128_from_string(s, &parsed); - if (r < 0) - return r; - - return sd_id128_equal(parsed, id); -} #endif /* NM_IGNORED */ diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h index 65a278c8..17b180c1 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h +++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h @@ -34,5 +34,3 @@ extern const struct hash_ops id128_hash_ops; sd_id128_t id128_make_v4_uuid(sd_id128_t id); int id128_get_product(sd_id128_t *ret); - -int id128_equal_string(const char *s, sd_id128_t id); diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c b/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c index 8e47e26e..b7d7788c 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c @@ -105,6 +105,22 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) { return 0; } +_public_ int sd_id128_string_equal(const char *s, sd_id128_t id) { + sd_id128_t parsed; + int r; + + if (!s) + return false; + + /* Checks if the specified string matches a valid string representation of the specified 128 bit ID/uuid */ + + r = sd_id128_from_string(s, &parsed); + if (r < 0) + return r; + + return sd_id128_equal(parsed, id); +} + _public_ int sd_id128_get_machine(sd_id128_t *ret) { static thread_local sd_id128_t saved_machine_id = {}; int r; @@ -261,7 +277,10 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) { /* We first check the environment. The environment variable is primarily relevant for user * services, and sufficiently safe as long as no privilege boundary is involved. */ r = get_invocation_from_environment(&saved_invocation_id); - if (r < 0 && r != -ENXIO) + if (r >= 0) { + *ret = saved_invocation_id; + return 0; + } else if (r != -ENXIO) return r; /* The kernel keyring is relevant for system services (as for user services we don't store @@ -277,13 +296,10 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) { _public_ int sd_id128_randomize(sd_id128_t *ret) { sd_id128_t t; - int r; assert_return(ret, -EINVAL); - r = genuine_random_bytes(&t, sizeof(t), 0); - if (r < 0) - return r; + random_bytes(&t, sizeof(t)); /* Turn this into a valid v4 UUID, to be nice. Note that we * only guarantee this for newly generated UUIDs, not for diff --git a/src/libnm-systemd-core/src/systemd/_sd-common.h b/src/libnm-systemd-core/src/systemd/_sd-common.h index e1214296..6f657c22 100644 --- a/src/libnm-systemd-core/src/systemd/_sd-common.h +++ b/src/libnm-systemd-core/src/systemd/_sd-common.h @@ -14,7 +14,7 @@ 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 . + along with systemd; If not, see . ***/ /* This is a private header; never even think of including this directly! */ @@ -85,7 +85,7 @@ typedef void (*_sd_destroy_t)(void *userdata); #endif #ifndef _SD_ARRAY_STATIC -# if __STDC_VERSION__ >= 199901L +# if __STDC_VERSION__ >= 199901L && !defined(__cplusplus) # define _SD_ARRAY_STATIC static # else # define _SD_ARRAY_STATIC 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 834f80b4..00000000 --- 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 . -***/ - -#include -#include -#include -#include -#include - -#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 578ac6d4..00000000 --- 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 . -***/ - -#include -#include -#include -#include -#include - -#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 71aa479b..00000000 --- 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 . -***/ - -#include -#include - -#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-core/src/systemd/sd-dhcp6-client.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h index d89b7d1c..2c66c51b 100644 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h +++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h @@ -16,7 +16,7 @@ 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 . + along with systemd; If not, see . ***/ #include @@ -36,7 +36,7 @@ enum { SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE = 10, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX = 11, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE = 12, - SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13, + SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13 }; /* https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-2 */ @@ -63,15 +63,15 @@ enum { SD_DHCP6_OPTION_RECONF_ACCEPT = 20, /* RFC 8415 */ SD_DHCP6_OPTION_SIP_SERVER_DOMAIN_NAME = 21, /* RFC 3319 */ SD_DHCP6_OPTION_SIP_SERVER_ADDRESS = 22, /* RFC 3319 */ - SD_DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */ - SD_DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */ + SD_DHCP6_OPTION_DNS_SERVER = 23, /* RFC 3646 */ + SD_DHCP6_OPTION_DOMAIN = 24, /* RFC 3646 */ SD_DHCP6_OPTION_IA_PD = 25, /* RFC 3633, RFC 8415 */ SD_DHCP6_OPTION_IA_PD_PREFIX = 26, /* RFC 3633, RFC 8415 */ - SD_DHCP6_OPTION_NIS_SERVERS = 27, /* RFC 3898 */ - SD_DHCP6_OPTION_NISP_SERVERS = 28, /* RFC 3898 */ + SD_DHCP6_OPTION_NIS_SERVER = 27, /* RFC 3898 */ + SD_DHCP6_OPTION_NISP_SERVER = 28, /* RFC 3898 */ SD_DHCP6_OPTION_NIS_DOMAIN_NAME = 29, /* RFC 3898 */ SD_DHCP6_OPTION_NISP_DOMAIN_NAME = 30, /* RFC 3898 */ - SD_DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075, deprecated */ + SD_DHCP6_OPTION_SNTP_SERVER = 31, /* RFC 4075, deprecated */ SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME = 32, /* RFC 4242, 8415, sec. 21.23 */ SD_DHCP6_OPTION_BCMCS_SERVER_D = 33, /* RFC 4280 */ SD_DHCP6_OPTION_BCMCS_SERVER_A = 34, /* RFC 4280 */ @@ -183,7 +183,7 @@ enum { SD_DHCP6_OPTION_SLAP_QUAD = 140, /* RFC 8948 */ SD_DHCP6_OPTION_V6_DOTS_RI = 141, /* RFC 8973 */ SD_DHCP6_OPTION_V6_DOTS_ADDRESS = 142, /* RFC 8973 */ - SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF = 143, /* RFC 6153 */ + SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF = 143 /* RFC 6153 */ /* option codes 144-65535 are unassigned */ }; @@ -262,6 +262,7 @@ int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request); int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client *client, sd_dhcp6_option *v); +int sd_dhcp6_client_set_rapid_commit(sd_dhcp6_client *client, int enable); int sd_dhcp6_client_get_lease( sd_dhcp6_client *client, diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h index 472276de..716f6fc1 100644 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h +++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h @@ -16,7 +16,7 @@ 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 . + along with systemd; If not, see . ***/ #include diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h index ddb2c7ce..b4b4671e 100644 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h +++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h @@ -14,7 +14,7 @@ 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 . + along with systemd; If not, see . ***/ #include diff --git a/src/libnm-systemd-core/src/systemd/sd-event.h b/src/libnm-systemd-core/src/systemd/sd-event.h index 63984eef..e782339c 100644 --- a/src/libnm-systemd-core/src/systemd/sd-event.h +++ b/src/libnm-systemd-core/src/systemd/sd-event.h @@ -14,7 +14,7 @@ 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 . + along with systemd; If not, see . ***/ #include diff --git a/src/libnm-systemd-core/src/systemd/sd-id128.h b/src/libnm-systemd-core/src/systemd/sd-id128.h index f7d3244b..3303c374 100644 --- a/src/libnm-systemd-core/src/systemd/sd-id128.h +++ b/src/libnm-systemd-core/src/systemd/sd-id128.h @@ -14,7 +14,7 @@ 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 . + along with systemd; If not, see . ***/ #include @@ -116,9 +116,11 @@ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret); #a #b #c #d "-" #e #f "-" #g #h "-" #i #j "-" #k #l #m #n #o #p _sd_pure_ static __inline__ int sd_id128_equal(sd_id128_t a, sd_id128_t b) { - return memcmp(&a, &b, 16) == 0; + return a.qwords[0] == b.qwords[0] && a.qwords[1] == b.qwords[1]; } +int sd_id128_string_equal(const char *s, sd_id128_t id); + _sd_pure_ static __inline__ int sd_id128_is_null(sd_id128_t a) { return a.qwords[0] == 0 && a.qwords[1] == 0; } diff --git a/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h b/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h index bfeac14c..504d7f59 100644 --- a/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h +++ b/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h @@ -14,7 +14,7 @@ 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 . + along with systemd; If not, see . ***/ #include @@ -32,14 +32,14 @@ _SD_BEGIN_DECLARATIONS; typedef struct sd_lldp_rx sd_lldp_rx; typedef struct sd_lldp_neighbor sd_lldp_neighbor; -typedef enum sd_lldp_rx_event_t { +__extension__ typedef enum sd_lldp_rx_event_t { SD_LLDP_RX_EVENT_ADDED, SD_LLDP_RX_EVENT_REMOVED, SD_LLDP_RX_EVENT_UPDATED, SD_LLDP_RX_EVENT_REFRESHED, _SD_LLDP_RX_EVENT_MAX, _SD_LLDP_RX_EVENT_INVALID = -EINVAL, - _SD_ENUM_FORCE_S64(LLDP_RX_EVENT), + _SD_ENUM_FORCE_S64(LLDP_RX_EVENT) } sd_lldp_rx_event_t; typedef void (*sd_lldp_rx_callback_t)(sd_lldp_rx *lldp_rx, sd_lldp_rx_event_t event, sd_lldp_neighbor *n, void *userdata); diff --git a/src/libnm-systemd-core/src/systemd/sd-lldp.h b/src/libnm-systemd-core/src/systemd/sd-lldp.h index c32d7894..4069c5b2 100644 --- a/src/libnm-systemd-core/src/systemd/sd-lldp.h +++ b/src/libnm-systemd-core/src/systemd/sd-lldp.h @@ -14,7 +14,7 @@ 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 . + along with systemd; If not, see . ***/ #include @@ -34,7 +34,7 @@ enum { SD_LLDP_TYPE_SYSTEM_DESCRIPTION = 6, SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7, SD_LLDP_TYPE_MGMT_ADDRESS = 8, - SD_LLDP_TYPE_PRIVATE = 127, + SD_LLDP_TYPE_PRIVATE = 127 }; /* IEEE 802.1AB-2009 Clause 8.5.2: Chassis subtypes */ @@ -46,7 +46,7 @@ enum { SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4, SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5, SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6, - SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7, + SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7 }; /* IEEE 802.1AB-2009 Clause 8.5.3: Port subtype */ @@ -58,7 +58,7 @@ enum { SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4, SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5, SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6, - SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7, + SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7 }; /* IEEE 802.1AB-2009 Clause 8.5.8: System capabilities */ @@ -73,7 +73,7 @@ enum { SD_LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7, SD_LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8, SD_LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9, - SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10, + SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10 }; #define SD_LLDP_SYSTEM_CAPABILITIES_ALL UINT16_MAX @@ -107,7 +107,7 @@ enum { SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4, SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5, SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6, - SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7, + SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7 }; /* IEEE 802.1AB-2009 Annex F */ @@ -115,7 +115,7 @@ enum { SD_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS = 1, SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI = 2, SD_LLDP_OUI_802_3_SUBTYPE_LINK_AGGREGATION = 3, - SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE = 4, + SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE = 4 }; _SD_END_DECLARATIONS; diff --git a/src/libnm-systemd-core/src/systemd/sd-ndisc.h b/src/libnm-systemd-core/src/systemd/sd-ndisc.h index ab9ff55d..ee309a42 100644 --- a/src/libnm-systemd-core/src/systemd/sd-ndisc.h +++ b/src/libnm-systemd-core/src/systemd/sd-ndisc.h @@ -16,7 +16,7 @@ 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 . + along with systemd; If not, see . ***/ #include @@ -42,25 +42,25 @@ enum { SD_NDISC_OPTION_RDNSS = 25, SD_NDISC_OPTION_FLAGS_EXTENSION = 26, SD_NDISC_OPTION_DNSSL = 31, - SD_NDISC_OPTION_CAPTIVE_PORTAL = 37, + SD_NDISC_OPTION_CAPTIVE_PORTAL = 37 }; /* Route preference, RFC 4191, Section 2.1 */ enum { SD_NDISC_PREFERENCE_LOW = 3U, SD_NDISC_PREFERENCE_MEDIUM = 0U, - SD_NDISC_PREFERENCE_HIGH = 1U, + SD_NDISC_PREFERENCE_HIGH = 1U }; typedef struct sd_ndisc sd_ndisc; typedef struct sd_ndisc_router sd_ndisc_router; -typedef enum sd_ndisc_event_t { +__extension__ typedef enum sd_ndisc_event_t { SD_NDISC_EVENT_TIMEOUT, SD_NDISC_EVENT_ROUTER, _SD_NDISC_EVENT_MAX, _SD_NDISC_EVENT_INVALID = -EINVAL, - _SD_ENUM_FORCE_S64(NDISC_EVENT), + _SD_ENUM_FORCE_S64(NDISC_EVENT) } sd_ndisc_event_t; typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata); @@ -82,7 +82,6 @@ int sd_ndisc_set_ifname(sd_ndisc *nd, const char *interface_name); int sd_ndisc_get_ifname(sd_ndisc *nd, const char **ret); int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); -int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size); sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt); sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt); diff --git a/src/libnm-systemd-shared/meson.build b/src/libnm-systemd-shared/meson.build index 05c81faf..d8e7a31a 100644 --- a/src/libnm-systemd-shared/meson.build +++ b/src/libnm-systemd-shared/meson.build @@ -14,6 +14,7 @@ libnm_systemd_shared = static_library( 'src/basic/fileio.c', 'src/basic/format-util.c', 'src/basic/fs-util.c', + 'src/basic/glyph-util.c', 'src/basic/hash-funcs.c', 'src/basic/hashmap.c', 'src/basic/hexdecoct.c', @@ -21,6 +22,7 @@ libnm_systemd_shared = static_library( 'src/basic/in-addr-util.c', 'src/basic/inotify-util.c', 'src/basic/io-util.c', + 'src/basic/locale-util.c', 'src/basic/memory-util.c', 'src/basic/mempool.c', 'src/basic/ordered-set.c', @@ -41,6 +43,7 @@ libnm_systemd_shared = static_library( 'src/basic/tmpfile-util.c', 'src/basic/utf8.c', 'src/basic/util.c', + 'src/fundamental/sha256.c', 'src/fundamental/string-util-fundamental.c', 'src/shared/dns-domain.c', 'src/shared/web-util.c', diff --git a/src/libnm-systemd-shared/nm-sd-utils-shared.c b/src/libnm-systemd-shared/nm-sd-utils-shared.c index 0a35016a..dad21596 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 82a50678..fefb8a1c 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/libnm-systemd-shared/sd-adapt-shared/locale-util.h b/src/libnm-systemd-shared/sd-adapt-shared/locale-util.h deleted file mode 100644 index 637892c2..00000000 --- a/src/libnm-systemd-shared/sd-adapt-shared/locale-util.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h b/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h index 586c3a7e..ee5a0a24 100644 --- a/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h +++ b/src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h @@ -51,8 +51,12 @@ #define LOG_TRACE 0 +#define WANT_LINUX_FS_H 0 + #define BUILD_MODE_DEVELOPER (NM_MORE_ASSERTS > 0) +#define LOG_MESSAGE_VERIFICATION (NM_MORE_ASSERTS > 0) + /*****************************************************************************/ /* systemd cannot be compiled with "-Wdeclaration-after-statement". In particular diff --git a/src/libnm-systemd-shared/src/basic/alloc-util.h b/src/libnm-systemd-shared/src/basic/alloc-util.h index 9dde770d..b38db7d4 100644 --- a/src/libnm-systemd-shared/src/basic/alloc-util.h +++ b/src/libnm-systemd-shared/src/basic/alloc-util.h @@ -50,16 +50,30 @@ typedef void* (*mfree_func_t)(void *p); #define malloc0(n) (calloc(1, (n) ?: 1)) -#define free_and_replace(a, b) \ +#define free_and_replace_full(a, b, free_func) \ ({ \ typeof(a)* _a = &(a); \ typeof(b)* _b = &(b); \ - free(*_a); \ - (*_a) = (*_b); \ - (*_b) = NULL; \ + free_func(*_a); \ + *_a = *_b; \ + *_b = NULL; \ 0; \ }) +#define free_and_replace(a, b) \ + free_and_replace_full(a, b, free) + +/* This is similar to free_and_replace_full(), but NULL is not assigned to 'b', and its reference counter is + * increased. */ +#define unref_and_replace_full(a, b, ref_func, unref_func) \ + ({ \ + typeof(a)* _a = &(a); \ + typeof(b) _b = ref_func(b); \ + unref_func(*_a); \ + *_a = _b; \ + 0; \ + }) + void* memdup(const void *p, size_t l) _alloc_(2); void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, since we return a buffer one byte larger than the specified size */ @@ -174,23 +188,13 @@ void* greedy_realloc0(void **p, size_t need, size_t size); * is compatible with _FORTIFY_SOURCES. If _FORTIFY_SOURCES is used many memory operations will take the * object size as returned by __builtin_object_size() into account. Hence, let's return the smaller size of * malloc_usable_size() and __builtin_object_size() here, so that we definitely operate in safe territory by - * both the compiler's and libc's standards. Note that _FORTIFY_SOURCES=3 handles also dynamically allocated - * objects and thus it's safer using __builtin_dynamic_object_size if _FORTIFY_SOURCES=3 is used (#22801). - * Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and + * both the compiler's and libc's standards. Note that __builtin_object_size() evaluates to SIZE_MAX if the + * size cannot be determined, hence the MIN() expression should be safe with dynamically sized memory, + * too. Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and * __builtin_object_size() returns SIZE_MAX too, hence we also return a sensible value of 0 in this corner * case. */ - -#if defined __has_builtin -# if __has_builtin(__builtin_dynamic_object_size) -# define MALLOC_SIZEOF_SAFE(x) \ - MIN(malloc_usable_size(x), __builtin_dynamic_object_size(x, 0)) -# endif -#endif - -#ifndef MALLOC_SIZEOF_SAFE #define MALLOC_SIZEOF_SAFE(x) \ MIN(malloc_usable_size(x), __builtin_object_size(x, 0)) -#endif /* Inspired by ELEMENTSOF() but operates on malloc()'ed memory areas: typesafely returns the number of items * that fit into the specified memory block */ diff --git a/src/libnm-systemd-shared/src/basic/env-util.c b/src/libnm-systemd-shared/src/basic/env-util.c index b4ac6811..e869fad1 100644 --- a/src/libnm-systemd-shared/src/basic/env-util.c +++ b/src/libnm-systemd-shared/src/basic/env-util.c @@ -35,7 +35,7 @@ static bool env_name_is_valid_n(const char *e, size_t n) { if (n <= 0) return false; - if (e[0] >= '0' && e[0] <= '9') + if (ascii_isdigit(e[0])) return false; /* POSIX says the overall size of the environment block cannot diff --git a/src/libnm-systemd-shared/src/basic/ether-addr-util.c b/src/libnm-systemd-shared/src/basic/ether-addr-util.c index 4504b6be..7984ddf4 100644 --- a/src/libnm-systemd-shared/src/basic/ether-addr-util.c +++ b/src/libnm-systemd-shared/src/basic/ether-addr-util.c @@ -35,6 +35,15 @@ char *hw_addr_to_string_full( return buffer; } +struct hw_addr_data *hw_addr_set(struct hw_addr_data *addr, const uint8_t *bytes, size_t length) { + assert(addr); + assert(length <= HW_ADDR_MAX_SIZE); + + addr->length = length; + memcpy_safe(addr->bytes, bytes, length); + return addr; +} + int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b) { int r; diff --git a/src/libnm-systemd-shared/src/basic/ether-addr-util.h b/src/libnm-systemd-shared/src/basic/ether-addr-util.h index 32f45fe8..83ed77d6 100644 --- a/src/libnm-systemd-shared/src/basic/ether-addr-util.h +++ b/src/libnm-systemd-shared/src/basic/ether-addr-util.h @@ -52,6 +52,8 @@ static inline char *hw_addr_to_string(const struct hw_addr_data *addr, char buff #define HW_ADDR_NULL ((const struct hw_addr_data){}) +struct hw_addr_data *hw_addr_set(struct hw_addr_data *addr, const uint8_t *bytes, size_t length); + void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *state); int hw_addr_compare(const struct hw_addr_data *a, const struct hw_addr_data *b); static inline bool hw_addr_equal(const struct hw_addr_data *a, const struct hw_addr_data *b) { diff --git a/src/libnm-systemd-shared/src/basic/fd-util.c b/src/libnm-systemd-shared/src/basic/fd-util.c index 53efeb40..80295445 100644 --- a/src/libnm-systemd-shared/src/basic/fd-util.c +++ b/src/libnm-systemd-shared/src/basic/fd-util.c @@ -5,7 +5,9 @@ #include #include #include +#if WANT_LINUX_FS_H #include +#endif #include #include #include diff --git a/src/libnm-systemd-shared/src/basic/fileio.c b/src/libnm-systemd-shared/src/basic/fileio.c index 0ad8ae03..d996bc02 100644 --- a/src/libnm-systemd-shared/src/basic/fileio.c +++ b/src/libnm-systemd-shared/src/basic/fileio.c @@ -767,8 +767,7 @@ int read_full_file_full( r = xfopenat(dir_fd, filename, "re", 0, &f); if (r < 0) { - _cleanup_close_ int dfd = -1, sk = -1; - union sockaddr_union sa; + _cleanup_close_ int sk = -1; /* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */ if (r != -ENXIO) @@ -780,23 +779,7 @@ int read_full_file_full( /* Seeking is not supported on AF_UNIX sockets */ if (offset != UINT64_MAX) - return -ESPIPE; - - if (dir_fd == AT_FDCWD) - r = sockaddr_un_set_path(&sa.un, filename); - else { - /* If we shall operate relative to some directory, then let's use O_PATH first to - * open the socket inode, and then connect to it via /proc/self/fd/. We have to do - * this since there's not connectat() that takes a directory fd as first arg. */ - - dfd = openat(dir_fd, filename, O_PATH|O_CLOEXEC); - if (dfd < 0) - return -errno; - - r = sockaddr_un_set_path(&sa.un, FORMAT_PROC_FD_PATH(dfd)); - } - if (r < 0) - return r; + return -ENXIO; sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); if (sk < 0) @@ -813,12 +796,14 @@ int read_full_file_full( return r; if (bind(sk, &bsa.sa, r) < 0) - return r; + return -errno; } - if (connect(sk, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) - return errno == ENOTSOCK ? -ENXIO : -errno; /* propagate original error if this is - * not a socket after all */ + r = connect_unix_path(sk, dir_fd, filename); + if (IN_SET(r, -ENOTSOCK, -EINVAL)) /* propagate original error if this is not a socket after all */ + return -ENXIO; + if (r < 0) + return r; if (shutdown(sk, SHUT_WR) < 0) return -errno; diff --git a/src/libnm-systemd-shared/src/basic/fs-util.c b/src/libnm-systemd-shared/src/basic/fs-util.c index dccfb27b..1a951bd5 100644 --- a/src/libnm-systemd-shared/src/basic/fs-util.c +++ b/src/libnm-systemd-shared/src/basic/fs-util.c @@ -160,24 +160,23 @@ int readlink_malloc(const char *p, char **ret) { #if 0 /* NM_IGNORED */ int readlink_value(const char *p, char **ret) { - _cleanup_free_ char *link = NULL; - char *value; + _cleanup_free_ char *link = NULL, *name = NULL; int r; + assert(p); + assert(ret); + r = readlink_malloc(p, &link); if (r < 0) return r; - value = basename(link); - if (!value) - return -ENOENT; - - value = strdup(value); - if (!value) - return -ENOMEM; - - *ret = value; + r = path_extract_filename(link, &name); + if (r < 0) + return r; + if (r == O_DIRECTORY) + return -EINVAL; + *ret = TAKE_PTR(name); return 0; } diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.c b/src/libnm-systemd-shared/src/basic/glyph-util.c new file mode 100644 index 00000000..ec851e8b --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/glyph-util.c @@ -0,0 +1,139 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "nm-sd-adapt-shared.h" + +#include "env-util.h" +#include "glyph-util.h" +#include "locale-util.h" +#include "strv.h" + +bool emoji_enabled(void) { + static int cached_emoji_enabled = -1; + + if (cached_emoji_enabled < 0) { + int val; + + val = getenv_bool("SYSTEMD_EMOJI"); + if (val < 0) + cached_emoji_enabled = + is_locale_utf8() && + !STRPTR_IN_SET(getenv("TERM"), "dumb", "linux"); + else + cached_emoji_enabled = val; + } + + return cached_emoji_enabled; +} + +const char *special_glyph(SpecialGlyph code) { + + /* A list of a number of interesting unicode glyphs we can use to decorate our output. It's probably wise to be + * conservative here, and primarily stick to the glyphs defined in the eurlatgr font, so that display still + * works reasonably well on the Linux console. For details see: + * + * http://git.altlinux.org/people/legion/packages/kbd.git?p=kbd.git;a=blob;f=data/consolefonts/README.eurlatgr + */ + + static const char* const draw_table[2][_SPECIAL_GLYPH_MAX] = { + /* ASCII fallback */ + [false] = { + [SPECIAL_GLYPH_TREE_VERTICAL] = "| ", + [SPECIAL_GLYPH_TREE_BRANCH] = "|-", + [SPECIAL_GLYPH_TREE_RIGHT] = "`-", + [SPECIAL_GLYPH_TREE_SPACE] = " ", + [SPECIAL_GLYPH_TREE_TOP] = ",-", + [SPECIAL_GLYPH_VERTICAL_DOTTED] = ":", + [SPECIAL_GLYPH_TRIANGULAR_BULLET] = ">", + [SPECIAL_GLYPH_BLACK_CIRCLE] = "*", + [SPECIAL_GLYPH_WHITE_CIRCLE] = "*", + [SPECIAL_GLYPH_MULTIPLICATION_SIGN] = "x", + [SPECIAL_GLYPH_CIRCLE_ARROW] = "*", + [SPECIAL_GLYPH_BULLET] = "*", + [SPECIAL_GLYPH_MU] = "u", + [SPECIAL_GLYPH_CHECK_MARK] = "+", + [SPECIAL_GLYPH_CROSS_MARK] = "-", + [SPECIAL_GLYPH_LIGHT_SHADE] = "-", + [SPECIAL_GLYPH_DARK_SHADE] = "X", + [SPECIAL_GLYPH_SIGMA] = "S", + [SPECIAL_GLYPH_ARROW_RIGHT] = "->", + [SPECIAL_GLYPH_ARROW_UP] = "^", + [SPECIAL_GLYPH_ARROW_DOWN] = "v", + [SPECIAL_GLYPH_ELLIPSIS] = "...", + [SPECIAL_GLYPH_EXTERNAL_LINK] = "[LNK]", + [SPECIAL_GLYPH_ECSTATIC_SMILEY] = ":-]", + [SPECIAL_GLYPH_HAPPY_SMILEY] = ":-}", + [SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY] = ":-)", + [SPECIAL_GLYPH_NEUTRAL_SMILEY] = ":-|", + [SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY] = ":-(", + [SPECIAL_GLYPH_UNHAPPY_SMILEY] = ":-{", + [SPECIAL_GLYPH_DEPRESSED_SMILEY] = ":-[", + [SPECIAL_GLYPH_LOCK_AND_KEY] = "o-,", + [SPECIAL_GLYPH_TOUCH] = "O=", /* Yeah, not very convincing, can you do it better? */ + [SPECIAL_GLYPH_RECYCLING] = "~", + [SPECIAL_GLYPH_DOWNLOAD] = "\\", + [SPECIAL_GLYPH_SPARKLES] = "*", + }, + + /* UTF-8 */ + [true] = { + /* The following are multiple glyphs in both ASCII and in UNICODE */ + [SPECIAL_GLYPH_TREE_VERTICAL] = u8"│ ", + [SPECIAL_GLYPH_TREE_BRANCH] = u8"├─", + [SPECIAL_GLYPH_TREE_RIGHT] = u8"└─", + [SPECIAL_GLYPH_TREE_SPACE] = u8" ", + [SPECIAL_GLYPH_TREE_TOP] = u8"┌─", + + /* Single glyphs in both cases */ + [SPECIAL_GLYPH_VERTICAL_DOTTED] = u8"┆", + [SPECIAL_GLYPH_TRIANGULAR_BULLET] = u8"‣", + [SPECIAL_GLYPH_BLACK_CIRCLE] = u8"●", + [SPECIAL_GLYPH_WHITE_CIRCLE] = u8"○", + [SPECIAL_GLYPH_MULTIPLICATION_SIGN] = u8"×", + [SPECIAL_GLYPH_CIRCLE_ARROW] = u8"↻", + [SPECIAL_GLYPH_BULLET] = u8"•", + [SPECIAL_GLYPH_MU] = u8"μ", /* actually called: GREEK SMALL LETTER MU */ + [SPECIAL_GLYPH_CHECK_MARK] = u8"✓", + [SPECIAL_GLYPH_CROSS_MARK] = u8"✗", /* actually called: BALLOT X */ + [SPECIAL_GLYPH_LIGHT_SHADE] = u8"░", + [SPECIAL_GLYPH_DARK_SHADE] = u8"▒", + [SPECIAL_GLYPH_SIGMA] = u8"Σ", + [SPECIAL_GLYPH_ARROW_UP] = u8"↑", /* actually called: UPWARDS ARROW */ + [SPECIAL_GLYPH_ARROW_DOWN] = u8"↓", /* actually called: DOWNWARDS ARROW */ + + /* Single glyph in Unicode, two in ASCII */ + [SPECIAL_GLYPH_ARROW_RIGHT] = u8"→", /* actually called: RIGHTWARDS ARROW */ + + /* Single glyph in Unicode, three in ASCII */ + [SPECIAL_GLYPH_ELLIPSIS] = u8"…", /* actually called: HORIZONTAL ELLIPSIS */ + + /* Three glyphs in Unicode, five in ASCII */ + [SPECIAL_GLYPH_EXTERNAL_LINK] = u8"[🡕]", /* actually called: NORTH EAST SANS-SERIF ARROW, enclosed in [] */ + + /* These smileys are a single glyph in Unicode, and three in ASCII */ + [SPECIAL_GLYPH_ECSTATIC_SMILEY] = u8"😇", /* actually called: SMILING FACE WITH HALO */ + [SPECIAL_GLYPH_HAPPY_SMILEY] = u8"😀", /* actually called: GRINNING FACE */ + [SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY] = u8"🙂", /* actually called: SLIGHTLY SMILING FACE */ + [SPECIAL_GLYPH_NEUTRAL_SMILEY] = u8"😐", /* actually called: NEUTRAL FACE */ + [SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY] = u8"🙁", /* actually called: SLIGHTLY FROWNING FACE */ + [SPECIAL_GLYPH_UNHAPPY_SMILEY] = u8"😨", /* actually called: FEARFUL FACE */ + [SPECIAL_GLYPH_DEPRESSED_SMILEY] = u8"🤢", /* actually called: NAUSEATED FACE */ + + /* This emoji is a single character cell glyph in Unicode, and three in ASCII */ + [SPECIAL_GLYPH_LOCK_AND_KEY] = u8"🔐", /* actually called: CLOSED LOCK WITH KEY */ + + /* This emoji is a single character cell glyph in Unicode, and two in ASCII */ + [SPECIAL_GLYPH_TOUCH] = u8"👆", /* actually called: BACKHAND INDEX POINTING UP */ + + /* These three emojis are single character cell glyphs in Unicode and also in ASCII. */ + [SPECIAL_GLYPH_RECYCLING] = u8"♻️", /* actually called: UNIVERSAL RECYCLNG SYMBOL */ + [SPECIAL_GLYPH_DOWNLOAD] = u8"⤵️", /* actually called: RIGHT ARROW CURVING DOWN */ + [SPECIAL_GLYPH_SPARKLES] = u8"✨", + }, + }; + + if (code < 0) + return NULL; + + assert(code < _SPECIAL_GLYPH_MAX); + return draw_table[code >= _SPECIAL_GLYPH_FIRST_EMOJI ? emoji_enabled() : is_locale_utf8()][code]; +} diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.h b/src/libnm-systemd-shared/src/basic/glyph-util.h new file mode 100644 index 00000000..065dde8a --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/glyph-util.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include +#include + +#include "macro.h" + +typedef enum SpecialGlyph { + SPECIAL_GLYPH_TREE_VERTICAL, + SPECIAL_GLYPH_TREE_BRANCH, + SPECIAL_GLYPH_TREE_RIGHT, + SPECIAL_GLYPH_TREE_SPACE, + SPECIAL_GLYPH_TREE_TOP, + SPECIAL_GLYPH_VERTICAL_DOTTED, + SPECIAL_GLYPH_TRIANGULAR_BULLET, + SPECIAL_GLYPH_BLACK_CIRCLE, + SPECIAL_GLYPH_WHITE_CIRCLE, + SPECIAL_GLYPH_MULTIPLICATION_SIGN, + SPECIAL_GLYPH_CIRCLE_ARROW, + SPECIAL_GLYPH_BULLET, + SPECIAL_GLYPH_MU, + SPECIAL_GLYPH_CHECK_MARK, + SPECIAL_GLYPH_CROSS_MARK, + SPECIAL_GLYPH_ARROW_RIGHT, + SPECIAL_GLYPH_ARROW_UP, + SPECIAL_GLYPH_ARROW_DOWN, + SPECIAL_GLYPH_ELLIPSIS, + SPECIAL_GLYPH_LIGHT_SHADE, + SPECIAL_GLYPH_DARK_SHADE, + SPECIAL_GLYPH_SIGMA, + SPECIAL_GLYPH_EXTERNAL_LINK, + _SPECIAL_GLYPH_FIRST_EMOJI, + SPECIAL_GLYPH_ECSTATIC_SMILEY = _SPECIAL_GLYPH_FIRST_EMOJI, + SPECIAL_GLYPH_HAPPY_SMILEY, + SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY, + SPECIAL_GLYPH_NEUTRAL_SMILEY, + SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY, + SPECIAL_GLYPH_UNHAPPY_SMILEY, + SPECIAL_GLYPH_DEPRESSED_SMILEY, + SPECIAL_GLYPH_LOCK_AND_KEY, + SPECIAL_GLYPH_TOUCH, + SPECIAL_GLYPH_RECYCLING, + SPECIAL_GLYPH_DOWNLOAD, + SPECIAL_GLYPH_SPARKLES, + _SPECIAL_GLYPH_MAX, + _SPECIAL_GLYPH_INVALID = -EINVAL, +} SpecialGlyph; + +const char *special_glyph(SpecialGlyph code) _const_; + +bool emoji_enabled(void); + +static inline const char *special_glyph_check_mark(bool b) { + return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : special_glyph(SPECIAL_GLYPH_CROSS_MARK); +} + +static inline const char *special_glyph_check_mark_space(bool b) { + return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : " "; +} diff --git a/src/libnm-systemd-shared/src/basic/hash-funcs.c b/src/libnm-systemd-shared/src/basic/hash-funcs.c index c1d28ff6..eed30f09 100644 --- a/src/libnm-systemd-shared/src/basic/hash-funcs.c +++ b/src/libnm-systemd-shared/src/basic/hash-funcs.c @@ -6,6 +6,7 @@ #include "hash-funcs.h" #include "path-util.h" +#include "strv.h" void string_hash_func(const char *p, struct siphash *state) { siphash24_compress(p, strlen(p) + 1, state); @@ -17,6 +18,9 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(string_hash_ops_free, DEFINE_HASH_OPS_FULL(string_hash_ops_free_free, char, string_hash_func, string_compare_func, free, void, free); +DEFINE_HASH_OPS_FULL(string_hash_ops_free_strv_free, + char, string_hash_func, string_compare_func, free, + char*, strv_free); #if 0 /* NM_IGNORED */ void path_hash_func(const char *q, struct siphash *state) { @@ -107,11 +111,17 @@ DEFINE_HASH_OPS(uint64_hash_ops, uint64_t, uint64_hash_func, uint64_compare_func void devt_hash_func(const dev_t *p, struct siphash *state) { siphash24_compress(p, sizeof(dev_t), state); } +#endif int devt_compare_func(const dev_t *a, const dev_t *b) { - return CMP(*a, *b); + int r; + + r = CMP(major(*a), major(*b)); + if (r != 0) + return r; + + return CMP(minor(*a), minor(*b)); } DEFINE_HASH_OPS(devt_hash_ops, dev_t, devt_hash_func, devt_compare_func); -#endif #endif /* NM_IGNORED */ diff --git a/src/libnm-systemd-shared/src/basic/hash-funcs.h b/src/libnm-systemd-shared/src/basic/hash-funcs.h index 023cfdf5..c14302ec 100644 --- a/src/libnm-systemd-shared/src/basic/hash-funcs.h +++ b/src/libnm-systemd-shared/src/basic/hash-funcs.h @@ -78,6 +78,7 @@ void string_hash_func(const char *p, struct siphash *state); extern const struct hash_ops string_hash_ops; extern const struct hash_ops string_hash_ops_free; extern const struct hash_ops string_hash_ops_free_free; +extern const struct hash_ops string_hash_ops_free_strv_free; void path_hash_func(const char *p, struct siphash *state); extern const struct hash_ops path_hash_ops; @@ -102,10 +103,9 @@ extern const struct hash_ops uint64_hash_ops; * 64bit archs. Yuck! */ #if SIZEOF_DEV_T != 8 void devt_hash_func(const dev_t *p, struct siphash *state) _pure_; -int devt_compare_func(const dev_t *a, const dev_t *b) _pure_; -extern const struct hash_ops devt_hash_ops; #else #define devt_hash_func uint64_hash_func -#define devt_compare_func uint64_compare_func -#define devt_hash_ops uint64_hash_ops #endif + +int devt_compare_func(const dev_t *a, const dev_t *b) _pure_; +extern const struct hash_ops devt_hash_ops; diff --git a/src/libnm-systemd-shared/src/basic/hashmap.c b/src/libnm-systemd-shared/src/basic/hashmap.c index e7dedc6d..5d0ae6aa 100644 --- a/src/libnm-systemd-shared/src/basic/hashmap.c +++ b/src/libnm-systemd-shared/src/basic/hashmap.c @@ -3,6 +3,7 @@ #include "nm-sd-adapt-shared.h" #include +#include #include #include #include @@ -772,16 +773,15 @@ static void shared_hash_key_initialize(void) { static struct HashmapBase* hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) { HashmapBase *h; const struct hashmap_type_info *hi = &hashmap_type_info[type]; - bool up; - up = mempool_enabled(); + bool use_pool = mempool_enabled && mempool_enabled(); - h = up ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size); + h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size); if (!h) return NULL; h->type = type; - h->from_pool = up; + h->from_pool = use_pool; h->hash_ops = hash_ops ?: &trivial_hash_ops; if (type == HASHMAP_TYPE_ORDERED) { @@ -1845,7 +1845,7 @@ int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const } #endif /* NM_IGNORED */ -int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS) { +int _set_put_strndup_full(Set **s, const struct hash_ops *hash_ops, const char *p, size_t n HASHMAP_DEBUG_PARAMS) { char *c; int r; @@ -1856,10 +1856,13 @@ int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p if (r < 0) return r; - if (set_contains(*s, (char*) p)) - return 0; + if (n == SIZE_MAX) { + if (set_contains(*s, (char*) p)) + return 0; - c = strdup(p); + c = strdup(p); + } else + c = strndup(p, n); if (!c) return -ENOMEM; @@ -1872,7 +1875,7 @@ int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HA assert(s); STRV_FOREACH(i, l) { - r = _set_put_strdup_full(s, hash_ops, *i HASHMAP_DEBUG_PASS_ARGS); + r = _set_put_strndup_full(s, hash_ops, *i, SIZE_MAX HASHMAP_DEBUG_PASS_ARGS); if (r < 0) return r; @@ -2074,3 +2077,27 @@ bool set_equal(Set *a, Set *b) { return true; } + +static bool set_fnmatch_one(Set *patterns, const char *needle) { + const char *p; + + assert(needle); + + SET_FOREACH(p, patterns) + if (fnmatch(p, needle, 0) == 0) + return true; + + return false; +} + +bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needle) { + assert(needle); + + if (set_fnmatch_one(exclude_patterns, needle)) + return false; + + if (set_isempty(include_patterns)) + return true; + + return set_fnmatch_one(include_patterns, needle); +} diff --git a/src/libnm-systemd-shared/src/basic/hashmap.h b/src/libnm-systemd-shared/src/basic/hashmap.h index eafc08f6..91b3fe86 100644 --- a/src/libnm-systemd-shared/src/basic/hashmap.h +++ b/src/libnm-systemd-shared/src/basic/hashmap.h @@ -90,12 +90,7 @@ OrderedHashmap* _ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DE #define ordered_hashmap_new(ops) _ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) #define hashmap_free_and_replace(a, b) \ - ({ \ - hashmap_free(a); \ - (a) = (b); \ - (b) = NULL; \ - 0; \ - }) + free_and_replace_full(a, b, hashmap_free) HashmapBase* _hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value); static inline Hashmap* hashmap_free(Hashmap *h) { diff --git a/src/libnm-systemd-shared/src/basic/hostname-util.c b/src/libnm-systemd-shared/src/basic/hostname-util.c index 692733ac..1e94ce13 100644 --- a/src/libnm-systemd-shared/src/basic/hostname-util.c +++ b/src/libnm-systemd-shared/src/basic/hostname-util.c @@ -79,10 +79,8 @@ int gethostname_full(GetHostnameFlags flags, char **ret) { bool 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') || + return ascii_isalpha(c) || + ascii_isdigit(c) || c == '-'; } diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.c b/src/libnm-systemd-shared/src/basic/in-addr-util.c index 51a6b165..dc4446ae 100644 --- a/src/libnm-systemd-shared/src/basic/in-addr-util.c +++ b/src/libnm-systemd-shared/src/basic/in-addr-util.c @@ -16,6 +16,7 @@ #include "macro.h" #include "parse-util.h" #include "random-util.h" +#include "stdio-util.h" #include "string-util.h" #include "strxcpyx.h" #include "util.h" @@ -50,6 +51,20 @@ bool in4_addr_is_link_local(const struct in_addr *a) { return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16); } +bool in4_addr_is_link_local_dynamic(const struct in_addr *a) { + assert(a); + + if (!in4_addr_is_link_local(a)) + return false; + + /* 169.254.0.0/24 and 169.254.255.0/24 must not be used for the dynamic IPv4LL assignment. + * See RFC 3927 Section 2.1: + * The IPv4 prefix 169.254/16 is registered with the IANA for this purpose. The first 256 and last + * 256 addresses in the 169.254/16 prefix are reserved for future use and MUST NOT be selected by a + * host using this dynamic configuration mechanism. */ + return !IN_SET(be32toh(a->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U); +} + bool in6_addr_is_link_local(const struct in6_addr *a) { assert(a); @@ -450,7 +465,7 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { return -ENOMEM; errno = 0; - if (!inet_ntop(family, u, x, l)) + if (!typesafe_inet_ntop(family, u, x, l)) return errno_or_else(EINVAL); *ret = TAKE_PTR(x); @@ -458,37 +473,26 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { } #if 0 /* NM_IGNORED */ -int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret) { - _cleanup_free_ char *x = NULL; - char *p; - size_t l; +int in_addr_prefix_to_string( + int family, + const union in_addr_union *u, + unsigned prefixlen, + char *buf, + size_t buf_len) { assert(u); - assert(ret); + assert(buf); - if (family == AF_INET) - l = INET_ADDRSTRLEN + 3; - else if (family == AF_INET6) - l = INET6_ADDRSTRLEN + 4; - else + if (!IN_SET(family, AF_INET, AF_INET6)) return -EAFNOSUPPORT; - if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8) - return -EINVAL; - - x = new(char, l); - if (!x) - return -ENOMEM; - errno = 0; - if (!inet_ntop(family, u, x, l)) - return errno_or_else(EINVAL); + if (!typesafe_inet_ntop(family, u, buf, buf_len)) + return errno_or_else(ENOSPC); - p = x + strlen(x); - l -= strlen(x); - (void) strpcpyf(&p, l, "/%u", prefixlen); - - *ret = TAKE_PTR(x); + size_t l = strlen(buf); + if (!snprintf_ok(buf + l, buf_len - l, "/%u", prefixlen)) + return -ENOSPC; return 0; } #endif /* NM_IGNORED */ diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.h b/src/libnm-systemd-shared/src/basic/in-addr-util.h index 5de87a95..fbc60436 100644 --- a/src/libnm-systemd-shared/src/basic/in-addr-util.h +++ b/src/libnm-systemd-shared/src/basic/in-addr-util.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include #include #include #include @@ -43,6 +44,7 @@ static inline bool in_addr_data_is_set(const struct in_addr_data *a) { int in_addr_is_multicast(int family, const union in_addr_union *u); bool in4_addr_is_link_local(const struct in_addr *a); +bool in4_addr_is_link_local_dynamic(const struct in_addr *a); bool in6_addr_is_link_local(const struct in6_addr *a); int in_addr_is_link_local(int family, const union in_addr_union *u); bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a); @@ -68,14 +70,62 @@ int in_addr_prefix_range( unsigned prefixlen, union in_addr_union *ret_start, union in_addr_union *ret_end); + int in_addr_to_string(int family, const union in_addr_union *u, char **ret); static inline int in6_addr_to_string(const struct in6_addr *u, char **ret) { return in_addr_to_string(AF_INET6, (const union in_addr_union*) u, ret); } -int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret); -static inline int in6_addr_prefix_to_string(const struct in6_addr *u, unsigned prefixlen, char **ret) { - return in_addr_prefix_to_string(AF_INET6, (const union in_addr_union*) u, prefixlen, ret); + +static inline const char* typesafe_inet_ntop(int family, const union in_addr_union *a, char *buf, size_t len) { + return inet_ntop(family, a, buf, len); +} +static inline const char* typesafe_inet_ntop4(const struct in_addr *a, char *buf, size_t len) { + return inet_ntop(AF_INET, a, buf, len); +} +static inline const char* typesafe_inet_ntop6(const struct in6_addr *a, char *buf, size_t len) { + return inet_ntop(AF_INET6, a, buf, len); +} + +/* Note: the lifetime of the compound literal is the immediately surrounding block, + * see C11 §6.5.2.5, and + * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */ +#define IN_ADDR_MAX CONST_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) +#define IN_ADDR_TO_STRING(family, addr) typesafe_inet_ntop(family, addr, (char[IN_ADDR_MAX]){}, IN_ADDR_MAX) +#define IN4_ADDR_TO_STRING(addr) typesafe_inet_ntop4(addr, (char[INET_ADDRSTRLEN]){}, INET_ADDRSTRLEN) +#define IN6_ADDR_TO_STRING(addr) typesafe_inet_ntop6(addr, (char[INET6_ADDRSTRLEN]){}, INET6_ADDRSTRLEN) + +int in_addr_prefix_to_string( + int family, + const union in_addr_union *u, + unsigned prefixlen, + char *buf, + size_t buf_len); + +static inline const char* _in_addr_prefix_to_string( + int family, + const union in_addr_union *u, + unsigned prefixlen, + char *buf, + size_t buf_len) { + /* We assume that this is called with an appropriately sized buffer and can never fail. */ + assert_se(in_addr_prefix_to_string(family, u, prefixlen, buf, buf_len) == 0); + return buf; +} +static inline const char* _in4_addr_prefix_to_string(const struct in_addr *a, unsigned prefixlen, char *buf, size_t buf_len) { + return _in_addr_prefix_to_string(AF_INET, (const union in_addr_union *) a, prefixlen, buf, buf_len); +} +static inline const char* _in6_addr_prefix_to_string(const struct in6_addr *a, unsigned prefixlen, char *buf, size_t buf_len) { + return _in_addr_prefix_to_string(AF_INET6, (const union in_addr_union *) a, prefixlen, buf, buf_len); } + +#define PREFIX_SUFFIX_MAX (1 + DECIMAL_STR_MAX(unsigned)) +#define IN_ADDR_PREFIX_TO_STRING(family, addr, prefixlen) \ + _in_addr_prefix_to_string(family, addr, prefixlen, (char[IN_ADDR_MAX + PREFIX_SUFFIX_MAX]){}, IN_ADDR_MAX + PREFIX_SUFFIX_MAX) +#define IN4_ADDR_PREFIX_TO_STRING(addr, prefixlen) \ + _in4_addr_prefix_to_string(addr, prefixlen, (char[INET_ADDRSTRLEN + PREFIX_SUFFIX_MAX]){}, INET_ADDRSTRLEN + PREFIX_SUFFIX_MAX) +#define IN6_ADDR_PREFIX_TO_STRING(addr, prefixlen) \ + _in6_addr_prefix_to_string(addr, prefixlen, (char[INET6_ADDRSTRLEN + PREFIX_SUFFIX_MAX]){}, INET6_ADDRSTRLEN + PREFIX_SUFFIX_MAX) + int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret); static inline int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) { return in_addr_port_ifindex_name_to_string(family, u, 0, ifindex, NULL, ret); diff --git a/src/libnm-systemd-shared/src/basic/list.h b/src/libnm-systemd-shared/src/basic/list.h index 58e83a6c..ca300396 100644 --- a/src/libnm-systemd-shared/src/basic/list.h +++ b/src/libnm-systemd-shared/src/basic/list.h @@ -170,9 +170,6 @@ i != (p); \ i = i->name##_next ? i->name##_next : (head)) -#define LIST_IS_EMPTY(head) \ - (!(head)) - /* Join two lists tail to head: a->b, c->d to a->b->c->d and de-initialise second list */ #define LIST_JOIN(name,a,b) \ do { \ diff --git a/src/libnm-systemd-shared/src/basic/locale-util.c b/src/libnm-systemd-shared/src/basic/locale-util.c new file mode 100644 index 00000000..ae567345 --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/locale-util.c @@ -0,0 +1,376 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "nm-sd-adapt-shared.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "def.h" +#include "dirent-util.h" +#include "env-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "hashmap.h" +#include "locale-util.h" +#include "path-util.h" +#include "set.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "utf8.h" + +#if 0 /* NM_IGNORED */ +static char *normalize_locale(const char *name) { + const char *e; + + /* Locale names are weird: glibc has some magic rules when looking for the charset name on disk: it + * lowercases everything, and removes most special chars. This means the official .UTF-8 suffix + * becomes .utf8 when looking things up on disk. When enumerating locales, let's do the reverse + * operation, and go back to ".UTF-8" which appears to be the more commonly accepted name. We only do + * that for UTF-8 however, since it's kinda the only charset that matters. */ + + e = endswith(name, ".utf8"); + if (e) { + _cleanup_free_ char *prefix = NULL; + + prefix = strndup(name, e - name); + if (!prefix) + return NULL; + + return strjoin(prefix, ".UTF-8"); + } + + e = strstr(name, ".utf8@"); + if (e) { + _cleanup_free_ char *prefix = NULL; + + prefix = strndup(name, e - name); + if (!prefix) + return NULL; + + return strjoin(prefix, ".UTF-8@", e + 6); + } + + return strdup(name); +} + +static int add_locales_from_archive(Set *locales) { + /* Stolen from glibc... */ + + struct locarhead { + uint32_t magic; + /* Serial number. */ + uint32_t serial; + /* Name hash table. */ + uint32_t namehash_offset; + uint32_t namehash_used; + uint32_t namehash_size; + /* String table. */ + uint32_t string_offset; + uint32_t string_used; + uint32_t string_size; + /* Table with locale records. */ + uint32_t locrectab_offset; + uint32_t locrectab_used; + uint32_t locrectab_size; + /* MD5 sum hash table. */ + uint32_t sumhash_offset; + uint32_t sumhash_used; + uint32_t sumhash_size; + }; + + struct namehashent { + /* Hash value of the name. */ + uint32_t hashval; + /* Offset of the name in the string table. */ + uint32_t name_offset; + /* Offset of the locale record. */ + uint32_t locrec_offset; + }; + + const struct locarhead *h; + const struct namehashent *e; + const void *p = MAP_FAILED; + _cleanup_close_ int fd = -1; + size_t sz = 0; + struct stat st; + int r; + + fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return errno == ENOENT ? 0 : -errno; + + if (fstat(fd, &st) < 0) + return -errno; + + if (!S_ISREG(st.st_mode)) + return -EBADMSG; + + if (st.st_size < (off_t) sizeof(struct locarhead)) + return -EBADMSG; + + if (file_offset_beyond_memory_size(st.st_size)) + return -EFBIG; + + p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (p == MAP_FAILED) + return -errno; + + h = (const struct locarhead *) p; + if (h->magic != 0xde020109 || + h->namehash_offset + h->namehash_size > st.st_size || + h->string_offset + h->string_size > st.st_size || + h->locrectab_offset + h->locrectab_size > st.st_size || + h->sumhash_offset + h->sumhash_size > st.st_size) { + r = -EBADMSG; + goto finish; + } + + e = (const struct namehashent*) ((const uint8_t*) p + h->namehash_offset); + for (size_t i = 0; i < h->namehash_size; i++) { + char *z; + + if (e[i].locrec_offset == 0) + continue; + + if (!utf8_is_valid((char*) p + e[i].name_offset)) + continue; + + z = normalize_locale((char*) p + e[i].name_offset); + if (!z) { + r = -ENOMEM; + goto finish; + } + + r = set_consume(locales, z); + if (r < 0) + goto finish; + } + + r = 0; + + finish: + if (p != MAP_FAILED) + munmap((void*) p, sz); + + return r; +} + +static int add_locales_from_libdir(Set *locales) { + _cleanup_closedir_ DIR *dir = NULL; + int r; + + dir = opendir("/usr/lib/locale"); + if (!dir) + return errno == ENOENT ? 0 : -errno; + + FOREACH_DIRENT(de, dir, return -errno) { + char *z; + + if (de->d_type != DT_DIR) + continue; + + z = normalize_locale(de->d_name); + if (!z) + return -ENOMEM; + + r = set_consume(locales, z); + if (r < 0 && r != -EEXIST) + return r; + } + + return 0; +} + +int get_locales(char ***ret) { + _cleanup_set_free_free_ Set *locales = NULL; + _cleanup_strv_free_ char **l = NULL; + int r; + + locales = set_new(&string_hash_ops); + if (!locales) + return -ENOMEM; + + r = add_locales_from_archive(locales); + if (r < 0 && r != -ENOENT) + return r; + + r = add_locales_from_libdir(locales); + if (r < 0) + return r; + + char *locale; + SET_FOREACH(locale, locales) { + r = locale_is_installed(locale); + if (r < 0) + return r; + if (r == 0) + free(set_remove(locales, locale)); + } + + l = set_get_strv(locales); + if (!l) + return -ENOMEM; + + /* Now, all elements are owned by strv 'l'. Hence, do not call set_free_free(). */ + locales = set_free(locales); + + r = getenv_bool("SYSTEMD_LIST_NON_UTF8_LOCALES"); + if (r == -ENXIO || r == 0) { + char **a, **b; + + /* Filter out non-UTF-8 locales, because it's 2019, by default */ + for (a = b = l; *a; a++) { + + if (endswith(*a, "UTF-8") || + strstr(*a, ".UTF-8@")) + *(b++) = *a; + else + free(*a); + } + + *b = NULL; + + } else if (r < 0) + log_debug_errno(r, "Failed to parse $SYSTEMD_LIST_NON_UTF8_LOCALES as boolean"); + + strv_sort(l); + + *ret = TAKE_PTR(l); + + return 0; +} + +bool locale_is_valid(const char *name) { + + if (isempty(name)) + return false; + + if (strlen(name) >= 128) + return false; + + if (!utf8_is_valid(name)) + return false; + + if (!filename_is_valid(name)) + return false; + + if (!string_is_safe(name)) + return false; + + return true; +} + +int locale_is_installed(const char *name) { + if (!locale_is_valid(name)) + return false; + + if (STR_IN_SET(name, "C", "POSIX")) /* These ones are always OK */ + return true; + + _cleanup_(freelocalep) locale_t loc = + newlocale(LC_ALL_MASK, name, 0); + if (loc == (locale_t) 0) + return errno == ENOMEM ? -ENOMEM : false; + + return true; +} + +void init_gettext(void) { + setlocale(LC_ALL, ""); + textdomain(GETTEXT_PACKAGE); +} +#endif /* NM_IGNORED */ + +bool is_locale_utf8(void) { + const char *set; + static int cached_answer = -1; + + /* Note that we default to 'true' here, since today UTF8 is + * pretty much supported everywhere. */ + + if (cached_answer >= 0) + goto out; + + if (!setlocale(LC_ALL, "")) { + cached_answer = true; + goto out; + } + + set = nl_langinfo(CODESET); + if (!set) { + cached_answer = true; + goto out; + } + + if (streq(set, "UTF-8")) { + cached_answer = true; + goto out; + } + + /* For LC_CTYPE=="C" return true, because CTYPE is effectively + * unset and everything can do to UTF-8 nowadays. */ + set = setlocale(LC_CTYPE, NULL); + if (!set) { + cached_answer = true; + goto out; + } + + /* Check result, but ignore the result if C was set + * explicitly. */ + cached_answer = + STR_IN_SET(set, "C", "POSIX") && + !getenv("LC_ALL") && + !getenv("LC_CTYPE") && + !getenv("LANG"); + +out: + return (bool) cached_answer; +} + +#if 0 /* NM_IGNORED */ +void locale_variables_free(char *l[_VARIABLE_LC_MAX]) { + if (!l) + return; + + for (LocaleVariable i = 0; i < _VARIABLE_LC_MAX; i++) + l[i] = mfree(l[i]); +} + +void locale_variables_simplify(char *l[_VARIABLE_LC_MAX]) { + assert(l); + + for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) { + if (p == VARIABLE_LANG) + continue; + if (isempty(l[p]) || streq_ptr(l[VARIABLE_LANG], l[p])) + l[p] = mfree(l[p]); + } +} + +static const char * const locale_variable_table[_VARIABLE_LC_MAX] = { + [VARIABLE_LANG] = "LANG", + [VARIABLE_LANGUAGE] = "LANGUAGE", + [VARIABLE_LC_CTYPE] = "LC_CTYPE", + [VARIABLE_LC_NUMERIC] = "LC_NUMERIC", + [VARIABLE_LC_TIME] = "LC_TIME", + [VARIABLE_LC_COLLATE] = "LC_COLLATE", + [VARIABLE_LC_MONETARY] = "LC_MONETARY", + [VARIABLE_LC_MESSAGES] = "LC_MESSAGES", + [VARIABLE_LC_PAPER] = "LC_PAPER", + [VARIABLE_LC_NAME] = "LC_NAME", + [VARIABLE_LC_ADDRESS] = "LC_ADDRESS", + [VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE", + [VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT", + [VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION" +}; + +DEFINE_STRING_TABLE_LOOKUP(locale_variable, LocaleVariable); +#endif /* NM_IGNORED */ diff --git a/src/libnm-systemd-shared/src/basic/locale-util.h b/src/libnm-systemd-shared/src/basic/locale-util.h new file mode 100644 index 00000000..8990cb6a --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/locale-util.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include +#include +#include + +#include "macro.h" + +typedef enum LocaleVariable { + /* We don't list LC_ALL here on purpose. People should be + * using LANG instead. */ + + VARIABLE_LANG, + VARIABLE_LANGUAGE, + VARIABLE_LC_CTYPE, + VARIABLE_LC_NUMERIC, + VARIABLE_LC_TIME, + VARIABLE_LC_COLLATE, + VARIABLE_LC_MONETARY, + VARIABLE_LC_MESSAGES, + VARIABLE_LC_PAPER, + VARIABLE_LC_NAME, + VARIABLE_LC_ADDRESS, + VARIABLE_LC_TELEPHONE, + VARIABLE_LC_MEASUREMENT, + VARIABLE_LC_IDENTIFICATION, + _VARIABLE_LC_MAX, + _VARIABLE_LC_INVALID = -EINVAL, +} LocaleVariable; + +int get_locales(char ***l); +bool locale_is_valid(const char *name); +int locale_is_installed(const char *name); + +#define _(String) gettext(String) +#define N_(String) String +void init_gettext(void); + +bool is_locale_utf8(void); + +const char* locale_variable_to_string(LocaleVariable i) _const_; +LocaleVariable locale_variable_from_string(const char *s) _pure_; + +static inline void freelocalep(locale_t *p) { + if (*p == (locale_t) 0) + return; + + freelocale(*p); +} + +void locale_variables_free(char* l[_VARIABLE_LC_MAX]); +static inline void locale_variables_freep(char*(*l)[_VARIABLE_LC_MAX]) { + locale_variables_free(*l); +} +void locale_variables_simplify(char *l[_VARIABLE_LC_MAX]); diff --git a/src/libnm-systemd-shared/src/basic/log.h b/src/libnm-systemd-shared/src/basic/log.h index 6361eb0f..1bc84e46 100644 --- a/src/libnm-systemd-shared/src/basic/log.h +++ b/src/libnm-systemd-shared/src/basic/log.h @@ -434,8 +434,16 @@ int log_emergency_level(void); bool log_on_console(void) _pure_; -/* Helper to prepare various field for structured logging */ -#define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__ +/* Helper to wrap the main message in structured logging. The macro doesn't do much, + * except to provide visual grouping of the format string and its arguments. */ +#if LOG_MESSAGE_VERIFICATION || defined(__COVERITY__) +/* Do a fake formatting of the message string to let the scanner verify the arguments against the format + * message. The variable will never be set to true, but we don't tell the compiler that :) */ +extern bool _log_message_dummy; +# define LOG_MESSAGE(fmt, ...) "MESSAGE=%.0d" fmt, (_log_message_dummy && printf(fmt, ##__VA_ARGS__)), ##__VA_ARGS__ +#else +# define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__ +#endif void log_received_signal(int level, const struct signalfd_siginfo *si); diff --git a/src/libnm-systemd-shared/src/basic/macro.h b/src/libnm-systemd-shared/src/basic/macro.h index 41d83b3e..7380da10 100644 --- a/src/libnm-systemd-shared/src/basic/macro.h +++ b/src/libnm-systemd-shared/src/basic/macro.h @@ -11,24 +11,6 @@ #include "macro-fundamental.h" -#define _printf_(a, b) __attribute__((__format__(printf, a, b))) -#ifdef __clang__ -# define _alloc_(...) -#else -# define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__))) -#endif -#define _sentinel_ __attribute__((__sentinel__)) -#define _destructor_ __attribute__((__destructor__)) -#define _deprecated_ __attribute__((__deprecated__)) -#define _malloc_ __attribute__((__malloc__)) -#define _weak_ __attribute__((__weak__)) -#define _public_ __attribute__((__visibility__("default"))) -#define _hidden_ __attribute__((__visibility__("hidden"))) -#define _weakref_(x) __attribute__((__weakref__(#x))) -#define _alignas_(x) __attribute__((__aligned__(__alignof__(x)))) -#define _alignptr_ __attribute__((__aligned__(sizeof(void*)))) -#define _warn_unused_result_ __attribute__((__warn_unused_result__)) - #if !defined(HAS_FEATURE_MEMORY_SANITIZER) # if defined(__has_feature) # if __has_feature(memory_sanitizer) @@ -106,10 +88,6 @@ _Pragma("GCC diagnostic push") #endif -#define DISABLE_WARNING_FLOAT_EQUAL \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wfloat-equal\"") - #define DISABLE_WARNING_TYPE_LIMITS \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") @@ -137,25 +115,6 @@ #error "neither int nor long are four bytes long?!?" #endif -/* Rounds up */ - -#define ALIGN4(l) (((l) + 3) & ~3) -#define ALIGN8(l) (((l) + 7) & ~7) - -#if __SIZEOF_POINTER__ == 8 -#define ALIGN(l) ALIGN8(l) -#elif __SIZEOF_POINTER__ == 4 -#define ALIGN(l) ALIGN4(l) -#else -#error "Wut? Pointers are neither 4 nor 8 bytes long?" -#endif - -#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) (p))) -#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) (p))) -#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) (p))) - -#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) (p), (ali))) - /* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */ static inline unsigned long ALIGN_POWER2(unsigned long u) { @@ -370,7 +329,7 @@ static inline int __coverity_check_and_return__(int condition) { #ifndef thread_local /* * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__ - * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 + * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 */ #if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) #define thread_local _Thread_local @@ -405,8 +364,12 @@ static inline int __coverity_check_and_return__(int condition) { if (!p) \ return NULL; \ \ - assert(p->n_ref > 0); \ - p->n_ref++; \ + /* For type check. */ \ + unsigned *q = &p->n_ref; \ + assert(*q > 0); \ + assert_se(*q < UINT_MAX); \ + \ + (*q)++; \ return p; \ } @@ -462,8 +425,15 @@ static inline int __coverity_check_and_return__(int condition) { _copy; \ }) +#define saturate_add(x, y, limit) \ + ({ \ + typeof(limit) _x = (x); \ + typeof(limit) _y = (y); \ + _x > (limit) || _y >= (limit) - _x ? (limit) : _x + _y; \ + }) + static inline size_t size_add(size_t x, size_t y) { - return y >= SIZE_MAX - x ? SIZE_MAX : x + y; + return saturate_add(x, y, SIZE_MAX); } typedef struct { diff --git a/src/libnm-systemd-shared/src/basic/mempool.c b/src/libnm-systemd-shared/src/basic/mempool.c index 46c44914..53a719e0 100644 --- a/src/libnm-systemd-shared/src/basic/mempool.c +++ b/src/libnm-systemd-shared/src/basic/mempool.c @@ -5,12 +5,9 @@ #include #include -#include "env-util.h" #include "macro.h" #include "memory-util.h" #include "mempool.h" -#include "process-util.h" -#include "util.h" struct pool { struct pool *next; @@ -75,20 +72,6 @@ void mempool_free_tile(struct mempool *mp, void *p) { mp->freelist = p; } -bool mempool_enabled(void) { - static int b = -1; - - if (!is_main_thread()) - return false; - - if (!mempool_use_allowed) - b = false; - if (b < 0) - b = getenv_bool("SYSTEMD_MEMPOOL") != 0; - - return b; -} - #if VALGRIND void mempool_drop(struct mempool *mp) { struct pool *p = mp->first_pool; diff --git a/src/libnm-systemd-shared/src/basic/mempool.h b/src/libnm-systemd-shared/src/basic/mempool.h index 0fe2f278..539ccbdf 100644 --- a/src/libnm-systemd-shared/src/basic/mempool.h +++ b/src/libnm-systemd-shared/src/basic/mempool.h @@ -23,8 +23,7 @@ static struct mempool pool_name = { \ .at_least = alloc_at_least, \ } -extern const bool mempool_use_allowed; -bool mempool_enabled(void); +__attribute__((weak)) bool mempool_enabled(void); #if VALGRIND void mempool_drop(struct mempool *mp); diff --git a/src/libnm-systemd-shared/src/basic/missing_syscall.h b/src/libnm-systemd-shared/src/basic/missing_syscall.h index e5bdc0e1..107f4b01 100644 --- a/src/libnm-systemd-shared/src/basic/missing_syscall.h +++ b/src/libnm-systemd-shared/src/basic/missing_syscall.h @@ -76,6 +76,7 @@ static inline int missing_memfd_create(const char *name, unsigned int flags) { # define memfd_create missing_memfd_create #endif +#endif /* NM_IGNORED */ /* ======================================================================= */ @@ -95,6 +96,7 @@ static inline ssize_t missing_getrandom(void *buffer, size_t count, unsigned fla /* ======================================================================= */ +#if 0 /* NM_IGNORED */ /* The syscall has been defined since forever, but the glibc wrapper was missing. */ #if !HAVE_GETTID static inline pid_t missing_gettid(void) { diff --git a/src/libnm-systemd-shared/src/basic/ordered-set.h b/src/libnm-systemd-shared/src/basic/ordered-set.h index c0650e01..e73da205 100644 --- a/src/libnm-systemd-shared/src/basic/ordered-set.h +++ b/src/libnm-systemd-shared/src/basic/ordered-set.h @@ -74,6 +74,10 @@ static inline char** ordered_set_get_strv(OrderedSet *s) { return _hashmap_get_strv(HASHMAP_BASE((OrderedHashmap*) s)); } +static inline int ordered_set_reserve(OrderedSet *s, unsigned entries_add) { + return ordered_hashmap_reserve((OrderedHashmap*) s, entries_add); +} + int ordered_set_consume(OrderedSet *s, void *p); int _ordered_set_put_strdup(OrderedSet **s, const char *p HASHMAP_DEBUG_PARAMS); #define ordered_set_put_strdup(s, p) _ordered_set_put_strdup(s, p HASHMAP_DEBUG_SRC_ARGS) diff --git a/src/libnm-systemd-shared/src/basic/parse-util.c b/src/libnm-systemd-shared/src/basic/parse-util.c index 0a623c51..d5dcaae8 100644 --- a/src/libnm-systemd-shared/src/basic/parse-util.c +++ b/src/libnm-systemd-shared/src/basic/parse-util.c @@ -215,7 +215,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) { e++; /* strtoull() itself would accept space/+/- */ - if (*e >= '0' && *e <= '9') { + if (ascii_isdigit(*e)) { unsigned long long l2; char *e2; @@ -606,7 +606,7 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { /* accept any number of digits, strtoull is limited to 19 */ for (size_t i = 0; i < digits; i++,s++) { - if (*s < '0' || *s > '9') { + if (!ascii_isdigit(*s)) { if (i == 0) return -EINVAL; @@ -699,34 +699,6 @@ int parse_ip_prefix_length(const char *s, int *ret) { return 0; } -int parse_dev(const char *s, dev_t *ret) { - const char *major; - unsigned x, y; - size_t n; - int r; - - n = strspn(s, DIGITS); - if (n == 0) - return -EINVAL; - if (s[n] != ':') - return -EINVAL; - - major = strndupa_safe(s, n); - r = safe_atou(major, &x); - if (r < 0) - return r; - - r = safe_atou(s + n + 1, &y); - if (r < 0) - return r; - - if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y)) - return -ERANGE; - - *ret = makedev(x, y); - return 0; -} - int parse_oom_score_adjust(const char *s, int *ret) { int r, v; diff --git a/src/libnm-systemd-shared/src/basic/parse-util.h b/src/libnm-systemd-shared/src/basic/parse-util.h index 82731246..f2222dcf 100644 --- a/src/libnm-systemd-shared/src/basic/parse-util.h +++ b/src/libnm-systemd-shared/src/basic/parse-util.h @@ -12,7 +12,6 @@ typedef unsigned long loadavg_t; int parse_boolean(const char *v) _pure_; -int parse_dev(const char *s, dev_t *ret); int parse_pid(const char *s, pid_t* ret_pid); int parse_mode(const char *s, mode_t *ret); int parse_ifindex(const char *s); diff --git a/src/libnm-systemd-shared/src/basic/path-util.c b/src/libnm-systemd-shared/src/basic/path-util.c index f6088458..3ba3510f 100644 --- a/src/libnm-systemd-shared/src/basic/path-util.c +++ b/src/libnm-systemd-shared/src/basic/path-util.c @@ -19,17 +19,13 @@ #include "extract-word.h" #include "fd-util.h" #include "fs-util.h" -#include "glob-util.h" #include "log.h" #include "macro.h" -#include "nulstr-util.h" -#include "parse-util.h" #include "path-util.h" #include "stat-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" -#include "utf8.h" #if 0 /* NM_IGNORED */ int path_split_and_make_absolute(const char *p, char ***ret) { @@ -380,54 +376,6 @@ char *path_simplify(char *path) { return path; } -#if 0 /* NM_IGNORED */ -int path_simplify_and_warn( - char *path, - unsigned flag, - const char *unit, - const char *filename, - unsigned line, - const char *lvalue) { - - bool fatal = flag & PATH_CHECK_FATAL; - - assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)); - - if (!utf8_is_valid(path)) - return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path); - - if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) { - bool absolute; - - absolute = path_is_absolute(path); - - if (!absolute && (flag & PATH_CHECK_ABSOLUTE)) - return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), - "%s= path is not absolute%s: %s", - lvalue, fatal ? "" : ", ignoring", path); - - if (absolute && (flag & PATH_CHECK_RELATIVE)) - return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), - "%s= path is absolute%s: %s", - lvalue, fatal ? "" : ", ignoring", path); - } - - path_simplify(path); - - if (!path_is_valid(path)) - return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), - "%s= path has invalid length (%zu bytes)%s.", - lvalue, strlen(path), fatal ? "" : ", ignoring"); - - if (!path_is_normalized(path)) - return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), - "%s= path is not normalized%s: %s", - lvalue, fatal ? "" : ", ignoring", path); - - return 0; -} -#endif /* NM_IGNORED */ - char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) { assert(path); assert(prefix); @@ -1113,7 +1061,7 @@ int path_extract_filename(const char *path, char **ret) { return -ENOMEM; *ret = TAKE_PTR(a); - return strlen(c) > (size_t)r ? O_DIRECTORY : 0; + return strlen(c) > (size_t) r ? O_DIRECTORY : 0; } int path_extract_directory(const char *path, char **ret) { @@ -1167,7 +1115,7 @@ bool filename_is_valid(const char *p) { if (isempty(p)) return false; - if (dot_or_dot_dot(p)) + if (dot_or_dot_dot(p)) /* Yes, in this context we consider "." and ".." invalid */ return false; e = strchrnul(p, '/'); @@ -1322,74 +1270,6 @@ bool valid_device_allow_pattern(const char *path) { return valid_device_node_path(path); } - -int systemd_installation_has_version(const char *root, unsigned minimal_version) { - const char *pattern; - int r; - - /* Try to guess if systemd installation is later than the specified version. This - * is hacky and likely to yield false negatives, particularly if the installation - * is non-standard. False positives should be relatively rare. - */ - - NULSTR_FOREACH(pattern, - /* /lib works for systems without usr-merge, and for systems with a sane - * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary - * for Gentoo which does a merge without making /lib a symlink. - */ - "lib/systemd/libsystemd-shared-*.so\0" - "lib64/systemd/libsystemd-shared-*.so\0" - "usr/lib/systemd/libsystemd-shared-*.so\0" - "usr/lib64/systemd/libsystemd-shared-*.so\0") { - - _cleanup_strv_free_ char **names = NULL; - _cleanup_free_ char *path = NULL; - char *c; - - path = path_join(root, pattern); - if (!path) - return -ENOMEM; - - r = glob_extend(&names, path, 0); - if (r == -ENOENT) - continue; - if (r < 0) - return r; - - assert_se(c = endswith(path, "*.so")); - *c = '\0'; /* truncate the glob part */ - - STRV_FOREACH(name, names) { - /* This is most likely to run only once, hence let's not optimize anything. */ - char *t, *t2; - unsigned version; - - t = startswith(*name, path); - if (!t) - continue; - - t2 = endswith(t, ".so"); - if (!t2) - continue; - - t2[0] = '\0'; /* truncate the suffix */ - - r = safe_atou(t, &version); - if (r < 0) { - log_debug_errno(r, "Found libsystemd shared at \"%s.so\", but failed to parse version: %m", *name); - continue; - } - - log_debug("Found libsystemd shared at \"%s.so\", version %u (%s).", - *name, version, - version >= minimal_version ? "OK" : "too old"); - if (version >= minimal_version) - return true; - } - } - - return false; -} #endif /* NM_IGNORED */ bool dot_or_dot_dot(const char *path) { diff --git a/src/libnm-systemd-shared/src/basic/path-util.h b/src/libnm-systemd-shared/src/basic/path-util.h index fc41c869..c97c4540 100644 --- a/src/libnm-systemd-shared/src/basic/path-util.h +++ b/src/libnm-systemd-shared/src/basic/path-util.h @@ -45,12 +45,16 @@ #endif static inline bool is_path(const char *p) { - assert(p); + if (!p) /* A NULL pointer is definitely not a path */ + return false; + return strchr(p, '/'); } static inline bool path_is_absolute(const char *p) { - assert(p); + if (!p) /* A NULL pointer is definitely not an absolute path */ + return false; + return p[0] == '/'; } @@ -79,14 +83,6 @@ char* path_extend_internal(char **x, ...); char* path_simplify(char *path); -enum { - PATH_CHECK_FATAL = 1 << 0, /* If not set, then error message is appended with 'ignoring'. */ - PATH_CHECK_ABSOLUTE = 1 << 1, - PATH_CHECK_RELATIVE = 1 << 2, -}; - -int path_simplify_and_warn(char *path, unsigned flag, const char *unit, const char *filename, unsigned line, const char *lvalue); - static inline bool path_equal_ptr(const char *a, const char *b) { return !!a == !!b && (!a || path_equal(a, b)); } @@ -167,10 +163,10 @@ int path_extract_directory(const char *path, char **ret); bool filename_is_valid(const char *p) _pure_; bool path_is_valid_full(const char *p, bool accept_dot_dot) _pure_; static inline bool path_is_valid(const char *p) { - return path_is_valid_full(p, true); + return path_is_valid_full(p, /* accept_dot_dot= */ true); } static inline bool path_is_safe(const char *p) { - return path_is_valid_full(p, false); + return path_is_valid_full(p, /* accept_dot_dot= */ false); } bool path_is_normalized(const char *p) _pure_; @@ -183,8 +179,6 @@ bool is_device_path(const char *path); bool valid_device_node_path(const char *path); bool valid_device_allow_pattern(const char *path); -int systemd_installation_has_version(const char *root, unsigned minimal_version); - bool dot_or_dot_dot(const char *path); static inline const char *skip_dev_prefix(const char *p) { diff --git a/src/libnm-systemd-shared/src/basic/process-util.c b/src/libnm-systemd-shared/src/basic/process-util.c index 83e3a71e..1c23a2f8 100644 --- a/src/libnm-systemd-shared/src/basic/process-util.c +++ b/src/libnm-systemd-shared/src/basic/process-util.c @@ -1034,7 +1034,7 @@ bool oom_score_adjust_is_valid(int oa) { } unsigned long personality_from_string(const char *p) { - int architecture; + Architecture architecture; if (!p) return PERSONALITY_INVALID; @@ -1058,7 +1058,7 @@ unsigned long personality_from_string(const char *p) { } const char* personality_to_string(unsigned long p) { - int architecture = _ARCHITECTURE_INVALID; + Architecture architecture = _ARCHITECTURE_INVALID; if (p == PER_LINUX) architecture = native_architecture(); @@ -1156,7 +1156,7 @@ void reset_cached_pid(void) { pid_t getpid_cached(void) { static bool installed = false; - pid_t current_value; + pid_t current_value = CACHED_PID_UNSET; /* getpid_cached() is much like getpid(), but caches the value in local memory, to avoid having to invoke a * system call each time. This restores glibc behaviour from before 2.24, when getpid() was unconditionally @@ -1167,7 +1167,13 @@ pid_t getpid_cached(void) { * https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=c579f48edba88380635ab98cb612030e3ed8691e */ - current_value = __sync_val_compare_and_swap(&cached_pid, CACHED_PID_UNSET, CACHED_PID_BUSY); + __atomic_compare_exchange_n( + &cached_pid, + ¤t_value, + CACHED_PID_BUSY, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST); switch (current_value) { @@ -1589,6 +1595,30 @@ bool invoked_as(char *argv[], const char *token) { return strstr(last_path_component(argv[0]), token); } +bool invoked_by_systemd(void) { + int r; + + /* If the process is directly executed by PID1 (e.g. ExecStart= or generator), systemd-importd, + * or systemd-homed, then $SYSTEMD_EXEC_PID= is set, and read the command line. */ + const char *e = getenv("SYSTEMD_EXEC_PID"); + if (!e) + return false; + + if (streq(e, "*")) + /* For testing. */ + return true; + + pid_t p; + r = parse_pid(e, &p); + if (r < 0) { + /* We know that systemd sets the variable correctly. Something else must have set it. */ + log_debug_errno(r, "Failed to parse \"SYSTEMD_EXEC_PID=%s\", ignoring: %m", e); + return false; + } + + return getpid_cached() == p; +} + _noreturn_ void freeze(void) { log_close(); diff --git a/src/libnm-systemd-shared/src/basic/process-util.h b/src/libnm-systemd-shared/src/basic/process-util.h index c488c6a8..962f12d1 100644 --- a/src/libnm-systemd-shared/src/basic/process-util.h +++ b/src/libnm-systemd-shared/src/basic/process-util.h @@ -192,6 +192,8 @@ int setpriority_closest(int priority); bool invoked_as(char *argv[], const char *token); +bool invoked_by_systemd(void); + _noreturn_ void freeze(void); bool argv_looks_like_help(int argc, char **argv); diff --git a/src/libnm-systemd-shared/src/basic/random-util.c b/src/libnm-systemd-shared/src/basic/random-util.c index e3f4ee72..d576bff1 100644 --- a/src/libnm-systemd-shared/src/basic/random-util.c +++ b/src/libnm-systemd-shared/src/basic/random-util.c @@ -32,192 +32,142 @@ #include "missing_syscall.h" #include "parse-util.h" #include "random-util.h" -#include "siphash24.h" +#include "sha256.h" #include "time-util.h" -static bool srand_called = false; +/* This is a "best effort" kind of thing, but has no real security value. + * So, this should only be used by random_bytes(), which is not meant for + * crypto. This could be made better, but we're *not* trying to roll a + * userspace prng here, or even have forward secrecy, but rather just do + * the shortest thing that is at least better than libc rand(). */ +static void fallback_random_bytes(void *p, size_t n) { + static thread_local uint64_t fallback_counter = 0; + struct { + char label[32]; + uint64_t call_id, block_id; + usec_t stamp_mono, stamp_real; + pid_t pid, tid; + uint8_t auxval[16]; + } state = { + /* Arbitrary domain separation to prevent other usage of AT_RANDOM from clashing. */ + .label = "systemd fallback random bytes v1", + .call_id = fallback_counter++, + .stamp_mono = now(CLOCK_MONOTONIC), + .stamp_real = now(CLOCK_REALTIME), + .pid = getpid(), + .tid = gettid() + }; -int genuine_random_bytes(void *p, size_t n, RandomFlags flags) { - static int have_syscall = -1; - _cleanup_close_ int fd = -1; - - /* Gathers some high-quality randomness from the kernel. This call won't block, unless the RANDOM_BLOCK - * flag is set. If it doesn't block, it will still always return some data from the kernel, regardless - * of whether the random pool is fully initialized or not. When creating cryptographic key material you - * should always use RANDOM_BLOCK. */ - - if (n == 0) - return 0; - - /* Use the getrandom() syscall unless we know we don't have it. */ - if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) { - for (;;) { -#if HAVE_GETRANDOM - ssize_t l = getrandom(p, n, FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_INSECURE); -#else - /* NetworkManager Note: systemd calls the syscall directly in this case. Don't add that workaround. - * If you don't compile against a libc that provides getrandom(), you don't get it. */ - ssize_t l = -1; - errno = ENOSYS; +#if HAVE_SYS_AUXV_H + memcpy(state.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(state.auxval)); #endif - if (l > 0) { - have_syscall = true; - - if ((size_t) l == n) - return 0; /* Yay, success! */ - - /* We didn't get enough data, so try again */ - assert((size_t) l < n); - p = (uint8_t*) p + l; - n -= l; - continue; - - } else if (l == 0) { - have_syscall = true; - return -EIO; - - } else if (ERRNO_IS_NOT_SUPPORTED(errno)) { - /* We lack the syscall, continue with reading from /dev/urandom. */ - have_syscall = false; - break; - - } else if (errno == EINVAL) { - /* If we previously passed GRND_INSECURE, and this flag isn't known, then - * we're likely running an old kernel which has getrandom() but not - * GRND_INSECURE. In this case, fall back to /dev/urandom. */ - if (!FLAGS_SET(flags, RANDOM_BLOCK)) - break; - - return -errno; - } else - return -errno; + while (n > 0) { + struct sha256_ctx ctx; + + sha256_init_ctx(&ctx); + sha256_process_bytes(&state, sizeof(state), &ctx); + if (n < SHA256_DIGEST_SIZE) { + uint8_t partial[SHA256_DIGEST_SIZE]; + sha256_finish_ctx(&ctx, partial); + memcpy(p, partial, n); + break; } + sha256_finish_ctx(&ctx, p); + p = (uint8_t *) p + SHA256_DIGEST_SIZE; + n -= SHA256_DIGEST_SIZE; + ++state.block_id; } - - fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return errno == ENOENT ? -ENOSYS : -errno; - - return loop_read_exact(fd, p, n, true); } -static void clear_srand_initialization(void) { - srand_called = false; -} +void random_bytes(void *p, size_t n) { + static bool have_getrandom = true, have_grndinsecure = true; + _cleanup_close_ int fd = -1; -void initialize_srand(void) { - static bool pthread_atfork_registered = false; - unsigned x; -#if HAVE_SYS_AUXV_H - const void *auxv; -#endif - if (srand_called) + if (n == 0) return; -#if HAVE_SYS_AUXV_H - /* The kernel provides us with 16 bytes of entropy in auxv, so let's try to make use of that to seed - * the pseudo-random generator. It's better than nothing... But let's first hash it to make it harder - * to recover the original value by watching any pseudo-random bits we generate. After all the - * AT_RANDOM data might be used by other stuff too (in particular: ASLR), and we probably shouldn't - * leak the seed for that. */ - - auxv = ULONG_TO_PTR(getauxval(AT_RANDOM)); - if (auxv) { - static const uint8_t auxval_hash_key[16] = { - 0x92, 0x6e, 0xfe, 0x1b, 0xcf, 0x00, 0x52, 0x9c, 0xcc, 0x42, 0xcf, 0xdc, 0x94, 0x1f, 0x81, 0x0f - }; - - x = (unsigned) siphash24(auxv, 16, auxval_hash_key); - } else -#endif - x = 0; - - x ^= (unsigned) now(CLOCK_REALTIME); - x ^= (unsigned) gettid(); - - srand(x); - srand_called = true; - - if (!pthread_atfork_registered) { - (void) pthread_atfork(NULL, NULL, clear_srand_initialization); - pthread_atfork_registered = true; + for (;;) { + ssize_t l; + + if (!have_getrandom) + break; + + l = getrandom(p, n, have_grndinsecure ? GRND_INSECURE : GRND_NONBLOCK); + if (l > 0) { + if ((size_t) l == n) + return; /* Done reading, success. */ + p = (uint8_t *) p + l; + n -= l; + continue; /* Interrupted by a signal; keep going. */ + } else if (l == 0) + break; /* Weird, so fallback to /dev/urandom. */ + else if (ERRNO_IS_NOT_SUPPORTED(errno)) { + have_getrandom = false; + break; /* No syscall, so fallback to /dev/urandom. */ + } else if (errno == EINVAL && have_grndinsecure) { + have_grndinsecure = false; + continue; /* No GRND_INSECURE; fallback to GRND_NONBLOCK. */ + } else if (errno == EAGAIN && !have_grndinsecure) + break; /* Will block, but no GRND_INSECURE, so fallback to /dev/urandom. */ + + break; /* Unexpected, so just give up and fallback to /dev/urandom. */ } -} - -/* INT_MAX gives us only 31 bits, so use 24 out of that. */ -#if RAND_MAX >= INT_MAX -assert_cc(RAND_MAX >= 16777215); -# define RAND_STEP 3 -#else -/* SHORT_INT_MAX or lower gives at most 15 bits, we just use 8 out of that. */ -assert_cc(RAND_MAX >= 255); -# define RAND_STEP 1 -#endif -void pseudo_random_bytes(void *p, size_t n) { - uint8_t *q; - - /* This returns pseudo-random data using libc's rand() function. You probably never want to call this - * directly, because why would you use this if you can get better stuff cheaply? Use random_bytes() - * instead, see below: it will fall back to this function if there's nothing better to get, but only - * then. */ + fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd >= 0 && loop_read_exact(fd, p, n, false) == 0) + return; - initialize_srand(); + /* This is a terrible fallback. Oh well. */ + fallback_random_bytes(p, n); +} - for (q = p; q < (uint8_t*) p + n; q += RAND_STEP) { - unsigned rr; +int crypto_random_bytes(void *p, size_t n) { + static bool have_getrandom = true, seen_initialized = false; + _cleanup_close_ int fd = -1; - rr = (unsigned) rand(); + if (n == 0) + return 0; -#if RAND_STEP >= 3 - if ((size_t) (q - (uint8_t*) p + 2) < n) - q[2] = rr >> 16; -#endif -#if RAND_STEP >= 2 - if ((size_t) (q - (uint8_t*) p + 1) < n) - q[1] = rr >> 8; -#endif - q[0] = rr; + for (;;) { + ssize_t l; + + if (!have_getrandom) + break; + + l = getrandom(p, n, 0); + if (l > 0) { + if ((size_t) l == n) + return 0; /* Done reading, success. */ + p = (uint8_t *) p + l; + n -= l; + continue; /* Interrupted by a signal; keep going. */ + } else if (l == 0) + return -EIO; /* Weird, should never happen. */ + else if (ERRNO_IS_NOT_SUPPORTED(errno)) { + have_getrandom = false; + break; /* No syscall, so fallback to /dev/urandom. */ + } + return -errno; } -} -void random_bytes(void *p, size_t n) { + if (!seen_initialized) { + _cleanup_close_ int ready_fd = -1; + int r; - /* This returns high quality randomness if we can get it cheaply. If we can't because for some reason - * it is not available we'll try some crappy fallbacks. - * - * What this function will do: - * - * • Use getrandom(GRND_INSECURE) or /dev/urandom, to return high-quality random values if - * they are cheaply available, or less high-quality random values if they are not. - * - * • This function will return pseudo-random data, generated via libc rand() if nothing - * better is available. - * - * • This function will work fine in early boot - * - * • This function will always succeed - * - * What this function won't do: - * - * • This function will never fail: it will give you randomness no matter what. It might not - * be high quality, but it will return some, possibly generated via libc's rand() call. - * - * • This function will never block: if the only way to get good randomness is a blocking, - * synchronous getrandom() we'll instead provide you with pseudo-random data. - * - * This function is hence great for things like seeding hash tables, generating random numeric UNIX - * user IDs (that are checked for collisions before use) and such. - * - * This function is hence not useful for generating UUIDs or cryptographic key material. - */ - - if (genuine_random_bytes(p, n, 0) >= 0) - return; + ready_fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (ready_fd < 0) + return -errno; + r = fd_wait_for_event(ready_fd, POLLIN, USEC_INFINITY); + if (r < 0) + return r; + seen_initialized = true; + } - /* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */ - pseudo_random_bytes(p, n); + fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return -errno; + return loop_read_exact(fd, p, n, false); } #if 0 /* NM_IGNORED */ diff --git a/src/libnm-systemd-shared/src/basic/random-util.h b/src/libnm-systemd-shared/src/basic/random-util.h index ccee3279..2d998072 100644 --- a/src/libnm-systemd-shared/src/basic/random-util.h +++ b/src/libnm-systemd-shared/src/basic/random-util.h @@ -5,15 +5,8 @@ #include #include -typedef enum RandomFlags { - RANDOM_BLOCK = 1 << 0, /* Rather block than return crap randomness (only if the kernel supports that) */ -} RandomFlags; - -int genuine_random_bytes(void *p, size_t n, RandomFlags flags); /* returns "genuine" randomness, optionally filled up with pseudo random, if not enough is available */ -void pseudo_random_bytes(void *p, size_t n); /* returns only pseudo-randommess (but possibly seeded from something better) */ -void random_bytes(void *p, size_t n); /* returns genuine randomness if cheaply available, and pseudo randomness if not. */ - -void initialize_srand(void); +void random_bytes(void *p, size_t n); /* Returns random bytes suitable for most uses, but may be insecure sometimes. */ +int crypto_random_bytes(void *p, size_t n); /* Returns secure random bytes after waiting for the RNG to initialize. */ static inline uint64_t random_u64(void) { uint64_t u; diff --git a/src/libnm-systemd-shared/src/basic/set.h b/src/libnm-systemd-shared/src/basic/set.h index 5cae1316..618e7297 100644 --- a/src/libnm-systemd-shared/src/basic/set.h +++ b/src/libnm-systemd-shared/src/basic/set.h @@ -6,12 +6,7 @@ #include "macro.h" #define set_free_and_replace(a, b) \ - ({ \ - set_free(a); \ - (a) = (b); \ - (b) = NULL; \ - 0; \ - }) + free_and_replace_full(a, b, set_free) Set* _set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); #define set_new(ops) _set_new(ops HASHMAP_DEBUG_SRC_ARGS) @@ -127,9 +122,12 @@ int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HAS int set_consume(Set *s, void *value); -int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS); -#define set_put_strdup_full(s, hash_ops, p) _set_put_strdup_full(s, hash_ops, p HASHMAP_DEBUG_SRC_ARGS) -#define set_put_strdup(s, p) set_put_strdup_full(s, &string_hash_ops_free, p) +int _set_put_strndup_full(Set **s, const struct hash_ops *hash_ops, const char *p, size_t n HASHMAP_DEBUG_PARAMS); +#define set_put_strndup_full(s, hash_ops, p, n) _set_put_strndup_full(s, hash_ops, p, n HASHMAP_DEBUG_SRC_ARGS) +#define set_put_strdup_full(s, hash_ops, p) set_put_strndup_full(s, hash_ops, p, SIZE_MAX) +#define set_put_strndup(s, p, n) set_put_strndup_full(s, &string_hash_ops_free, p, n) +#define set_put_strdup(s, p) set_put_strndup(s, p, SIZE_MAX) + int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HASHMAP_DEBUG_PARAMS); #define set_put_strdupv_full(s, hash_ops, l) _set_put_strdupv_full(s, hash_ops, l HASHMAP_DEBUG_SRC_ARGS) #define set_put_strdupv(s, l) set_put_strdupv_full(s, &string_hash_ops_free, l) @@ -153,3 +151,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret); bool set_equal(Set *a, Set *b); + +bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needle); diff --git a/src/libnm-systemd-shared/src/basic/socket-util.c b/src/libnm-systemd-shared/src/basic/socket-util.c index 6478fdee..c155e352 100644 --- a/src/libnm-systemd-shared/src/basic/socket-util.c +++ b/src/libnm-systemd-shared/src/basic/socket-util.c @@ -495,9 +495,7 @@ int sockaddr_pretty( if (r < 0) return -ENOMEM; } else { - char a[INET6_ADDRSTRLEN]; - - inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)); + const char *a = IN6_ADDR_TO_STRING(&sa->in6.sin6_addr); if (include_port) { if (asprintf(&p, @@ -656,24 +654,24 @@ int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) } static const char* const netlink_family_table[] = { - [NETLINK_ROUTE] = "route", - [NETLINK_FIREWALL] = "firewall", - [NETLINK_INET_DIAG] = "inet-diag", - [NETLINK_NFLOG] = "nflog", - [NETLINK_XFRM] = "xfrm", - [NETLINK_SELINUX] = "selinux", - [NETLINK_ISCSI] = "iscsi", - [NETLINK_AUDIT] = "audit", - [NETLINK_FIB_LOOKUP] = "fib-lookup", - [NETLINK_CONNECTOR] = "connector", - [NETLINK_NETFILTER] = "netfilter", - [NETLINK_IP6_FW] = "ip6-fw", - [NETLINK_DNRTMSG] = "dnrtmsg", + [NETLINK_ROUTE] = "route", + [NETLINK_FIREWALL] = "firewall", + [NETLINK_INET_DIAG] = "inet-diag", + [NETLINK_NFLOG] = "nflog", + [NETLINK_XFRM] = "xfrm", + [NETLINK_SELINUX] = "selinux", + [NETLINK_ISCSI] = "iscsi", + [NETLINK_AUDIT] = "audit", + [NETLINK_FIB_LOOKUP] = "fib-lookup", + [NETLINK_CONNECTOR] = "connector", + [NETLINK_NETFILTER] = "netfilter", + [NETLINK_IP6_FW] = "ip6-fw", + [NETLINK_DNRTMSG] = "dnrtmsg", [NETLINK_KOBJECT_UEVENT] = "kobject-uevent", - [NETLINK_GENERIC] = "generic", - [NETLINK_SCSITRANSPORT] = "scsitransport", - [NETLINK_ECRYPTFS] = "ecryptfs", - [NETLINK_RDMA] = "rdma", + [NETLINK_GENERIC] = "generic", + [NETLINK_SCSITRANSPORT] = "scsitransport", + [NETLINK_ECRYPTFS] = "ecryptfs", + [NETLINK_RDMA] = "rdma", }; DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX); @@ -780,10 +778,10 @@ int fd_set_rcvbuf(int fd, size_t n, bool increase) { } static const char* const ip_tos_table[] = { - [IPTOS_LOWDELAY] = "low-delay", - [IPTOS_THROUGHPUT] = "throughput", + [IPTOS_LOWDELAY] = "low-delay", + [IPTOS_THROUGHPUT] = "throughput", [IPTOS_RELIABILITY] = "reliability", - [IPTOS_LOWCOST] = "low-cost", + [IPTOS_LOWCOST] = "low-cost", }; DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); @@ -841,7 +839,7 @@ bool ifname_valid_full(const char *p, IfnameValidFlags flags) { if (!ifname_valid_char(*t)) return false; - numeric = numeric && (*t >= '0' && *t <= '9'); + numeric = numeric && ascii_isdigit(*t); } /* It's fully numeric but didn't parse as valid ifindex above? if so, it must be too large or zero or @@ -1248,7 +1246,10 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) { * addresses!), which the kernel doesn't. We do this to reduce chance of incompatibility with other apps that * do not expect non-NUL terminated file system path. */ if (l+1 > sizeof(ret->sun_path)) - return -EINVAL; + return path[0] == '@' ? -EINVAL : -ENAMETOOLONG; /* return a recognizable error if this is + * too long to fit into a sockaddr_un, but + * is a file system path, and thus might be + * connectible via O_PATH indirection. */ *ret = (struct sockaddr_un) { .sun_family = AF_UNIX, @@ -1437,3 +1438,51 @@ int socket_get_mtu(int fd, int af, size_t *ret) { return 0; } #endif /* NM_IGNORED */ + +int connect_unix_path(int fd, int dir_fd, const char *path) { + _cleanup_close_ int inode_fd = -1; + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + }; + size_t path_len; + socklen_t salen; + + assert(fd >= 0); + assert(dir_fd == AT_FDCWD || dir_fd >= 0); + assert(path); + + /* Connects to the specified AF_UNIX socket in the file system. Works around the 108 byte size limit + * in sockaddr_un, by going via O_PATH if needed. This hence works for any kind of path. */ + + path_len = strlen(path); + + /* Refuse zero length path early, to make sure AF_UNIX stack won't mistake this for an abstract + * namespace path, since first char is NUL */ + if (path_len <= 0) + return -EINVAL; + + if (dir_fd == AT_FDCWD && path_len < sizeof(sa.un.sun_path)) { + memcpy(sa.un.sun_path, path, path_len + 1); + salen = offsetof(struct sockaddr_un, sun_path) + path_len + 1; + } else { + const char *proc; + size_t proc_len; + + /* If dir_fd is specified, then we need to go the indirect O_PATH route, because connectat() + * does not exist. If the path is too long, we also need to take the indirect route, since we + * can't fit this into a sockaddr_un directly. */ + + inode_fd = openat(dir_fd, path, O_PATH|O_CLOEXEC); + if (inode_fd < 0) + return -errno; + + proc = FORMAT_PROC_FD_PATH(inode_fd); + proc_len = strlen(proc); + + assert(proc_len < sizeof(sa.un.sun_path)); + memcpy(sa.un.sun_path, proc, proc_len + 1); + salen = offsetof(struct sockaddr_un, sun_path) + proc_len + 1; + } + + return RET_NERRNO(connect(fd, &sa.sa, salen)); +} diff --git a/src/libnm-systemd-shared/src/basic/socket-util.h b/src/libnm-systemd-shared/src/basic/socket-util.h index 709da206..cf9a0b35 100644 --- a/src/libnm-systemd-shared/src/basic/socket-util.h +++ b/src/libnm-systemd-shared/src/basic/socket-util.h @@ -131,7 +131,7 @@ static inline int fd_inc_sndbuf(int fd, size_t n) { return fd_set_sndbuf(fd, n, true); } int fd_set_rcvbuf(int fd, size_t n, bool increase); -static inline int fd_inc_rcvbuf(int fd, size_t n) { +static inline int fd_increase_rxbuf(int fd, size_t n) { return fd_set_rcvbuf(fd, n, true); } @@ -226,9 +226,9 @@ struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t leng strnlen(_sa->sun_path, sizeof(_sa->sun_path))+1); \ }) -#define SOCKADDR_LEN(sa) \ +#define SOCKADDR_LEN(saddr) \ ({ \ - const union sockaddr_union *__sa = &(sa); \ + const union sockaddr_union *__sa = &(saddr); \ size_t _len; \ switch (__sa->sa.sa_family) { \ case AF_INET: \ @@ -336,3 +336,5 @@ int socket_get_mtu(int fd, int af, size_t *ret); /* an initializer for struct ucred that initialized all fields to the invalid value appropriate for each */ #define UCRED_INVALID { .pid = 0, .uid = UID_INVALID, .gid = GID_INVALID } + +int connect_unix_path(int fd, int dir_fd, const char *path); diff --git a/src/libnm-systemd-shared/src/basic/stat-util.c b/src/libnm-systemd-shared/src/basic/stat-util.c index fd32f25d..8c5858ff 100644 --- a/src/libnm-systemd-shared/src/basic/stat-util.c +++ b/src/libnm-systemd-shared/src/basic/stat-util.c @@ -39,16 +39,17 @@ int is_symlink(const char *path) { } #endif /* NM_IGNORED */ -int is_dir(const char* path, bool follow) { +int is_dir_full(int atfd, const char* path, bool follow) { struct stat st; int r; - assert(path); + assert(atfd >= 0 || atfd == AT_FDCWD); + assert(atfd >= 0 || path); - if (follow) - r = stat(path, &st); + if (path) + r = fstatat(atfd, path, &st, follow ? 0 : AT_SYMLINK_NOFOLLOW); else - r = lstat(path, &st); + r = fstat(atfd, &st); if (r < 0) return -errno; @@ -56,15 +57,6 @@ int is_dir(const char* path, bool follow) { } #if 0 /* NM_IGNORED */ -int is_dir_fd(int fd) { - struct stat st; - - if (fstat(fd, &st) < 0) - return -errno; - - return !!S_ISDIR(st.st_mode); -} - int is_device_node(const char *path) { struct stat info; @@ -76,13 +68,10 @@ int is_device_node(const char *path) { return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode)); } -int dir_is_empty_at(int dir_fd, const char *path) { +int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) { _cleanup_close_ int fd = -1; - /* Allocate space for at least 3 full dirents, since every dir has at least two entries ("." + - * ".."), and only once we have seen if there's a third we know whether the dir is empty or not. */ - DEFINE_DIRENT_BUFFER(buffer, 3); - struct dirent *de; - ssize_t n; + struct dirent *buf; + size_t m; if (path) { assert(dir_fd >= 0 || dir_fd == AT_FDCWD); @@ -104,15 +93,30 @@ int dir_is_empty_at(int dir_fd, const char *path) { return fd; } - n = getdents64(fd, &buffer, sizeof(buffer)); - if (n < 0) - return -errno; + /* Allocate space for at least 3 full dirents, since every dir has at least two entries ("." + + * ".."), and only once we have seen if there's a third we know whether the dir is empty or not. If + * 'ignore_hidden_or_backup' is true we'll allocate a bit more, since we might skip over a bunch of + * entries that we end up ignoring. */ + m = (ignore_hidden_or_backup ? 16 : 3) * DIRENT_SIZE_MAX; + buf = alloca(m); + + for (;;) { + struct dirent *de; + ssize_t n; + + n = getdents64(fd, buf, m); + if (n < 0) + return -errno; + if (n == 0) + break; - msan_unpoison(&buffer, n); + assert((size_t) n <= m); + msan_unpoison(buf, n); - FOREACH_DIRENT_IN_BUFFER(de, &buffer.de, n) - if (!dot_or_dot_dot(de->d_name)) - return 0; + FOREACH_DIRENT_IN_BUFFER(de, buf, n) + if (!(ignore_hidden_or_backup ? hidden_or_backup_file(de->d_name) : dot_or_dot_dot(de->d_name))) + return 0; + } return 1; } @@ -324,101 +328,6 @@ int fd_verify_directory(int fd) { return stat_verify_directory(&st); } - -int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret) { - const char *t; - - /* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */ - - if (S_ISCHR(mode)) - t = "char"; - else if (S_ISBLK(mode)) - t = "block"; - else - return -ENODEV; - - if (asprintf(ret, "/dev/%s/%u:%u", t, major(devno), minor(devno)) < 0) - return -ENOMEM; - - return 0; -} - -int device_path_make_canonical(mode_t mode, dev_t devno, char **ret) { - _cleanup_free_ char *p = NULL; - int r; - - /* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */ - - assert(ret); - - if (major(devno) == 0 && minor(devno) == 0) { - char *s; - - /* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in - * /dev/block/ and /dev/char/, hence we handle them specially here. */ - - if (S_ISCHR(mode)) - s = strdup("/run/systemd/inaccessible/chr"); - else if (S_ISBLK(mode)) - s = strdup("/run/systemd/inaccessible/blk"); - else - return -ENODEV; - - if (!s) - return -ENOMEM; - - *ret = s; - return 0; - } - - r = device_path_make_major_minor(mode, devno, &p); - if (r < 0) - return r; - - return chase_symlinks(p, NULL, 0, ret, NULL); -} - -int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno) { - mode_t mode; - dev_t devno; - int r; - - /* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/ - * paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device - * path cannot be parsed like this. */ - - if (path_equal(path, "/run/systemd/inaccessible/chr")) { - mode = S_IFCHR; - devno = makedev(0, 0); - } else if (path_equal(path, "/run/systemd/inaccessible/blk")) { - mode = S_IFBLK; - devno = makedev(0, 0); - } else { - const char *w; - - w = path_startswith(path, "/dev/block/"); - if (w) - mode = S_IFBLK; - else { - w = path_startswith(path, "/dev/char/"); - if (!w) - return -ENODEV; - - mode = S_IFCHR; - } - - r = parse_dev(w, &devno); - if (r < 0) - return r; - } - - if (ret_mode) - *ret_mode = mode; - if (ret_devno) - *ret_devno = devno; - - return 0; -} #endif /* NM_IGNORED */ int proc_mounted(void) { diff --git a/src/libnm-systemd-shared/src/basic/stat-util.h b/src/libnm-systemd-shared/src/basic/stat-util.h index 37513a43..56f15534 100644 --- a/src/libnm-systemd-shared/src/basic/stat-util.h +++ b/src/libnm-systemd-shared/src/basic/stat-util.h @@ -13,21 +13,18 @@ #include "missing_stat.h" int is_symlink(const char *path); -int is_dir(const char *path, bool follow); -int is_dir_fd(int fd); -int is_device_node(const char *path); - -int dir_is_empty_at(int dir_fd, const char *path); -static inline int dir_is_empty(const char *path) { - return dir_is_empty_at(AT_FDCWD, path); +int is_dir_full(int atfd, const char *fname, bool follow); +static inline int is_dir(const char *path, bool follow) { + return is_dir_full(AT_FDCWD, path, follow); } +static inline int is_dir_fd(int fd) { + return is_dir_full(fd, NULL, false); +} +int is_device_node(const char *path); -static inline int dir_is_populated(const char *path) { - int r; - r = dir_is_empty(path); - if (r < 0) - return r; - return !r; +int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup); +static inline int dir_is_empty(const char *path, bool ignore_hidden_or_backup) { + return dir_is_empty_at(AT_FDCWD, path, ignore_hidden_or_backup); } bool null_or_empty(struct stat *st) _pure_; @@ -71,29 +68,6 @@ int fd_verify_regular(int fd); int stat_verify_directory(const struct stat *st); int fd_verify_directory(int fd); -/* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the - * specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of - * major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of - * comparing directly >= 0: it's to trick out -Wtype-limits, which would otherwise complain if the type is unsigned, as - * such a test would be pointless in such a case.) */ - -#define DEVICE_MAJOR_VALID(x) \ - ({ \ - typeof(x) _x = (x), _y = 0; \ - _x >= _y && _x < (UINT32_C(1) << 12); \ - \ - }) - -#define DEVICE_MINOR_VALID(x) \ - ({ \ - typeof(x) _x = (x), _y = 0; \ - _x >= _y && _x < (UINT32_C(1) << 20); \ - }) - -int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret); -int device_path_make_canonical(mode_t mode, dev_t devno, char **ret); -int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno); - int proc_mounted(void); bool stat_inode_same(const struct stat *a, const struct stat *b); @@ -119,9 +93,3 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s struct new_statx nsx; \ } var #endif - -static inline bool devid_set_and_equal(dev_t a, dev_t b) { - /* Returns true if a and b definitely refer to the same device. If either is zero, this means "don't - * know" and we'll return false */ - return a == b && a != 0; -} diff --git a/src/libnm-systemd-shared/src/basic/string-util.c b/src/libnm-systemd-shared/src/basic/string-util.c index fea22ec8..7cd4b055 100644 --- a/src/libnm-systemd-shared/src/basic/string-util.c +++ b/src/libnm-systemd-shared/src/basic/string-util.c @@ -1171,4 +1171,31 @@ bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok) { return in_charset(s1, ok) && in_charset(s2, ok); } + +char *string_replace_char(char *str, char old_char, char new_char) { + assert(str); + assert(old_char != '\0'); + assert(new_char != '\0'); + assert(old_char != new_char); + + for (char *p = strchr(str, old_char); p; p = strchr(p + 1, old_char)) + *p = new_char; + + return str; +} + +size_t strspn_from_end(const char *str, const char *accept) { + size_t n = 0; + + if (isempty(str)) + return 0; + + if (isempty(accept)) + return 0; + + for (const char *p = str + strlen(str); p > str && strchr(accept, p[-1]); p--) + n++; + + return n; +} #endif /* NM_IGNORED */ diff --git a/src/libnm-systemd-shared/src/basic/string-util.h b/src/libnm-systemd-shared/src/basic/string-util.h index a1d88fbb..1dd46f7f 100644 --- a/src/libnm-systemd-shared/src/basic/string-util.h +++ b/src/libnm-systemd-shared/src/basic/string-util.h @@ -10,17 +10,18 @@ #include "string-util-fundamental.h" /* What is interpreted as whitespace? */ -#define WHITESPACE " \t\n\r" -#define NEWLINE "\n\r" -#define QUOTES "\"\'" -#define COMMENTS "#;" -#define GLOB_CHARS "*?[" -#define DIGITS "0123456789" -#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" -#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS -#define ALPHANUMERICAL LETTERS DIGITS -#define HEXDIGITS DIGITS "abcdefABCDEF" +#define WHITESPACE " \t\n\r" +#define NEWLINE "\n\r" +#define QUOTES "\"\'" +#define COMMENTS "#;" +#define GLOB_CHARS "*?[" +#define DIGITS "0123456789" +#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" +#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS +#define ALPHANUMERICAL LETTERS DIGITS +#define HEXDIGITS DIGITS "abcdefABCDEF" +#define LOWERCASE_HEXDIGITS DIGITS "abcdef" static inline char* strstr_ptr(const char *haystack, const char *needle) { if (!haystack || !needle) @@ -28,10 +29,6 @@ static inline char* strstr_ptr(const char *haystack, const char *needle) { return strstr(haystack, needle); } -static inline const char* strempty(const char *s) { - return s ?: ""; -} - static inline const char* strnull(const char *s) { return s ?: "(null)"; } @@ -180,13 +177,6 @@ int free_and_strndup(char **p, const char *s, size_t l); bool string_is_safe(const char *p) _pure_; -static inline size_t strlen_ptr(const char *s) { - if (!s) - return 0; - - return strlen(s); -} - DISABLE_WARNING_STRINGOP_TRUNCATION; static inline void strncpy_exact(char *buf, const char *src, size_t buf_len) { strncpy(buf, src, buf_len); @@ -232,3 +222,7 @@ static inline int string_contains_word(const char *string, const char *separator } bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok); + +char *string_replace_char(char *str, char old_char, char new_char); + +size_t strspn_from_end(const char *str, const char *accept); diff --git a/src/libnm-systemd-shared/src/basic/strv.c b/src/libnm-systemd-shared/src/basic/strv.c index f2cb80fe..d9c58633 100644 --- a/src/libnm-systemd-shared/src/basic/strv.c +++ b/src/libnm-systemd-shared/src/basic/strv.c @@ -357,7 +357,7 @@ int strv_split_colon_pairs(char ***t, const char *s) { } #endif /* NM_IGNORED */ -char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool unescape_separators) { +char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separator) { char *r, *e; size_t n, k, m; @@ -367,7 +367,7 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix, k = strlen(separator); m = strlen_ptr(prefix); - if (unescape_separators) /* If there separator is multi-char, we won't know how to escape it. */ + if (escape_separator) /* If the separator was multi-char, we wouldn't know how to escape it. */ assert(k == 1); n = 0; @@ -375,7 +375,7 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix, if (s != l) n += k; - bool needs_escaping = unescape_separators && strchr(*s, separator[0]); + bool needs_escaping = escape_separator && strchr(*s, *separator); n += m + strlen(*s) * (1 + needs_escaping); } @@ -392,11 +392,11 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix, if (prefix) e = stpcpy(e, prefix); - bool needs_escaping = unescape_separators && strchr(*s, separator[0]); + bool needs_escaping = escape_separator && strchr(*s, *separator); if (needs_escaping) for (size_t i = 0; (*s)[i]; i++) { - if ((*s)[i] == separator[0]) + if ((*s)[i] == *separator) *(e++) = '\\'; *(e++) = (*s)[i]; } @@ -409,27 +409,33 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix, return r; } -int strv_push(char ***l, char *value) { - char **c; - size_t n; +int strv_push_with_size(char ***l, size_t *n, char *value) { + /* n is a pointer to a variable to store the size of l. + * If not given (i.e. n is NULL or *n is SIZE_MAX), size will be calculated using strv_length(). + * If n is not NULL, the size after the push will be returned. + * If value is empty, no action is taken and *n is not set. */ if (!value) return 0; - n = strv_length(*l); + size_t size = n ? *n : SIZE_MAX; + if (size == SIZE_MAX) + size = strv_length(*l); /* Check for overflow */ - if (n > SIZE_MAX-2) + if (size > SIZE_MAX-2) return -ENOMEM; - c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + 2), sizeof(char*)); + char **c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(size + 2), sizeof(char*)); if (!c) return -ENOMEM; - c[n] = value; - c[n+1] = NULL; + c[size] = value; + c[size+1] = NULL; *l = c; + if (n) + *n = size + 1; return 0; } @@ -490,10 +496,10 @@ int strv_insert(char ***l, size_t position, char *value) { return free_and_replace(*l, c); } -int strv_consume(char ***l, char *value) { +int strv_consume_with_size(char ***l, size_t *n, char *value) { int r; - r = strv_push(l, value); + r = strv_push_with_size(l, n, value); if (r < 0) free(value); @@ -535,7 +541,7 @@ int strv_prepend(char ***l, const char *value) { return strv_consume_prepend(l, v); } -int strv_extend(char ***l, const char *value) { +int strv_extend_with_size(char ***l, size_t *n, const char *value) { char *v; if (!value) @@ -545,7 +551,7 @@ int strv_extend(char ***l, const char *value) { if (!v) return -ENOMEM; - return strv_consume(l, v); + return strv_consume_with_size(l, n, v); } int strv_extend_front(char ***l, const char *value) { diff --git a/src/libnm-systemd-shared/src/basic/strv.h b/src/libnm-systemd-shared/src/basic/strv.h index 2a858326..87ec6337 100644 --- a/src/libnm-systemd-shared/src/basic/strv.h +++ b/src/libnm-systemd-shared/src/basic/strv.h @@ -35,18 +35,36 @@ size_t strv_length(char * const *l) _pure_; int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates); int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix); int strv_prepend(char ***l, const char *value); -int strv_extend(char ***l, const char *value); + +/* _with_size() are lower-level functions where the size can be provided externally, + * which allows us to skip iterating over the strv to find the end, which saves + * a bit of time and reduces the complexity of appending from O(n²) to O(n). */ + +int strv_extend_with_size(char ***l, size_t *n, const char *value); +static inline int strv_extend(char ***l, const char *value) { + return strv_extend_with_size(l, NULL, value); +} + int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); int strv_extend_front(char ***l, const char *value); -int strv_push(char ***l, char *value); + +int strv_push_with_size(char ***l, size_t *n, char *value); +static inline int strv_push(char ***l, char *value) { + return strv_push_with_size(l, NULL, value); +} int strv_push_pair(char ***l, char *a, char *b); + int strv_insert(char ***l, size_t position, char *value); static inline int strv_push_prepend(char ***l, char *value) { return strv_insert(l, 0, value); } -int strv_consume(char ***l, char *value); +int strv_consume_with_size(char ***l, size_t *n, char *value); +static inline int strv_consume(char ***l, char *value) { + return strv_consume_with_size(l, NULL, value); +} + int strv_consume_pair(char ***l, char *a, char *b); int strv_consume_prepend(char ***l, char *value); @@ -77,7 +95,7 @@ int strv_split_full(char ***t, const char *s, const char *separators, ExtractFla static inline char** strv_split(const char *s, const char *separators) { char **ret; - if (strv_split_full(&ret, s, separators, 0) < 0) + if (strv_split_full(&ret, s, separators, EXTRACT_RETAIN_ESCAPE) < 0) return NULL; return ret; @@ -101,7 +119,7 @@ static inline char** strv_split_newlines(const char *s) { * string in the vector is an empty string. */ int strv_split_colon_pairs(char ***t, const char *s); -char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separtor); +char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separator); static inline char *strv_join(char * const *l, const char *separator) { return strv_join_full(l, separator, NULL, false); } @@ -122,12 +140,6 @@ static inline int strv_from_nulstr(char ***a, const char *nulstr) { bool strv_overlap(char * const *a, char * const *b) _pure_; -#define _STRV_FOREACH(s, l, i) \ - for (typeof(*(l)) *s, *i = (l); (s = i) && *i; i++) - -#define STRV_FOREACH(s, l) \ - _STRV_FOREACH(s, l, UNIQ_T(i, UNIQ)) - #define _STRV_FOREACH_BACKWARDS(s, l, h, i) \ for (typeof(*(l)) *s, *h = (l), *i = ({ \ size_t _len = strv_length(h); \ @@ -246,14 +258,7 @@ int strv_extend_n(char ***l, const char *value, size_t n); int fputstrv(FILE *f, char * const *l, const char *separator, bool *space); #define strv_free_and_replace(a, b) \ - ({ \ - char ***_a = &(a); \ - char ***_b = &(b); \ - strv_free(*_a); \ - (*_a) = (*_b); \ - (*_b) = NULL; \ - 0; \ - }) + free_and_replace_full(a, b, strv_free) extern const struct hash_ops string_strv_hash_ops; int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS); diff --git a/src/libnm-systemd-shared/src/basic/time-util.c b/src/libnm-systemd-shared/src/basic/time-util.c index 8476a650..0c8f4929 100644 --- a/src/libnm-systemd-shared/src/basic/time-util.c +++ b/src/libnm-systemd-shared/src/basic/time-util.c @@ -31,10 +31,10 @@ static clockid_t map_clock_id(clockid_t c) { - /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will - * fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is - * when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on - * those archs. */ + /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, + * clock_gettime() will fail for them. Since they are essentially the same as their non-ALARM + * pendants (their only difference is when timers are set on them), let's just map them + * accordingly. This way, we can get the correct time even on those archs. */ switch (c) { @@ -298,8 +298,8 @@ char *format_timestamp_style( usec_t t, TimestampStyle style) { - /* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our - * generated timestamps may be parsed with parse_timestamp(), and always read the same. */ + /* The weekdays in non-localized (English) form. We use this instead of the localized form, so that + * our generated timestamps may be parsed with parse_timestamp(), and always read the same. */ static const char * const weekdays[] = { [0] = "Sun", [1] = "Mon", @@ -386,8 +386,8 @@ char *format_timestamp_style( /* Append the timezone */ n = strlen(buf); if (utc) { - /* If this is UTC then let's explicitly use the "UTC" string here, because gmtime_r() normally uses the - * obsolete "GMT" instead. */ + /* If this is UTC then let's explicitly use the "UTC" string here, because gmtime_r() + * normally uses the obsolete "GMT" instead. */ if (n + 5 > l) return NULL; /* "UTC" doesn't fit. */ @@ -402,12 +402,14 @@ char *format_timestamp_style( /* The full time zone does not fit in. Yuck. */ if (n + 1 + _POSIX_TZNAME_MAX + 1 > l) - return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that case, complain that it doesn't fit */ - - /* So the time zone doesn't fit in fully, but the caller passed enough space for the POSIX - * minimum time zone length. In this case suppress the timezone entirely, in order not to dump - * an overly long, hard to read string on the user. This should be safe, because the user will - * assume the local timezone anyway if none is shown. And so does parse_timestamp(). */ + return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that + * case, complain that it doesn't fit. */ + + /* So the time zone doesn't fit in fully, but the caller passed enough space for the + * POSIX minimum time zone length. In this case suppress the timezone entirely, in + * order not to dump an overly long, hard to read string on the user. This should be + * safe, because the user will assume the local timezone anyway if none is shown. And + * so does parse_timestamp(). */ } else { buf[n++] = ' '; strcpy(buf + n, tm.tm_zone); @@ -593,7 +595,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { t = b; } - n = MIN((size_t) k, l); + n = MIN((size_t) k, l-1); l -= n; p += n; @@ -705,10 +707,11 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) { tzset(); - /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only - * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because - * there are no nice APIs available to cover this. By accepting the local time zone strings, we make - * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't + /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note + * that we only support the local timezones here, nothing else. Not because we + * wouldn't want to, but simply because there are no nice APIs available to cover + * this. By accepting the local time zone strings, we make sure that all timestamps + * written by format_timestamp() can be parsed correctly, even though we don't * support arbitrary timezone specifications. */ for (j = 0; j <= 1; j++) { @@ -1414,9 +1417,8 @@ int verify_timezone(const char *name, int log_level) { return -EINVAL; for (p = name; *p; p++) { - if (!(*p >= '0' && *p <= '9') && - !(*p >= 'a' && *p <= 'z') && - !(*p >= 'A' && *p <= 'Z') && + if (!ascii_isdigit(*p) && + !ascii_isalpha(*p) && !IN_SET(*p, '-', '_', '+', '/')) return -EINVAL; diff --git a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h index 1c198f6a..0ed99403 100644 --- a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h +++ b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h @@ -2,36 +2,50 @@ #pragma once #ifndef SD_BOOT -#include +# include #endif #include -#include "types-fundamental.h" +#include +#include +#include #define _align_(x) __attribute__((__aligned__(x))) +#define _alignas_(x) __attribute__((__aligned__(__alignof__(x)))) +#define _alignptr_ __attribute__((__aligned__(sizeof(void *)))) +#define _cleanup_(x) __attribute__((__cleanup__(x))) #define _const_ __attribute__((__const__)) -#define _pure_ __attribute__((__pure__)) -#define _section_(x) __attribute__((__section__(x))) +#define _deprecated_ __attribute__((__deprecated__)) +#define _destructor_ __attribute__((__destructor__)) +#define _hidden_ __attribute__((__visibility__("hidden"))) +#define _likely_(x) (__builtin_expect(!!(x), 1)) +#define _malloc_ __attribute__((__malloc__)) +#define _noreturn_ _Noreturn #define _packed_ __attribute__((__packed__)) +#define _printf_(a, b) __attribute__((__format__(printf, a, b))) +#define _public_ __attribute__((__visibility__("default"))) +#define _pure_ __attribute__((__pure__)) #define _retain_ __attribute__((__retain__)) -#define _used_ __attribute__((__used__)) -#define _unused_ __attribute__((__unused__)) -#define _cleanup_(x) __attribute__((__cleanup__(x))) -#define _likely_(x) (__builtin_expect(!!(x), 1)) +#define _returns_nonnull_ __attribute__((__returns_nonnull__)) +#define _section_(x) __attribute__((__section__(x))) +#define _sentinel_ __attribute__((__sentinel__)) #define _unlikely_(x) (__builtin_expect(!!(x), 0)) -#if __GNUC__ >= 7 -#define _fallthrough_ __attribute__((__fallthrough__)) +#define _unused_ __attribute__((__unused__)) +#define _used_ __attribute__((__used__)) +#define _warn_unused_result_ __attribute__((__warn_unused_result__)) +#define _weak_ __attribute__((__weak__)) +#define _weakref_(x) __attribute__((__weakref__(#x))) + +#ifdef __clang__ +# define _alloc_(...) #else -#define _fallthrough_ +# define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__))) #endif -/* Define C11 noreturn without and even on older gcc - * compiler versions */ -#ifndef _noreturn_ -#if __STDC_VERSION__ >= 201112L -#define _noreturn_ _Noreturn + +#if __GNUC__ >= 7 || (defined(__clang__) && __clang_major__ >= 10) +# define _fallthrough_ __attribute__((__fallthrough__)) #else -#define _noreturn_ __attribute__((__noreturn__)) -#endif +# define _fallthrough_ #endif #define XSTRINGIFY(x) #x @@ -53,7 +67,7 @@ #define CONCATENATE(x, y) XCONCATENATE(x, y) #ifdef SD_BOOT - void efi_assert(const char *expr, const char *file, unsigned line, const char *function) _noreturn_; + _noreturn_ void efi_assert(const char *expr, const char *file, unsigned line, const char *function); #ifdef NDEBUG #define assert(expr) @@ -62,10 +76,8 @@ #define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); }) #define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __PRETTY_FUNCTION__) #endif + #define static_assert _Static_assert #define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); }) - - #define memcpy(a, b, c) CopyMem((a), (b), (c)) - #define free(a) FreePool(a) #endif /* This passes the argument through after (if asserts are enabled) checking that it is not null. */ @@ -83,15 +95,22 @@ _expr_; \ }) -#if defined(static_assert) -#define assert_cc(expr) \ - static_assert(expr, #expr) -#else -#define assert_cc(expr) \ - struct CONCATENATE(_assert_struct_, __COUNTER__) { \ - char x[(expr) ? 0 : -1]; \ - } -#endif +#define ASSERT_NONNEG(expr) \ + ({ \ + typeof(expr) _expr_ = (expr), _zero = 0; \ + assert(_expr_ >= _zero); \ + _expr_; \ + }) + +#define ASSERT_SE_NONNEG(expr) \ + ({ \ + typeof(expr) _expr_ = (expr), _zero = 0; \ + assert_se(_expr_ >= _zero); \ + _expr_; \ + }) + +#define assert_cc(expr) static_assert(expr, #expr) + #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) #define UNIQ __COUNTER__ @@ -101,10 +120,10 @@ * on this macro will run concurrently to all other code conditionalized * the same way, there's no ordering or completion enforced. */ #define ONCE __ONCE(UNIQ_T(_once_, UNIQ)) -#define __ONCE(o) \ - ({ \ - static sd_bool (o) = sd_false; \ - __sync_bool_compare_and_swap(&(o), sd_false, sd_true); \ +#define __ONCE(o) \ + ({ \ + static bool (o) = false; \ + __atomic_exchange_n(&(o), true, __ATOMIC_SEQ_CST); \ }) #undef MAX @@ -181,6 +200,27 @@ MIN(_c, z); \ }) +/* Returns true if the passed integer is a positive power of two */ +#define CONST_ISPOWEROF2(x) \ + ((x) > 0 && ((x) & ((x) - 1)) == 0) + +#if 0 /* NM_IGNORED */ +#define ISPOWEROF2(x) \ + __builtin_choose_expr( \ + __builtin_constant_p(x), \ + CONST_ISPOWEROF2(x), \ + ({ \ + const typeof(x) _x = (x); \ + CONST_ISPOWEROF2(_x); \ + })) +#else /* NM_IGNORED */ +#define ISPOWEROF2(x) \ + ({ \ + const typeof(x) _x = (x); \ + CONST_ISPOWEROF2(_x); \ + }) +#endif /* NM_IGNORED */ + #define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b)) #define __LESS_BY(aq, a, bq, b) \ ({ \ @@ -254,7 +294,7 @@ #define IN_SET(x, ...) \ ({ \ - sd_bool _found = sd_false; \ + bool _found = false; \ /* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \ * type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \ * the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \ @@ -263,7 +303,7 @@ assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \ switch (x) { \ FOR_EACH_MAKE_CASE(__VA_ARGS__) \ - _found = sd_true; \ + _found = true; \ break; \ default: \ break; \ @@ -295,19 +335,7 @@ }) static inline size_t ALIGN_TO(size_t l, size_t ali) { - /* sd-boot uses UINTN for size_t, let's make sure SIZE_MAX is correct. */ - assert_cc(SIZE_MAX == ~(size_t)0); - - /* Check that alignment is exponent of 2 */ -#if SIZE_MAX == UINT_MAX - assert(__builtin_popcount(ali) == 1); -#elif SIZE_MAX == ULONG_MAX - assert(__builtin_popcountl(ali) == 1); -#elif SIZE_MAX == ULLONG_MAX - assert(__builtin_popcountll(ali) == 1); -#else - #error "Unexpected size_t" -#endif + assert(ISPOWEROF2(ali)); if (l > SIZE_MAX - (ali - 1)) return SIZE_MAX; /* indicate overflow */ @@ -315,12 +343,20 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) { return ((l + ali - 1) & ~(ali - 1)); } +#define ALIGN4(l) ALIGN_TO(l, 4) +#define ALIGN8(l) ALIGN_TO(l, 8) +#ifndef SD_BOOT +/* libefi also provides ALIGN, and we do not use them in sd-boot explicitly. */ +#define ALIGN(l) ALIGN_TO(l, sizeof(void*)) +#define ALIGN_PTR(p) ((void*) ALIGN((uintptr_t) (p))) +#endif + /* Same as ALIGN_TO but callable in constant contexts. */ #define CONST_ALIGN_TO(l, ali) \ __builtin_choose_expr( \ __builtin_constant_p(l) && \ __builtin_constant_p(ali) && \ - __builtin_popcountll(ali) == 1 && /* is power of 2? */ \ + CONST_ISPOWEROF2(ali) && \ (l <= SIZE_MAX - (ali - 1)), /* overflow? */ \ ((l) + (ali) - 1) & ~((ali) - 1), \ VOID_0) diff --git a/src/libnm-systemd-shared/src/fundamental/sha256.c b/src/libnm-systemd-shared/src/fundamental/sha256.c new file mode 100644 index 00000000..0f3872ae --- /dev/null +++ b/src/libnm-systemd-shared/src/fundamental/sha256.c @@ -0,0 +1,293 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "nm-sd-adapt-shared.h" + +/* Stolen from glibc and converted to our style. In glibc it comes with the following copyright blurb: */ + +/* Functions to compute SHA256 message digest of files or memory blocks. + according to the definition of SHA256 in FIPS 180-2. + Copyright (C) 2007-2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#ifdef SD_BOOT +# include "efi-string.h" +#else +# include +#endif + +#include "macro-fundamental.h" +#include "sha256.h" + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +# define SWAP64(n) \ + (((n) << 56) \ + | (((n) & 0xff00) << 40) \ + | (((n) & 0xff0000) << 24) \ + | (((n) & 0xff000000) << 8) \ + | (((n) >> 8) & 0xff000000) \ + | (((n) >> 24) & 0xff0000) \ + | (((n) >> 40) & 0xff00) \ + | ((n) >> 56)) +#else +# define SWAP(n) (n) +# define SWAP64(n) (n) +#endif + +/* The condition below is from glibc's string/string-inline.c. + * See definition of _STRING_INLINE_unaligned. */ +#if !defined(__mc68020__) && !defined(__s390__) && !defined(__i386__) +# define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__(uint32_t) != 0) +#else +# define UNALIGNED_P(p) false +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (FIPS 180-2:5.1.1) */ +static const uint8_t fillbuf[64] = { + 0x80, 0 /* , 0, 0, ... */ +}; + +/* Constants for SHA256 from FIPS 180-2:4.2.2. */ +static const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +static void sha256_process_block(const void *, size_t, struct sha256_ctx *); + +/* Initialize structure containing state of computation. + (FIPS 180-2:5.3.2) */ +void sha256_init_ctx(struct sha256_ctx *ctx) { + assert(ctx); + + ctx->H[0] = 0x6a09e667; + ctx->H[1] = 0xbb67ae85; + ctx->H[2] = 0x3c6ef372; + ctx->H[3] = 0xa54ff53a; + ctx->H[4] = 0x510e527f; + ctx->H[5] = 0x9b05688c; + ctx->H[6] = 0x1f83d9ab; + ctx->H[7] = 0x5be0cd19; + + ctx->total64 = 0; + ctx->buflen = 0; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) { + /* Take yet unprocessed bytes into account. */ + uint32_t bytes = ctx->buflen; + size_t pad; + + assert(ctx); + assert(resbuf); + + /* Now count remaining bytes. */ + ctx->total64 += bytes; + + pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; + memcpy(&ctx->buffer[bytes], fillbuf, pad); + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + ctx->buffer32[(bytes + pad + 4) / 4] = SWAP(ctx->total[TOTAL64_low] << 3); + ctx->buffer32[(bytes + pad) / 4] = SWAP((ctx->total[TOTAL64_high] << 3) + | (ctx->total[TOTAL64_low] >> 29)); + + /* Process last bytes. */ + sha256_process_block(ctx->buffer, bytes + pad + 8, ctx); + + /* Put result from CTX in first 32 bytes following RESBUF. */ + for (size_t i = 0; i < 8; ++i) + if (UNALIGNED_P(resbuf)) + memcpy((uint8_t*) resbuf + i * sizeof(uint32_t), (uint32_t[]) { SWAP(ctx->H[i]) }, sizeof(uint32_t)); + else + ((uint32_t *) resbuf)[i] = SWAP(ctx->H[i]); + + return resbuf; +} + +void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx) { + assert(buffer); + assert(ctx); + + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + + if (ctx->buflen != 0) { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy(&ctx->buffer[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) { + sha256_process_block(ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) { + if (UNALIGNED_P(buffer)) + while (len > 64) { + memcpy(ctx->buffer, buffer, 64); + sha256_process_block(ctx->buffer, 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else { + sha256_process_block(buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes into internal buffer. */ + if (len > 0) { + size_t left_over = ctx->buflen; + + memcpy(&ctx->buffer[left_over], buffer, len); + left_over += len; + if (left_over >= 64) { + sha256_process_block(ctx->buffer, 64, ctx); + left_over -= 64; + memcpy(ctx->buffer, &ctx->buffer[64], left_over); + } + ctx->buflen = left_over; + } +} + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ +static void sha256_process_block(const void *buffer, size_t len, struct sha256_ctx *ctx) { + const uint32_t *words = buffer; + size_t nwords = len / sizeof(uint32_t); + + assert(buffer); + assert(ctx); + + uint32_t a = ctx->H[0]; + uint32_t b = ctx->H[1]; + uint32_t c = ctx->H[2]; + uint32_t d = ctx->H[3]; + uint32_t e = ctx->H[4]; + uint32_t f = ctx->H[5]; + uint32_t g = ctx->H[6]; + uint32_t h = ctx->H[7]; + + /* First increment the byte count. FIPS 180-2 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. */ + ctx->total64 += len; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (nwords > 0) { + uint32_t W[64]; + uint32_t a_save = a; + uint32_t b_save = b; + uint32_t c_save = c; + uint32_t d_save = d; + uint32_t e_save = e; + uint32_t f_save = f; + uint32_t g_save = g; + uint32_t h_save = h; + + /* Operators defined in FIPS 180-2:4.1.2. */ +#define Ch(x, y, z) ((x & y) ^ (~x & z)) +#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) +#define S0(x) (CYCLIC (x, 2) ^ CYCLIC (x, 13) ^ CYCLIC (x, 22)) +#define S1(x) (CYCLIC (x, 6) ^ CYCLIC (x, 11) ^ CYCLIC (x, 25)) +#define R0(x) (CYCLIC (x, 7) ^ CYCLIC (x, 18) ^ (x >> 3)) +#define R1(x) (CYCLIC (x, 17) ^ CYCLIC (x, 19) ^ (x >> 10)) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) ((w >> s) | (w << (32 - s))) + + /* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */ + for (size_t t = 0; t < 16; ++t) { + W[t] = SWAP (*words); + ++words; + } + for (size_t t = 16; t < 64; ++t) + W[t] = R1 (W[t - 2]) + W[t - 7] + R0 (W[t - 15]) + W[t - 16]; + + /* The actual computation according to FIPS 180-2:6.2.2 step 3. */ + for (size_t t = 0; t < 64; ++t) { + uint32_t T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t]; + uint32_t T2 = S0 (a) + Maj (a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + } + + /* Add the starting values of the context according to FIPS 180-2:6.2.2 + step 4. */ + a += a_save; + b += b_save; + c += c_save; + d += d_save; + e += e_save; + f += f_save; + g += g_save; + h += h_save; + + /* Prepare for the next round. */ + nwords -= 16; + } + + /* Put checksum in context given as argument. */ + ctx->H[0] = a; + ctx->H[1] = b; + ctx->H[2] = c; + ctx->H[3] = d; + ctx->H[4] = e; + ctx->H[5] = f; + ctx->H[6] = g; + ctx->H[7] = h; +} diff --git a/src/libnm-systemd-shared/src/fundamental/sha256.h b/src/libnm-systemd-shared/src/fundamental/sha256.h new file mode 100644 index 00000000..f296f76a --- /dev/null +++ b/src/libnm-systemd-shared/src/fundamental/sha256.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "stdint.h" + +#define SHA256_DIGEST_SIZE 32 + +struct sha256_ctx { + uint32_t H[8]; + + union { + uint64_t total64; +#define TOTAL64_low (1 - (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) +#define TOTAL64_high (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + uint32_t total[2]; + }; + + uint32_t buflen; + + union { + uint8_t buffer[128]; /* NB: always correctly aligned for UINT32. */ + uint32_t buffer32[32]; + uint64_t buffer64[16]; + }; +}; + +void sha256_init_ctx(struct sha256_ctx *ctx); +void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf); +void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx); diff --git a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c index 73569765..33f2d860 100644 --- a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c +++ b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c @@ -3,10 +3,10 @@ #include "nm-sd-adapt-shared.h" #ifndef SD_BOOT -#include - -#include "macro.h" +# include #endif + +#include "macro-fundamental.h" #include "string-util-fundamental.h" sd_char *startswith(const sd_char *s, const sd_char *prefix) { @@ -80,36 +80,27 @@ sd_char* endswith_no_case(const sd_char *s, const sd_char *postfix) { } #if 0 /* NM_IGNORED */ -#ifdef SD_BOOT -static sd_bool isdigit(sd_char a) { - return a >= '0' && a <= '9'; -} -#endif - -static sd_bool is_alpha(sd_char a) { - /* Locale independent version of isalpha(). */ - return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z'); -} - -static sd_bool is_valid_version_char(sd_char a) { - return isdigit(a) || is_alpha(a) || IN_SET(a, '~', '-', '^', '.'); +static bool is_valid_version_char(sd_char a) { + return ascii_isdigit(a) || ascii_isalpha(a) || IN_SET(a, '~', '-', '^', '.'); } -sd_int strverscmp_improved(const sd_char *a, const sd_char *b) { - - /* This is based on RPM's rpmvercmp(). But this explicitly handles '-' and '.', as we usually - * want to directly compare strings which contain both version and release; e.g. +int strverscmp_improved(const sd_char *a, const sd_char *b) { + /* This function is similar to strverscmp(3), but it treats '-' and '.' as separators. + * + * The logic is based on rpm's rpmvercmp(), but unlike rpmvercmp(), it distiguishes e.g. + * '123a' and '123.a', with '123a' being newer. + * + * It allows direct comparison of strings which contain both a version and a release; e.g. * '247.2-3.1.fc33.x86_64' or '5.11.0-0.rc5.20210128git76c057c84d28.137.fc34'. - * Unlike rpmvercmp(), this distiguishes e.g. 123a and 123.a, and 123a is newer. * - * This splits the input strings into segments. Each segment is numeric or alpha, and may be + * The input string is split into segments. Each segment is numeric or alphabetic, and may be * prefixed with the following: * '~' : used for pre-releases, a segment prefixed with this is the oldest, * '-' : used for the separator between version and release, * '^' : used for patched releases, a segment with this is newer than one with '-'. * '.' : used for point releases. - * Note, no prefix segment is the newest. All non-supported characters are dropped, and - * handled as a separator of segments, e.g., 123_a is equivalent to 123a. + * Note that no prefix segment is the newest. All non-supported characters are dropped, and + * handled as a separator of segments, e.g., '123_a' is equivalent to '123a'. * * By using this, version strings can be sorted like following: * (older) 122.1 @@ -126,12 +117,12 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) { * (newer) 124-1 */ - if (isempty(a) || isempty(b)) - return strcmp_ptr(a, b); + a = strempty(a); + b = strempty(b); for (;;) { const sd_char *aa, *bb; - sd_int r; + int r; /* Drop leading invalid characters. */ while (*a != '\0' && !is_valid_version_char(*a)) @@ -152,7 +143,7 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) { } /* If at least one string reaches the end, then longer is newer. - * Note that except for '~' prefixed segments, a string has more segments is newer. + * Note that except for '~' prefixed segments, a string which has more segments is newer. * So, this check must be after the '~' check. */ if (*a == '\0' || *b == '\0') return CMP(*a, *b); @@ -188,20 +179,25 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) { b++; } - if (isdigit(*a) || isdigit(*b)) { + if (ascii_isdigit(*a) || ascii_isdigit(*b)) { + /* Find the leading numeric segments. One may be an empty string. So, + * numeric segments are always newer than alpha segments. */ + for (aa = a; ascii_isdigit(*aa); aa++) + ; + for (bb = b; ascii_isdigit(*bb); bb++) + ; + + /* Check if one of the strings was empty, but the other not. */ + r = CMP(a != aa, b != bb); + if (r != 0) + return r; + /* Skip leading '0', to make 00123 equivalent to 123. */ while (*a == '0') a++; while (*b == '0') b++; - /* Find the leading numeric segments. One may be an empty string. So, - * numeric segments are always newer than alpha segments. */ - for (aa = a; isdigit(*aa); aa++) - ; - for (bb = b; isdigit(*bb); bb++) - ; - /* To compare numeric segments without parsing their values, first compare the * lengths of the segments. Eg. 12345 vs 123, longer is newer. */ r = CMP(aa - a, bb - b); @@ -209,18 +205,18 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) { return r; /* Then, compare them as strings. */ - r = strncmp(a, b, aa - a); + r = CMP(strncmp(a, b, aa - a), 0); if (r != 0) return r; } else { /* Find the leading non-numeric segments. */ - for (aa = a; is_alpha(*aa); aa++) + for (aa = a; ascii_isalpha(*aa); aa++) ; - for (bb = b; is_alpha(*bb); bb++) + for (bb = b; ascii_isalpha(*bb); bb++) ; /* Note that the segments are usually not NUL-terminated. */ - r = strncmp(a, b, MIN(aa - a, bb - b)); + r = CMP(strncmp(a, b, MIN(aa - a, bb - b)), 0); if (r != 0) return r; @@ -230,7 +226,7 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) { return r; } - /* The current segments are equivalent. Let's compare the next one. */ + /* The current segments are equivalent. Let's move to the next one. */ a = aa; b = bb; } diff --git a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h index dc0c1202..ecf32e51 100644 --- a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h +++ b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h @@ -2,54 +2,62 @@ #pragma once #ifdef SD_BOOT -#include -#include +# include +# include +# include "efi-string.h" #else -#include +# include #endif #include "macro-fundamental.h" #ifdef SD_BOOT -#define strlen(a) StrLen((a)) -#define strcmp(a, b) StrCmp((a), (b)) -#define strncmp(a, b, n) StrnCmp((a), (b), (n)) -#define strcasecmp(a, b) StriCmp((a), (b)) -#define STR_C(str) (L ## str) -#define memcmp(a, b, n) CompareMem(a, b, n) +# define strlen strlen16 +# define strcmp strcmp16 +# define strncmp strncmp16 +# define strcasecmp strcasecmp16 +# define strncasecmp strncasecmp16 +# define STR_C(str) (L ## str) +typedef char16_t sd_char; #else -#define STR_C(str) (str) +# define STR_C(str) (str) +typedef char sd_char; #endif #define streq(a,b) (strcmp((a),(b)) == 0) #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) #define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) -#ifndef SD_BOOT #define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) -#endif -static inline sd_int strcmp_ptr(const sd_char *a, const sd_char *b) { +static inline int strcmp_ptr(const sd_char *a, const sd_char *b) { if (a && b) return strcmp(a, b); return CMP(a, b); } -static inline sd_int strcasecmp_ptr(const sd_char *a, const sd_char *b) { +static inline int strcasecmp_ptr(const sd_char *a, const sd_char *b) { if (a && b) return strcasecmp(a, b); return CMP(a, b); } -static inline sd_bool streq_ptr(const sd_char *a, const sd_char *b) { +static inline bool streq_ptr(const sd_char *a, const sd_char *b) { return strcmp_ptr(a, b) == 0; } -static inline sd_bool strcaseeq_ptr(const sd_char *a, const sd_char *b) { +static inline bool strcaseeq_ptr(const sd_char *a, const sd_char *b) { return strcasecmp_ptr(a, b) == 0; } +static inline size_t strlen_ptr(const sd_char *s) { + if (!s) + return 0; + + return strlen(s); +} + sd_char *startswith(const sd_char *s, const sd_char *prefix) _pure_; #ifndef SD_BOOT sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_; @@ -57,15 +65,23 @@ sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_; sd_char *endswith(const sd_char *s, const sd_char *postfix) _pure_; sd_char *endswith_no_case(const sd_char *s, const sd_char *postfix) _pure_; -static inline sd_bool isempty(const sd_char *a) { +static inline bool isempty(const sd_char *a) { return !a || a[0] == '\0'; } -static inline const sd_char *yes_no(sd_bool b) { +static inline const sd_char *strempty(const sd_char *s) { + return s ?: STR_C(""); +} + +static inline const sd_char *yes_no(bool b) { return b ? STR_C("yes") : STR_C("no"); } -sd_int strverscmp_improved(const sd_char *a, const sd_char *b); +static inline const sd_char* comparison_operator(int result) { + return result < 0 ? STR_C("<") : result > 0 ? STR_C(">") : STR_C("=="); +} + +int strverscmp_improved(const sd_char *a, const sd_char *b); /* Like startswith(), but operates on arbitrary memory blocks */ static inline void *memory_startswith(const void *p, size_t sz, const sd_char *token) { @@ -82,3 +98,19 @@ static inline void *memory_startswith(const void *p, size_t sz, const sd_char *t return (uint8_t*) p + n; } + +#define _STRV_FOREACH(s, l, i) \ + for (typeof(*(l)) *s, *i = (l); (s = i) && *i; i++) + +#define STRV_FOREACH(s, l) \ + _STRV_FOREACH(s, l, UNIQ_T(i, UNIQ)) + +static inline bool ascii_isdigit(sd_char a) { + /* A pure ASCII, locale independent version of isdigit() */ + return a >= '0' && a <= '9'; +} + +static inline bool ascii_isalpha(sd_char a) { + /* A pure ASCII, locale independent version of isalpha() */ + return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z'); +} diff --git a/src/libnm-systemd-shared/src/fundamental/types-fundamental.h b/src/libnm-systemd-shared/src/fundamental/types-fundamental.h deleted file mode 100644 index 5977e40c..00000000 --- a/src/libnm-systemd-shared/src/fundamental/types-fundamental.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/* This defines a number of basic types that are one thing in userspace and another in the UEFI environment, - * but mostly the same in concept and behaviour. - * - * Note: if the definition of these types/values has slightly different semantics in userspace and in the - * UEFI environment then please prefix its name with "sd_" to make clear these types have special semantics, - * and *we* defined them. Otherwise, if the types are effectively 100% identical in behaviour in userspace - * and UEFI environment you can omit the prefix. (Examples: sd_char is 8 bit in userspace and 16 bit in UEFI - * space hence it should have the sd_ prefix; but size_t in userspace and UINTN in UEFI environment are 100% - * defined the same way ultimately, hence it's OK to just define size_t as alias to UINTN in UEFI - * environment, so that size_t can be used everywhere, without any "sd_" prefix.) - * - * Note: we generally prefer the userspace names of types and concepts. i.e. if in doubt please name types - * after the userspace vocabulary, and let's keep UEFI vocabulary specific to the UEFI build environment. */ - -#ifdef SD_BOOT -#include - -typedef BOOLEAN sd_bool; -typedef CHAR16 sd_char; -typedef INTN sd_int; -typedef UINTN size_t; - -#define sd_true TRUE -#define sd_false FALSE -#else -#include -#include - -typedef bool sd_bool; -typedef char sd_char; -typedef int sd_int; - -#define sd_true true -#define sd_false false - -#endif diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.c b/src/libnm-systemd-shared/src/shared/dns-domain.c index e932b693..7bba3b18 100644 --- a/src/libnm-systemd-shared/src/shared/dns-domain.c +++ b/src/libnm-systemd-shared/src/shared/dns-domain.c @@ -9,6 +9,7 @@ #include "alloc-util.h" #include "dns-domain.h" +#include "glyph-util.h" #include "hashmap.h" #include "hexdecoct.h" #include "hostname-util.h" @@ -239,9 +240,8 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) { sz -= 2; } else if (IN_SET(*p, '_', '-') || - (*p >= '0' && *p <= '9') || - (*p >= 'a' && *p <= 'z') || - (*p >= 'A' && *p <= 'Z')) { + ascii_isdigit(*p) || + ascii_isalpha(*p)) { /* Proper character */ @@ -456,12 +456,8 @@ int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_r return r; } - if (!first) - n++; - else - first = false; - - n += r; + n += r + !first; + first = false; } finish: @@ -919,15 +915,13 @@ static bool srv_type_label_is_valid(const char *label, size_t n) { return false; /* Second char must be a letter */ - if (!(label[1] >= 'A' && label[1] <= 'Z') && - !(label[1] >= 'a' && label[1] <= 'z')) + if (!ascii_isalpha(label[1])) return false; /* Third and further chars must be alphanumeric or a hyphen */ for (k = 2; k < n; k++) { - if (!(label[k] >= 'A' && label[k] <= 'Z') && - !(label[k] >= 'a' && label[k] <= 'z') && - !(label[k] >= '0' && label[k] <= '9') && + if (!ascii_isalpha(label[k]) && + !ascii_isdigit(label[k]) && label[k] != '-') return false; } @@ -1035,10 +1029,10 @@ static bool dns_service_name_label_is_valid(const char *label, size_t n) { return dns_service_name_is_valid(s); } -int dns_service_split(const char *joined, char **_name, char **_type, char **_domain) { +int dns_service_split(const char *joined, char **ret_name, char **ret_type, char **ret_domain) { _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL; - const char *p = joined, *q = NULL, *d = NULL; - char a[DNS_LABEL_MAX], b[DNS_LABEL_MAX], c[DNS_LABEL_MAX]; + const char *p = joined, *q = NULL, *d = joined; + char a[DNS_LABEL_MAX+1], b[DNS_LABEL_MAX+1], c[DNS_LABEL_MAX+1]; int an, bn, cn, r; unsigned x = 0; @@ -1058,6 +1052,9 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do return bn; if (bn > 0) { + if (!srv_type_label_is_valid(b, bn)) + goto finish; + x++; /* If there was a second label, try to get the third one */ @@ -1066,64 +1063,58 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do if (cn < 0) return cn; - if (cn > 0) + if (cn > 0 && srv_type_label_is_valid(c, cn)) x++; - } else - cn = 0; - } else - an = 0; - - if (x >= 2 && srv_type_label_is_valid(b, bn)) { + } + } - if (x >= 3 && srv_type_label_is_valid(c, cn)) { + switch (x) { + case 2: + if (!srv_type_label_is_valid(a, an)) + break; - if (dns_service_name_label_is_valid(a, an)) { - /* OK, got . . . */ + /* OK, got . . */ - name = strndup(a, an); - if (!name) - return -ENOMEM; + name = NULL; - type = strjoin(b, ".", c); - if (!type) - return -ENOMEM; + type = strjoin(a, ".", b); + if (!type) + return -ENOMEM; - d = p; - goto finish; - } + d = q; + break; - } else if (srv_type_label_is_valid(a, an)) { + case 3: + if (!dns_service_name_label_is_valid(a, an)) + break; - /* OK, got . . */ + /* OK, got . . . */ - name = NULL; + name = strndup(a, an); + if (!name) + return -ENOMEM; - type = strjoin(a, ".", b); - if (!type) - return -ENOMEM; + type = strjoin(b, ".", c); + if (!type) + return -ENOMEM; - d = q; - goto finish; - } + d = p; + break; } - name = NULL; - type = NULL; - d = joined; - finish: r = dns_name_normalize(d, 0, &domain); if (r < 0) return r; - if (_domain) - *_domain = TAKE_PTR(domain); + if (ret_domain) + *ret_domain = TAKE_PTR(domain); - if (_type) - *_type = TAKE_PTR(type); + if (ret_type) + *ret_type = TAKE_PTR(type); - if (_name) - *_name = TAKE_PTR(name); + if (ret_name) + *ret_name = TAKE_PTR(name); return 0; } @@ -1303,7 +1294,7 @@ int dns_name_apply_idna(const char *name, char **ret) { r = sym_idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t, IDN2_NFC_INPUT | IDN2_TRANSITIONAL); - log_debug("idn2_lookup_u8: %s → %s", name, t); + log_debug("idn2_lookup_u8: %s %s %s", name, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), t); if (r == IDN2_OK) { if (!startswith(name, "xn--")) { _cleanup_free_ char *s = NULL; @@ -1317,8 +1308,9 @@ int dns_name_apply_idna(const char *name, char **ret) { } if (!streq_ptr(name, s)) { - log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.", - name, t, s); + log_debug("idn2 roundtrip failed: \"%s\" %s \"%s\" %s \"%s\", ignoring.", + name, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), t, + special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), s); *ret = NULL; return 0; } diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.h b/src/libnm-systemd-shared/src/shared/dns-domain.h index ec174c0e..828e924d 100644 --- a/src/libnm-systemd-shared/src/shared/dns-domain.h +++ b/src/libnm-systemd-shared/src/shared/dns-domain.h @@ -42,8 +42,8 @@ static inline int dns_name_normalize(const char *s, DNSLabelFlags flags, char ** static inline int dns_name_is_valid(const char *s) { int r; - /* dns_name_normalize() verifies as a side effect */ - r = dns_name_normalize(s, 0, NULL); + /* dns_name_concat() verifies as a side effect */ + r = dns_name_concat(s, NULL, 0, NULL); if (r == -EINVAL) return 0; if (r < 0) @@ -90,7 +90,7 @@ bool dnssd_srv_type_is_valid(const char *name); bool dns_service_name_is_valid(const char *name); int dns_service_join(const char *name, const char *type, const char *domain, char **ret); -int dns_service_split(const char *joined, char **name, char **type, char **domain); +int dns_service_split(const char *joined, char **ret_name, char **ret_type, char **ret_domain); int dns_name_suffix(const char *name, unsigned n_labels, const char **ret); int dns_name_count_labels(const char *name); diff --git a/src/libnmc-base/nm-client-utils.c b/src/libnmc-base/nm-client-utils.c index e2ed7fc2..4ce1ac6c 100644 --- a/src/libnmc-base/nm-client-utils.c +++ b/src/libnmc-base/nm-client-utils.c @@ -305,7 +305,7 @@ NM_UTILS_LOOKUP_STR_DEFINE( NM_UTILS_LOOKUP_ITEM(NM_DEVICE_STATE_UNKNOWN, N_("unknown")), ); static NM_UTILS_LOOKUP_STR_DEFINE( - _device_state_to_string, + _device_state_externally_to_string, NMDeviceState, NM_UTILS_LOOKUP_DEFAULT(NULL), NM_UTILS_LOOKUP_ITEM(NM_DEVICE_STATE_PREPARE, N_("connecting (externally)")), @@ -330,7 +330,7 @@ nmc_device_state_to_string_with_external(NMDevice *device) if ((ac = nm_device_get_active_connection(device)) && NM_FLAGS_HAS(nm_active_connection_get_state_flags(ac), NM_ACTIVATION_STATE_FLAG_EXTERNAL) - && (s = _device_state_to_string(state))) + && (s = _device_state_externally_to_string(state))) return s; return nmc_device_state_to_string(state); diff --git a/src/libnmc-base/nm-polkit-listener.c b/src/libnmc-base/nm-polkit-listener.c index 39a06bc6..e7972faa 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/libnmc-base/nm-vpn-helpers.c b/src/libnmc-base/nm-vpn-helpers.c index e2c0c394..7ad5bee5 100644 --- a/src/libnmc-base/nm-vpn-helpers.c +++ b/src/libnmc-base/nm-vpn-helpers.c @@ -199,13 +199,13 @@ nm_vpn_openconnect_authenticate_helper(const char *host, const char *const *iter; const char *path; const char *const DEFAULT_PATHS[] = { - "/sbin/", - "/usr/sbin/", - "/usr/local/sbin/", - "/bin/", - "/usr/bin/", - "/usr/local/bin/", - NULL, + "/sbin/", + "/usr/sbin/", + "/usr/local/sbin/", + "/bin/", + "/usr/bin/", + "/usr/local/bin/", + NULL, }; path = nm_utils_file_search_in_paths("openconnect", @@ -247,570 +247,3 @@ nm_vpn_openconnect_authenticate_helper(const char *host, return TRUE; } - -static gboolean -_wg_complete_peer(GPtrArray **p_peers, - NMWireGuardPeer *peer_take, - gsize peer_start_line_nr, - const char *filename, - GError **error) -{ - nm_auto_unref_wgpeer NMWireGuardPeer *peer = peer_take; - gs_free_error GError *local = NULL; - - if (!peer) - return TRUE; - - if (!nm_wireguard_peer_is_valid(peer, TRUE, TRUE, &local)) { - nm_utils_error_set(error, - NM_UTILS_ERROR_UNKNOWN, - _("Invalid peer starting at %s:%zu: %s"), - filename, - peer_start_line_nr, - local->message); - return FALSE; - } - - if (!*p_peers) - *p_peers = g_ptr_array_new_with_free_func((GDestroyNotify) nm_wireguard_peer_unref); - g_ptr_array_add(*p_peers, g_steal_pointer(&peer)); - return TRUE; -} - -static gboolean -_line_match(char *line, const char *key, gsize key_len, const char **out_key, char **out_value) -{ - nm_assert(line); - nm_assert(key); - nm_assert(strlen(key) == key_len); - nm_assert(!strchr(key, '=')); - nm_assert(out_key && !*out_key); - nm_assert(out_value && !*out_value); - - /* Note that `wg-quick` (linux.bash) does case-insensitive comparison (shopt -s nocasematch). - * `wg setconf` does case-insensitive comparison too (with strncasecmp, which is locale dependent). - * - * We do a case-insensitive comparison of the key, however in a locale-independent manner. */ - - if (g_ascii_strncasecmp(line, key, key_len) != 0) - return FALSE; - - if (line[key_len] != '=') - return FALSE; - - *out_key = key; - *out_value = &line[key_len + 1]; - return TRUE; -} - -#define line_match(line, key, out_key, out_value) \ - _line_match((line), "" key "", NM_STRLEN(key), (out_key), (out_value)) - -static gboolean -value_split_word(char **line_remainder, char **out_word) -{ - char *str; - - if ((*line_remainder)[0] == '\0') - return FALSE; - - *out_word = *line_remainder; - - str = strchrnul(*line_remainder, ','); - if (str[0] == ',') { - str[0] = '\0'; - *line_remainder = &str[1]; - } else - *line_remainder = str; - return TRUE; -} - -NMConnection * -nm_vpn_wireguard_import(const char *filename, GError **error) -{ - nm_auto_clear_secret_ptr NMSecretPtr file_content = NM_SECRET_PTR_INIT(); - char ifname[IFNAMSIZ]; - gs_free char *uuid = NULL; - gboolean ifname_valid = FALSE; - const char *cstr; - char *line_remainder; - gs_unref_object NMConnection *connection = NULL; - NMSettingConnection *s_con; - NMSettingIPConfig *s_ip4; - NMSettingIPConfig *s_ip6; - NMSettingWireGuard *s_wg; - gs_free_error GError *local = NULL; - enum { - LINE_CONTEXT_INIT, - LINE_CONTEXT_INTERFACE, - LINE_CONTEXT_PEER, - } line_context; - gsize line_nr; - gsize current_peer_start_line_nr = 0; - nm_auto_unref_wgpeer NMWireGuardPeer *current_peer = NULL; - gs_unref_ptrarray GPtrArray *data_dns_search = NULL; - gs_unref_ptrarray GPtrArray *data_dns_v4 = NULL; - gs_unref_ptrarray GPtrArray *data_dns_v6 = NULL; - gs_unref_ptrarray GPtrArray *data_addr_v4 = NULL; - gs_unref_ptrarray GPtrArray *data_addr_v6 = NULL; - gs_unref_ptrarray GPtrArray *data_peers = NULL; - const char *data_private_key = NULL; - gint64 data_table; - guint data_listen_port = 0; - guint data_fwmark = 0; - guint data_mtu = 0; - int is_v4; - guint i; - - g_return_val_if_fail(filename, NULL); - g_return_val_if_fail(!error || !*error, NULL); - - /* contrary to "wg-quick", we never interpret the filename as "/etc/wireguard/$INTERFACE.conf". - * If the filename has no '/', it is interpreted as relative to the current working directory. - * However, we do require a suitable filename suffix and that the name corresponds to the interface - * name. */ - cstr = strrchr(filename, '/'); - cstr = cstr ? &cstr[1] : filename; - if (NM_STR_HAS_SUFFIX(cstr, ".conf")) { - gsize len = strlen(cstr) - NM_STRLEN(".conf"); - - if (len > 0 && len < sizeof(ifname)) { - memcpy(ifname, cstr, len); - ifname[len] = '\0'; - - if (nm_utils_ifname_valid(ifname, NMU_IFACE_KERNEL, NULL)) - ifname_valid = TRUE; - } - } - if (!ifname_valid) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_UNKNOWN, - _("The name of the WireGuard config must be a valid interface " - "name followed by \".conf\"")); - return FALSE; - } - - if (!nm_utils_file_get_contents(-1, - filename, - 10 * 1024 * 1024, - NM_UTILS_FILE_GET_CONTENTS_FLAG_SECRET, - &file_content.str, - &file_content.len, - NULL, - error)) - return NULL; - - /* We interpret the file like `wg-quick up` and `wg setconf` do. - * - * Of course the WireGuard scripts do something fundamentlly different. They - * perform actions to configure the WireGuard link in kernel, add routes and - * addresses, and call resolvconf. It all happens at the time when the script - * run. - * - * This code here instead generates a NetworkManager connection profile so that - * NetworkManager will apply a similar configuration when later activating the profile. */ - -#define _TABLE_AUTO ((gint64) -1) -#define _TABLE_OFF ((gint64) -2) - - data_table = _TABLE_AUTO; - - line_remainder = file_content.str; - line_context = LINE_CONTEXT_INIT; - line_nr = 0; - while (line_remainder[0] != '\0') { - const char *matched_key = NULL; - char *value = NULL; - char *line; - char ch; - gint64 i64; - - line_nr++; - - line = line_remainder; - line_remainder = strchrnul(line, '\n'); - if (line_remainder[0] != '\0') - (line_remainder++)[0] = '\0'; - - /* Drop all spaces and truncate at first '#'. - * See wg's config_read_line(). - * - * Note that wg-quick doesn't do that. - * - * Neither `wg setconf` nor `wg-quick` does a strict parsing. - * We don't either. Just try to interpret the file (mostly) the same as - * they would. - */ - { - gsize l, n; - - n = 0; - for (l = 0; (ch = line[l]); l++) { - if (g_ascii_isspace(ch)) { - /* wg-setconf strips all whitespace before parsing the content. That means, - * *[I nterface]" will be accepted. We do that too. */ - continue; - } - if (ch == '#') - break; - line[n++] = line[l]; - } - if (n == 0) - continue; - line[n] = '\0'; - } - - if (g_ascii_strcasecmp(line, "[Interface]") == 0) { - if (!_wg_complete_peer(&data_peers, - g_steal_pointer(¤t_peer), - current_peer_start_line_nr, - filename, - error)) - return FALSE; - line_context = LINE_CONTEXT_INTERFACE; - continue; - } - - if (g_ascii_strcasecmp(line, "[Peer]") == 0) { - if (!_wg_complete_peer(&data_peers, - g_steal_pointer(¤t_peer), - current_peer_start_line_nr, - filename, - error)) - return FALSE; - current_peer_start_line_nr = line_nr; - current_peer = nm_wireguard_peer_new(); - line_context = LINE_CONTEXT_PEER; - continue; - } - - if (line_context == LINE_CONTEXT_INTERFACE) { - if (line_match(line, "Address", &matched_key, &value)) { - char *value_word; - - while (value_split_word(&value, &value_word)) { - GPtrArray **p_data_addr; - NMIPAddr addr_bin; - int addr_family; - int prefix_len; - - if (!nm_utils_parse_inaddr_prefix_bin(AF_UNSPEC, - value_word, - &addr_family, - &addr_bin, - &prefix_len)) - goto fail_invalid_value; - - p_data_addr = (addr_family == AF_INET) ? &data_addr_v4 : &data_addr_v6; - - if (!*p_data_addr) - *p_data_addr = - g_ptr_array_new_with_free_func((GDestroyNotify) nm_ip_address_unref); - - g_ptr_array_add( - *p_data_addr, - nm_ip_address_new_binary( - addr_family, - &addr_bin, - prefix_len == -1 ? ((addr_family == AF_INET) ? 32 : 128) : prefix_len, - NULL)); - } - continue; - } - - if (line_match(line, "MTU", &matched_key, &value)) { - i64 = _nm_utils_ascii_str_to_int64(value, 0, 0, G_MAXUINT32, -1); - if (i64 == -1) - goto fail_invalid_value; - - /* wg-quick accepts the "MTU" value, but it also fetches routes to - * autodetect it. NetworkManager won't do that, we can only configure - * an explicit MTU or no autodetection will be performed. */ - data_mtu = i64; - continue; - } - - if (line_match(line, "DNS", &matched_key, &value)) { - char *value_word; - - while (value_split_word(&value, &value_word)) { - GPtrArray **p_data_dns; - NMIPAddr addr_bin; - int addr_family; - - if (nm_utils_parse_inaddr_bin(AF_UNSPEC, value_word, &addr_family, &addr_bin)) { - p_data_dns = (addr_family == AF_INET) ? &data_dns_v4 : &data_dns_v6; - if (!*p_data_dns) - *p_data_dns = g_ptr_array_new_with_free_func(g_free); - - g_ptr_array_add(*p_data_dns, - nm_utils_inet_ntop_dup(addr_family, &addr_bin)); - continue; - } - - if (!data_dns_search) - data_dns_search = g_ptr_array_new_with_free_func(g_free); - g_ptr_array_add(data_dns_search, g_strdup(value_word)); - } - continue; - } - - if (line_match(line, "Table", &matched_key, &value)) { - if (nm_streq(value, "auto")) - data_table = _TABLE_AUTO; - else if (nm_streq(value, "off")) - data_table = _TABLE_OFF; - else { - /* we don't support table names from /etc/iproute2/rt_tables - * But we accept hex like `ip route add` would. */ - i64 = _nm_utils_ascii_str_to_int64(value, 0, 0, G_MAXINT32, -1); - if (i64 == -1) - goto fail_invalid_value; - data_table = i64; - } - continue; - } - - if (line_match(line, "PreUp", &matched_key, &value) - || line_match(line, "PreDown", &matched_key, &value) - || line_match(line, "PostUp", &matched_key, &value) - || line_match(line, "PostDown", &matched_key, &value)) { - /* we don't run any scripts. Silently ignore these parameters. */ - continue; - } - - if (line_match(line, "SaveConfig", &matched_key, &value)) { - /* we ignore the setting, but enforce that it's either true or false (like - * wg-quick. */ - if (!NM_IN_STRSET(value, "true", "false")) - goto fail_invalid_value; - continue; - } - - if (line_match(line, "ListenPort", &matched_key, &value)) { - /* we don't use getaddrinfo(), unlike `wg setconf`. Just interpret - * the port as plain decimal number. */ - i64 = _nm_utils_ascii_str_to_int64(value, 10, 0, 0xFFFF, -1); - if (i64 == -1) - goto fail_invalid_value; - data_listen_port = i64; - continue; - } - - if (line_match(line, "FwMark", &matched_key, &value)) { - if (nm_streq(value, "off")) - data_fwmark = 0; - else { - i64 = _nm_utils_ascii_str_to_int64(value, 0, 0, G_MAXINT32, -1); - if (i64 == -1) - goto fail_invalid_value; - data_fwmark = i64; - } - continue; - } - - if (line_match(line, "PrivateKey", &matched_key, &value)) { - if (!nm_utils_base64secret_decode(value, NM_WIREGUARD_PUBLIC_KEY_LEN, NULL)) - goto fail_invalid_secret; - data_private_key = value; - continue; - } - - goto fail_invalid_line; - } - - if (line_context == LINE_CONTEXT_PEER) { - if (line_match(line, "Endpoint", &matched_key, &value)) { - if (!nm_wireguard_peer_set_endpoint(current_peer, value, FALSE)) - goto fail_invalid_value; - continue; - } - - if (line_match(line, "PublicKey", &matched_key, &value)) { - if (!nm_wireguard_peer_set_public_key(current_peer, value, FALSE)) - goto fail_invalid_value; - continue; - } - - if (line_match(line, "AllowedIPs", &matched_key, &value)) { - char *value_word; - - while (value_split_word(&value, &value_word)) { - if (!nm_wireguard_peer_append_allowed_ip(current_peer, value_word, FALSE)) - goto fail_invalid_value; - } - continue; - } - - if (line_match(line, "PersistentKeepalive", &matched_key, &value)) { - if (nm_streq(value, "off")) - i64 = 0; - else { - i64 = _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXUINT16, -1); - if (i64 == -1) - goto fail_invalid_value; - } - nm_wireguard_peer_set_persistent_keepalive(current_peer, i64); - continue; - } - - if (line_match(line, "PresharedKey", &matched_key, &value)) { - if (!nm_wireguard_peer_set_preshared_key(current_peer, value, FALSE)) - goto fail_invalid_secret; - nm_wireguard_peer_set_preshared_key_flags(current_peer, - NM_SETTING_SECRET_FLAG_NONE); - continue; - } - - goto fail_invalid_line; - } - -fail_invalid_line: - nm_utils_error_set(error, - NM_UTILS_ERROR_INVALID_ARGUMENT, - _("unrecognized line at %s:%zu"), - filename, - line_nr); - return FALSE; -fail_invalid_value: - nm_utils_error_set(error, - NM_UTILS_ERROR_INVALID_ARGUMENT, - _("invalid value for '%s' at %s:%zu"), - matched_key, - filename, - line_nr); - return FALSE; -fail_invalid_secret: - nm_utils_error_set(error, - NM_UTILS_ERROR_INVALID_ARGUMENT, - _("invalid secret '%s' at %s:%zu"), - matched_key, - filename, - line_nr); - return FALSE; - } - - if (!_wg_complete_peer(&data_peers, - g_steal_pointer(¤t_peer), - current_peer_start_line_nr, - filename, - error)) - return FALSE; - - connection = nm_simple_connection_new(); - s_con = NM_SETTING_CONNECTION(nm_setting_connection_new()); - nm_connection_add_setting(connection, NM_SETTING(s_con)); - s_ip4 = NM_SETTING_IP_CONFIG(nm_setting_ip4_config_new()); - nm_connection_add_setting(connection, NM_SETTING(s_ip4)); - s_ip6 = NM_SETTING_IP_CONFIG(nm_setting_ip6_config_new()); - nm_connection_add_setting(connection, NM_SETTING(s_ip6)); - s_wg = NM_SETTING_WIREGUARD(nm_setting_wireguard_new()); - nm_connection_add_setting(connection, NM_SETTING(s_wg)); - - uuid = nm_utils_uuid_generate(); - - g_object_set(s_con, - NM_SETTING_CONNECTION_ID, - ifname, - NM_SETTING_CONNECTION_UUID, - uuid, - NM_SETTING_CONNECTION_TYPE, - NM_SETTING_WIREGUARD_SETTING_NAME, - NM_SETTING_CONNECTION_INTERFACE_NAME, - ifname, - NULL); - - g_object_set(s_wg, - NM_SETTING_WIREGUARD_PRIVATE_KEY, - data_private_key, - NM_SETTING_WIREGUARD_LISTEN_PORT, - data_listen_port, - NM_SETTING_WIREGUARD_FWMARK, - data_fwmark, - NM_SETTING_WIREGUARD_MTU, - data_mtu, - NULL); - - if (data_peers) { - for (i = 0; i < data_peers->len; i++) - nm_setting_wireguard_append_peer(s_wg, data_peers->pdata[i]); - } - - for (is_v4 = 0; is_v4 < 2; is_v4++) { - const char *method_disabled = - is_v4 ? NM_SETTING_IP4_CONFIG_METHOD_DISABLED : NM_SETTING_IP6_CONFIG_METHOD_DISABLED; - const char *method_manual = - is_v4 ? NM_SETTING_IP4_CONFIG_METHOD_MANUAL : NM_SETTING_IP6_CONFIG_METHOD_MANUAL; - NMSettingIPConfig *s_ip = is_v4 ? s_ip4 : s_ip6; - GPtrArray *data_dns = is_v4 ? data_dns_v4 : data_dns_v6; - GPtrArray *data_addr = is_v4 ? data_addr_v4 : data_addr_v6; - GPtrArray *data_dns_search2 = data_dns_search; - - if (!data_addr) { - /* When specifying "DNS", we also require an "Address" for the same address - * family. That is because a NMSettingIPConfig cannot have @method_disabled - * and DNS settings at the same time. - * - * We don't have addresses. Silently ignore the DNS setting. */ - data_dns = NULL; - data_dns_search2 = NULL; - } - - g_object_set(s_ip, - NM_SETTING_IP_CONFIG_METHOD, - data_addr ? method_manual : method_disabled, - NULL); - - if (data_addr) { - for (i = 0; i < data_addr->len; i++) - nm_setting_ip_config_add_address(s_ip, data_addr->pdata[i]); - } - if (data_dns) { - for (i = 0; i < data_dns->len; i++) - nm_setting_ip_config_add_dns(s_ip, data_dns->pdata[i]); - - /* Of the wg-quick doesn't specify a search domain, assume the user - * wants to use the domain server for all searches. */ - if (!data_dns_search2) - nm_setting_ip_config_add_dns_search(s_ip, "~"); - } - if (data_dns_search2) { - for (i = 0; i < data_dns_search2->len; i++) - nm_setting_ip_config_add_dns_search(s_ip, data_dns_search2->pdata[i]); - } - - if (data_table == _TABLE_AUTO) { - /* in the "auto" setting, wg-quick adds peer-routes automatically to the main - * table. NetworkManager will do that too, but there are differences: - * - * - NetworkManager (contrary to wg-quick) does not check whether the peer-route is necessary. - * It will always add a route for each allowed-ips range, even if there is already another - * route that would ensure packets to the endpoint are routed via the WireGuard interface. - * If you don't want that, disable "wireguard.peer-routes", and add the necessary routes - * yourself to "ipv4.routes" and "ipv6.routes". - * - * - With "auto", wg-quick also configures policy routing to handle default-routes (/0) to - * avoid routing loops. - * The imported connection profile will have wireguard.ip4-auto-default-route and - * wireguard.ip6-auto-default-route set to "default". It will thus configure wg-quick's - * policy routing if the profile has any AllowedIPs ranges with /0. - */ - } else if (data_table == _TABLE_OFF) { - if (is_v4) { - g_object_set(s_wg, NM_SETTING_WIREGUARD_PEER_ROUTES, FALSE, NULL); - } - } else { - g_object_set(s_ip, NM_SETTING_IP_CONFIG_ROUTE_TABLE, (guint) data_table, NULL); - } - } - - if (!nm_connection_normalize(connection, NULL, NULL, &local)) { - nm_utils_error_set(error, - NM_UTILS_ERROR_INVALID_ARGUMENT, - _("Failed to create WireGuard connection: %s"), - local->message); - return FALSE; - } - - return g_steal_pointer(&connection); -} diff --git a/src/libnmc-base/nm-vpn-helpers.h b/src/libnmc-base/nm-vpn-helpers.h index 678ce1e2..8bea8460 100644 --- a/src/libnmc-base/nm-vpn-helpers.h +++ b/src/libnmc-base/nm-vpn-helpers.h @@ -26,6 +26,4 @@ gboolean nm_vpn_openconnect_authenticate_helper(const char *host, int *status, GError **error); -NMConnection *nm_vpn_wireguard_import(const char *filename, GError **error); - #endif /* __NM_VPN_HELPERS_H__ */ diff --git a/src/libnmc-setting/meson.build b/src/libnmc-setting/meson.build index 8f07ae63..49314cad 100644 --- a/src/libnmc-setting/meson.build +++ b/src/libnmc-setting/meson.build @@ -1,6 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1-or-later if enable_docs + assert(enable_introspection, '-Ddocs=true requires -Dintrospection=true') settings_docs_input_xml = custom_target( 'settings-docs-input.xml', input: [nm_settings_docs_xml_gir, nm_property_infos_xml['nmcli']], @@ -18,7 +19,12 @@ if enable_docs 'settings-docs.h', input: settings_docs_input_xml, output: 'settings-docs.h', - command: [xsltproc, '--output', '@OUTPUT@', join_paths(meson.current_source_dir(), 'settings-docs.xsl'), '@INPUT@'], + command: [ + python.path(), + join_paths(meson.source_root(), 'tools', 'generate-docs-settings-docs.py'), + '--output', '@OUTPUT@', + '--xml', '@INPUT@' + ], ) test( diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c index 4a6f3882..31beb65e 100644 --- a/src/libnmc-setting/nm-meta-setting-desc.c +++ b/src/libnmc-setting/nm-meta-setting-desc.c @@ -30,6 +30,8 @@ static char *secret_flags_to_string(guint32 flags, NMMetaAccessorGetType get_typ (NM_SETTING_SECRET_FLAG_NONE | NM_SETTING_SECRET_FLAG_AGENT_OWNED \ | NM_SETTING_SECRET_FLAG_NOT_SAVED | NM_SETTING_SECRET_FLAG_NOT_REQUIRED) +const NMUtilsEnumValueInfo GOBJECT_ENUM_VALUE_INFOS_GET_FROM_SETTER[1]; + /*****************************************************************************/ static GType @@ -259,11 +261,11 @@ _parse_ip_address(int family, const char *address, GError **error) plen = strchr(ip_str, '/'); if (plen) { *plen++ = '\0'; - if ((prefix = _nm_utils_ascii_str_to_int64(plen, 10, 1, MAX_PREFIX, -1)) == -1) { + if ((prefix = _nm_utils_ascii_str_to_int64(plen, 10, 0, MAX_PREFIX, -1)) == -1) { g_set_error(error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, - _("invalid prefix '%s'; <1-%d> allowed"), + _("invalid prefix '%s'; <0-%d> allowed"), plen, MAX_PREFIX); return NULL; @@ -329,7 +331,7 @@ _parse_ip_route(int family, const char *str, GError **error) g_set_error(error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, - _("invalid prefix '%s'; <1-%d> allowed"), + _("invalid prefix '%s'; <0-%d> allowed"), plen, MAX_PREFIX); return NULL; @@ -1082,7 +1084,7 @@ _get_fcn_gobject_enum(ARGS_GET_FCN) GType gtype = 0; nm_auto_unref_gtypeclass GTypeClass *gtype_class = NULL; nm_auto_unref_gtypeclass GTypeClass *gtype_prop_class = NULL; - const struct _NMUtilsEnumValueInfo *value_infos = NULL; + const NMUtilsEnumValueInfo *value_infos = NULL; gboolean has_gtype = FALSE; nm_auto_unset_gvalue GValue gval = G_VALUE_INIT; gint64 v; @@ -1198,11 +1200,12 @@ _get_fcn_gobject_enum(ARGS_GET_FCN) RETURN_STR_TO_FREE(g_steal_pointer(&s)); } - /* the gobject_enum.value_infos are currently ignored for the getter. They - * only declare additional aliases for the setter. */ - - if (property_info->property_typ_data) + if (property_info->property_typ_data) { value_infos = property_info->property_typ_data->subtype.gobject_enum.value_infos_get; + if (value_infos == GOBJECT_ENUM_VALUE_INFOS_GET_FROM_SETTER) + value_infos = property_info->property_typ_data->subtype.gobject_enum.value_infos; + } + s = _nm_utils_enum_to_str_full(gtype, (int) v, ", ", value_infos); if (!format_numeric) @@ -1676,12 +1679,13 @@ fail: static const char *const * _values_fcn_gobject_enum(ARGS_VALUES_FCN) { - GType gtype = 0; - gboolean has_gtype = FALSE; - gboolean has_minmax = FALSE; - int min = G_MININT; - int max = G_MAXINT; - char **v; + const NMUtilsEnumValueInfo *value_infos = NULL; + GType gtype = 0; + gboolean has_gtype = FALSE; + gboolean has_minmax = FALSE; + int min = G_MININT; + int max = G_MAXINT; + char **v; if (property_info->property_typ_data) { if (property_info->property_typ_data->subtype.gobject_enum.min @@ -1711,10 +1715,29 @@ _values_fcn_gobject_enum(ARGS_VALUES_FCN) } } - /* the gobject_enum.value_infos are currently ignored for the list of - * values. They only declare additional (hidden) aliases for the setter. */ + /* There is a problem. For flags, we don't expand to all the values that we could + * complete for. We only expand to a single flag "FLAG1", but if the property + * is already set to "FLAG2", we should also expand to "FLAG1,FLAG2". */ v = nm_strv_make_deep_copied(nm_utils_enum_get_values(gtype, min, max)); + + if (property_info->property_typ_data + && (value_infos = property_info->property_typ_data->subtype.gobject_enum.value_infos)) { + const guint V_N = NM_PTRARRAY_LEN(v); + guint n; + guint i; + + nm_assert(value_infos[0].nick); + + for (n = 0; value_infos[n].nick;) + n++; + + v = g_realloc(v, (V_N + n + 1) * sizeof(char *)); + for (i = 0; i < n; i++) + v[V_N + i] = g_strdup(value_infos[i].nick); + v[V_N + n] = NULL; + } + return (const char *const *) (*out_to_free = v); } @@ -4456,7 +4479,8 @@ static const NMMetaNestedPropertyInfo meta_nested_property_infos_bond[] = { .property_name = NM_SETTING_BOND_OPTIONS, .property_alias = "primary", .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, - .prompt = N_("Bonding primary interface [none]"), + .prompt = N_("Bonding primary interface"), + .def_hint = "[none]", ) }, { @@ -4472,7 +4496,8 @@ static const NMMetaNestedPropertyInfo meta_nested_property_infos_bond[] = { .property_name = NM_SETTING_BOND_OPTIONS, .property_alias = "miimon", .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, - .prompt = N_("Bonding miimon [100]"), + .prompt = N_("Bonding miimon"), + .def_hint = "[100]", ) }, { @@ -4480,7 +4505,8 @@ static const NMMetaNestedPropertyInfo meta_nested_property_infos_bond[] = { .property_name = NM_SETTING_BOND_OPTIONS, .property_alias = "downdelay", .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, - .prompt = N_("Bonding downdelay [0]"), + .prompt = N_("Bonding downdelay"), + .def_hint = "[0]", ) }, { @@ -4488,7 +4514,8 @@ static const NMMetaNestedPropertyInfo meta_nested_property_infos_bond[] = { .property_name = NM_SETTING_BOND_OPTIONS, .property_alias = "updelay", .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, - .prompt = N_("Bonding updelay [0]"), + .prompt = N_("Bonding updelay"), + .def_hint = "[0]", ) }, { @@ -4496,7 +4523,8 @@ static const NMMetaNestedPropertyInfo meta_nested_property_infos_bond[] = { .property_name = NM_SETTING_BOND_OPTIONS, .property_alias = "arp-interval", .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, - .prompt = N_("Bonding arp-interval [0]"), + .prompt = N_("Bonding arp-interval"), + .def_hint = "[0]", ) }, { @@ -4504,7 +4532,8 @@ static const NMMetaNestedPropertyInfo meta_nested_property_infos_bond[] = { .property_name = NM_SETTING_BOND_OPTIONS, .property_alias = "arp-ip-target", .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, - .prompt = N_("Bonding arp-ip-target [none]"), + .prompt = N_("Bonding arp-ip-target"), + .def_hint = "[none]", ) }, { @@ -4512,7 +4541,8 @@ static const NMMetaNestedPropertyInfo meta_nested_property_infos_bond[] = { .property_name = NM_SETTING_BOND_OPTIONS, .property_alias = "lacp-rate", .inf_flags = NM_META_PROPERTY_INF_FLAG_DONT_ASK, - .prompt = N_("LACP rate ('slow' or 'fast') [slow]"), + .prompt = N_("LACP rate (slow/fast)"), + .def_hint = "[slow]", ) }, }; @@ -5121,7 +5151,7 @@ static const NMMetaPropertyInfo *const property_infos_BOND_PORT[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_BOND_PORT_QUEUE_ID, .is_cli_option = TRUE, .property_alias = "queue-id", - .prompt = N_("Queue ID [0]"), + .prompt = N_("Queue ID"), .property_type = &_pt_gobject_int, ), NULL @@ -5139,37 +5169,37 @@ static const NMMetaPropertyInfo *const property_infos_BRIDGE[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_STP, .is_cli_option = TRUE, .property_alias = "stp", - .prompt = N_("Enable STP [no]"), + .prompt = N_("Enable STP"), .property_type = &_pt_gobject_bool, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_PRIORITY, .is_cli_option = TRUE, .property_alias = "priority", - .prompt = N_("STP priority [32768]"), + .prompt = N_("STP priority"), .property_type = &_pt_gobject_int, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_FORWARD_DELAY, .is_cli_option = TRUE, .property_alias = "forward-delay", - .prompt = N_("Forward delay [15]"), + .prompt = N_("Forward delay"), .property_type = &_pt_gobject_int, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_HELLO_TIME, .is_cli_option = TRUE, .property_alias = "hello-time", - .prompt = N_("Hello time [2]"), + .prompt = N_("Hello time"), .property_type = &_pt_gobject_int, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MAX_AGE, .is_cli_option = TRUE, .property_alias = "max-age", - .prompt = N_("Max age [20]"), + .prompt = N_("Max age"), .property_type = &_pt_gobject_int, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_AGEING_TIME, .is_cli_option = TRUE, .property_alias = "ageing-time", - .prompt = N_("MAC address ageing time [300]"), + .prompt = N_("MAC address ageing time"), .property_type = &_pt_gobject_int, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_GROUP_ADDRESS, @@ -5179,7 +5209,7 @@ static const NMMetaPropertyInfo *const property_infos_BRIDGE[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, .is_cli_option = TRUE, .property_alias = "group-forward-mask", - .prompt = N_("Group forward mask [0]"), + .prompt = N_("Group forward mask"), .property_type = &_pt_gobject_int, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MULTICAST_HASH_MAX, @@ -5221,7 +5251,7 @@ static const NMMetaPropertyInfo *const property_infos_BRIDGE[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MULTICAST_SNOOPING, .is_cli_option = TRUE, .property_alias = "multicast-snooping", - .prompt = N_("Enable IGMP snooping [no]"), + .prompt = N_("Enable IGMP snooping"), .property_type = &_pt_gobject_bool, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT, @@ -5279,19 +5309,19 @@ static const NMMetaPropertyInfo *const property_infos_BRIDGE_PORT[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_PORT_PRIORITY, .is_cli_option = TRUE, .property_alias = "priority", - .prompt = N_("Bridge port priority [32]"), + .prompt = N_("Bridge port priority"), .property_type = &_pt_gobject_int, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_PORT_PATH_COST, .is_cli_option = TRUE, .property_alias = "path-cost", - .prompt = N_("Bridge port STP path cost [100]"), + .prompt = N_("Bridge port STP path cost"), .property_type = &_pt_gobject_int, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, .is_cli_option = TRUE, .property_alias = "hairpin", - .prompt = N_("Hairpin [no]"), + .prompt = N_("Hairpin"), .property_type = &_pt_gobject_bool, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_PORT_VLANS, @@ -5548,6 +5578,21 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = { ), ), ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_MPTCP_FLAGS, + .property_type = &_pt_gobject_enum, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (gobject_enum, + .get_gtype = nm_mptcp_flags_get_type, + .value_infos_get = GOBJECT_ENUM_VALUE_INFOS_GET_FROM_SETTER, + .value_infos = ENUM_VALUE_INFOS ( + { + .value = NM_MPTCP_FLAGS_NONE, + .nick = "default", + }, + ), + ), + ), + ), PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_MUD_URL, .property_type = &_pt_gobject_string, .hide_if_default = TRUE, @@ -5555,6 +5600,9 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT, .property_type = &_pt_gobject_int, ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY, + .property_type = &_pt_gobject_int, + ), NULL }; @@ -5875,7 +5923,7 @@ static const NMMetaPropertyInfo *const property_infos_INFINIBAND[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_INFINIBAND_MTU, .is_cli_option = TRUE, .property_alias = "mtu", - .prompt = N_("MTU [auto]"), + .prompt = N_("MTU"), .property_type = &_pt_gobject_mtu, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (mtu, .get_fcn = MTU_GET_FCN (NMSettingInfiniband, nm_setting_infiniband_get_mtu), @@ -6133,6 +6181,14 @@ static const NMMetaPropertyInfo *const property_infos_IP4_CONFIG[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER, .property_type = &_pt_gobject_string, ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_IP4_CONFIG_LINK_LOCAL, + .property_type = &_pt_gobject_enum, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (gobject_enum, + .get_gtype = nm_setting_ip4_link_local_get_type, + ), + ), + ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_DHCP_REJECT_SERVERS, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_REJECT_SERVERS, .property_type = &_pt_multilist, .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( @@ -6362,6 +6418,12 @@ static const NMMetaPropertyInfo *const property_infos_IP6_CONFIG[] = { .property_type = &_pt_gobject_int, .property_typ_data = &_ptd_gobject_int_timeout, ), + PROPERTY_INFO (NM_SETTING_IP6_CONFIG_MTU, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_MTU, + .property_type = &_pt_gobject_mtu, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (mtu, + .get_fcn = MTU_GET_FCN (NMSettingIP6Config, nm_setting_ip6_config_get_mtu), + ), + ), PROPERTY_INFO (NM_SETTING_IP6_CONFIG_DHCP_DUID, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_DUID, .property_type = &_pt_gobject_string, ), @@ -6493,7 +6555,7 @@ static const NMMetaPropertyInfo *const property_infos_MACSEC[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_MACSEC_ENCRYPT, .is_cli_option = TRUE, .property_alias = "encrypt", - .prompt = N_("Enable encryption [yes]"), + .prompt = N_("Enable encryption"), .property_type = &_pt_gobject_bool, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_MACSEC_MKA_CAK, @@ -6515,7 +6577,7 @@ static const NMMetaPropertyInfo *const property_infos_MACSEC[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_MACSEC_PORT, .is_cli_option = TRUE, .property_alias = "port", - .prompt = N_("SCI port [1]"), + .prompt = N_("SCI port"), .property_type = &_pt_gobject_int, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_MACSEC_VALIDATION, @@ -6562,7 +6624,7 @@ static const NMMetaPropertyInfo *const property_infos_MACVLAN[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_MACVLAN_TAP, .is_cli_option = TRUE, .property_alias = "tap", - .prompt = N_("Tap [no]"), + .prompt = N_("Tap"), .property_type = &_pt_gobject_bool, ), NULL @@ -6638,7 +6700,7 @@ static const NMMetaPropertyInfo *const property_infos_OLPC_MESH[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_OLPC_MESH_CHANNEL, .is_cli_option = TRUE, .property_alias = "channel", - .prompt = N_("OLPC Mesh channel [1]"), + .prompt = N_("OLPC Mesh channel"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, .set_fcn = _set_fcn_olpc_mesh_channel, @@ -6864,7 +6926,7 @@ static const NMMetaPropertyInfo *const property_infos_PROXY[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_PROXY_BROWSER_ONLY, .is_cli_option = TRUE, .property_alias = "browser-only", - .prompt = N_("Browser only [no]"), + .prompt = N_("Browser only"), .property_type = &_pt_gobject_bool ), PROPERTY_INFO_WITH_DESC (NM_SETTING_PROXY_PAC_URL, @@ -7303,19 +7365,19 @@ static const NMMetaPropertyInfo *const property_infos_TUN[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_TUN_PI, .is_cli_option = TRUE, .property_alias = "pi", - .prompt = N_("Enable PI [no]"), + .prompt = N_("Enable PI"), .property_type = &_pt_gobject_bool, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_TUN_VNET_HDR, .is_cli_option = TRUE, .property_alias = "vnet-hdr", - .prompt = N_("Enable VNET header [no]"), + .prompt = N_("Enable VNET header"), .property_type = &_pt_gobject_bool, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_TUN_MULTI_QUEUE, .is_cli_option = TRUE, .property_alias = "multi-queue", - .prompt = N_("Enable multi queue [no]"), + .prompt = N_("Enable multi queue"), .property_type = &_pt_gobject_bool, ), NULL @@ -7441,7 +7503,7 @@ static const NMMetaPropertyInfo *const property_infos_VRF[] = { .is_cli_option = TRUE, .property_alias = "table", .inf_flags = NM_META_PROPERTY_INF_FLAG_REQD, - .prompt = N_("Table [0]"), + .prompt = N_("Table"), .property_type = &_pt_gobject_int, ), NULL @@ -7479,19 +7541,19 @@ static const NMMetaPropertyInfo *const property_infos_VXLAN[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_VXLAN_SOURCE_PORT_MIN, .is_cli_option = TRUE, .property_alias = "source-port-min", - .prompt = N_("Minimum source port [0]"), + .prompt = N_("Minimum source port"), .property_type = &_pt_gobject_int, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_VXLAN_SOURCE_PORT_MAX, .is_cli_option = TRUE, .property_alias = "source-port-max", - .prompt = N_("Maximum source port [0]"), + .prompt = N_("Maximum source port"), .property_type = &_pt_gobject_int, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_VXLAN_DESTINATION_PORT, .is_cli_option = TRUE, .property_alias = "destination-port", - .prompt = N_("Destination port [8472]"), + .prompt = N_("Destination port"), .property_type = &_pt_gobject_int, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_VXLAN_TOS, @@ -7623,7 +7685,7 @@ static const NMMetaPropertyInfo *const property_infos_WIRED[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRED_MTU, .is_cli_option = TRUE, .property_alias = "mtu", - .prompt = N_("MTU [auto]"), + .prompt = N_("MTU"), .property_type = &_pt_gobject_mtu, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (mtu, .get_fcn = MTU_GET_FCN (NMSettingWired, nm_setting_wired_get_mtu), @@ -7817,7 +7879,7 @@ static const NMMetaPropertyInfo *const property_infos_WIRELESS[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_MTU, .is_cli_option = TRUE, .property_alias = "mtu", - .prompt = N_("MTU [auto]"), + .prompt = N_("MTU"), .property_type = &_pt_gobject_mtu, .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (mtu, .get_fcn = MTU_GET_FCN (NMSettingWireless, nm_setting_wireless_get_mtu), diff --git a/src/libnmc-setting/nm-meta-setting-desc.h b/src/libnmc-setting/nm-meta-setting-desc.h index b08d4c08..ca044571 100644 --- a/src/libnmc-setting/nm-meta-setting-desc.h +++ b/src/libnmc-setting/nm-meta-setting-desc.h @@ -24,7 +24,7 @@ struct _NMDevice; "(" NM_SETTING_ADSL_ENCAPSULATION_VCMUX "/" NM_SETTING_ADSL_ENCAPSULATION_LLC ") [none]" #define NM_META_TEXT_PROMPT_CON_TYPE N_("Connection type") -#define NM_META_TEXT_PROMPT_IFNAME N_("Interface name [*]") +#define NM_META_TEXT_PROMPT_IFNAME N_("Interface name") #define NM_META_TEXT_PROMPT_VPN_TYPE N_("VPN type") #define NM_META_TEXT_PROMPT_MASTER N_("Master") diff --git a/src/libnmc-setting/settings-docs-input.xml b/src/libnmc-setting/settings-docs-input.xml index f7552644..87302f0e 100644 --- a/src/libnmc-setting/settings-docs-input.xml +++ b/src/libnmc-setting/settings-docs-input.xml @@ -1,4 +1,192 @@ - + The number of retries for the authentication. Zero means to try indefinitely; -1 means to use a global default. If the global default is not set, the authentication retries for 3 times before failing the connection. Currently, this only applies to 802-1x authentication. The number of retries for the authentication. Zero means to try indefinitely; -1 means to use a global default. If the global default is not set, the authentication retries for 3 times before failing the connection. + + Currently, this only applies to 802-1x authentication. Whether or not the connection should be automatically connected by NetworkManager when the resources for the connection are available. TRUE to automatically activate the connection, FALSE to require manual intervention to activate the connection. Autoconnect happens when the circumstances are suitable. That means for example that the device is currently managed and not active. Autoconnect thus never replaces or competes with an already active profile. Note that autoconnect is not implemented for VPN profiles. See "secondaries" as an alternative to automatically connect VPN profiles. If multiple profiles are ready to autoconnect on the same device, the one with the better "connection.autoconnect-priority" is chosen. If the priorities are equal, then the most recently connected profile is activated. If the profiles were not connected earlier or their "connection.timestamp" is identical, the choice is undefined. Depending on "connection.multi-connect", a profile can (auto)connect only once at a time or multiple times. Whether or not the connection should be automatically connected by NetworkManager when the resources for the connection are available. TRUE to automatically activate the connection, FALSE to require manual intervention to activate the connection. + + Autoconnect happens when the circumstances are suitable. That means for example that the device is currently managed and not active. Autoconnect thus never replaces or competes with an already active profile. + + Note that autoconnect is not implemented for VPN profiles. See "secondaries" as an alternative to automatically connect VPN profiles. + + If multiple profiles are ready to autoconnect on the same device, the one with the better "connection.autoconnect-priority" is chosen. If the priorities are equal, then the most recently connected profile is activated. If the profiles were not connected earlier or their "connection.timestamp" is identical, the choice is undefined. + + Depending on "connection.multi-connect", a profile can (auto)connect only once at a time or multiple times. The autoconnect priority in range -999 to 999. If the connection is set to autoconnect, connections with higher priority will be preferred. The higher number means higher priority. Defaults to 0. Note that this property only matters if there are more than one candidate profile to select for autoconnect. In case of equal priority, the profile used most recently is chosen. The autoconnect priority in range -999 to 999. If the connection is set to autoconnect, connections with higher priority will be preferred. The higher number means higher priority. Defaults to 0. Note that this property only matters if there are more than one candidate profile to select for autoconnect. In case of equal priority, the profile used most recently is chosen. The number of times a connection should be tried when autoactivating before giving up. Zero means forever, -1 means the global default (4 times if not overridden). Setting this to 1 means to try activation only once before blocking autoconnect. Note that after a timeout, NetworkManager will try to autoconnect again. The number of times a connection should be tried when autoactivating before giving up. Zero means forever, -1 means the global default (4 times if not overridden). Setting this to 1 means to try activation only once before blocking autoconnect. Note that after a timeout, NetworkManager will try to autoconnect again. Whether or not slaves of this connection should be automatically brought up when NetworkManager activates this connection. This only has a real effect for master connections. The properties "autoconnect", "autoconnect-priority" and "autoconnect-retries" are unrelated to this setting. The permitted values are: 0: leave slave connections untouched, 1: activate all the slave connections with this connection, -1: default. If -1 (default) is set, global connection.autoconnect-slaves is read to determine the real value. If it is default as well, this fallbacks to 0. Whether or not slaves of this connection should be automatically brought up when NetworkManager activates this connection. This only has a real effect for master connections. The properties "autoconnect", "autoconnect-priority" and "autoconnect-retries" are unrelated to this setting. The permitted values are: 0: leave slave connections untouched, 1: activate all the slave connections with this connection, -1: default. If -1 (default) is set, global connection.autoconnect-slaves is read to determine the real value. If it is default as well, this fallbacks to 0. Whether DNSOverTls (dns-over-tls) is enabled for the connection. DNSOverTls is a technology which uses TLS to encrypt dns traffic. The permitted values are: "yes" (2) use DNSOverTls and disabled fallback, "opportunistic" (1) use DNSOverTls but allow fallback to unencrypted resolution, "no" (0) don't ever use DNSOverTls. If unspecified "default" depends on the plugin used. Systemd-resolved uses global setting. This feature requires a plugin which supports DNSOverTls. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved. Whether DNSOverTls (dns-over-tls) is enabled for the connection. DNSOverTls is a technology which uses TLS to encrypt dns traffic. + + The permitted values are: "yes" (2) use DNSOverTls and disabled fallback, "opportunistic" (1) use DNSOverTls but allow fallback to unencrypted resolution, "no" (0) don't ever use DNSOverTls. If unspecified "default" depends on the plugin used. Systemd-resolved uses global setting. + + This feature requires a plugin which supports DNSOverTls. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved. If greater than zero, delay success of IP addressing until either the timeout is reached, or an IP gateway replies to a ping. If greater than zero, delay success of IP addressing until either the timeout is reached, or an IP gateway replies to a ping. A human readable unique identifier for the connection, like "Work Wi-Fi" or "T-Mobile 3G". A human readable unique identifier for the connection, like "Work Wi-Fi" or "T-Mobile 3G". The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). For software devices this specifies the name of the created device. For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface. The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). + + For software devices this specifies the name of the created device. + + For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface. Whether LLDP is enabled for the connection. Whether LLDP is enabled for the connection. Whether Link-Local Multicast Name Resolution (LLMNR) is enabled for the connection. LLMNR is a protocol based on the Domain Name System (DNS) packet format that allows both IPv4 and IPv6 hosts to perform name resolution for hosts on the same local link. The permitted values are: "yes" (2) register hostname and resolving for the connection, "no" (0) disable LLMNR for the interface, "resolve" (1) do not register hostname but allow resolving of LLMNR host names If unspecified, "default" ultimately depends on the DNS plugin (which for systemd-resolved currently means "yes"). This feature requires a plugin which supports LLMNR. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved. Whether Link-Local Multicast Name Resolution (LLMNR) is enabled for the connection. LLMNR is a protocol based on the Domain Name System (DNS) packet format that allows both IPv4 and IPv6 hosts to perform name resolution for hosts on the same local link. + + The permitted values are: "yes" (2) register hostname and resolving for the connection, "no" (0) disable LLMNR for the interface, "resolve" (1) do not register hostname but allow resolving of LLMNR host names If unspecified, "default" ultimately depends on the DNS plugin (which for systemd-resolved currently means "yes"). + + This feature requires a plugin which supports LLMNR. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved. Interface name of the master device or UUID of the master connection. Interface name of the master device or UUID of the master connection. Whether mDNS is enabled for the connection. The permitted values are: "yes" (2) register hostname and resolving for the connection, "no" (0) disable mDNS for the interface, "resolve" (1) do not register hostname but allow resolving of mDNS host names and "default" (-1) to allow lookup of a global default in NetworkManager.conf. If unspecified, "default" ultimately depends on the DNS plugin (which for systemd-resolved currently means "no"). This feature requires a plugin which supports mDNS. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved. Whether mDNS is enabled for the connection. + + The permitted values are: "yes" (2) register hostname and resolving for the connection, "no" (0) disable mDNS for the interface, "resolve" (1) do not register hostname but allow resolving of mDNS host names and "default" (-1) to allow lookup of a global default in NetworkManager.conf. If unspecified, "default" ultimately depends on the DNS plugin (which for systemd-resolved currently means "no"). + + This feature requires a plugin which supports mDNS. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved. Whether the connection is metered. When updating this property on a currently activated connection, the change takes effect immediately. Whether the connection is metered. + + When updating this property on a currently activated connection, the change takes effect immediately. Whether to configure MPTCP endpoints and the address flags. If MPTCP is enabled in NetworkManager, it will configure the addresses of the interface as MPTCP endpoints. Note that IPv4 loopback addresses (127.0.0.0/8), IPv4 link local addresses (169.254.0.0/16), the IPv6 loopback address (::1), IPv6 link local addresses (fe80::/10), IPv6 unique local addresses (ULA, fc00::/7) and IPv6 privacy extension addresses (rfc3041, ipv6.ip6-privacy) will be excluded from being configured as endpoints. If "disabled" (0x1), MPTCP handling for the interface is disabled and no endpoints are registered. The flag "enabled-on-global-iface" (0x2) means that MPTCP handling is enabled if the interface configures a default route in the main routing table. This choice is per-address family, for example if there is an IPv4 default route 0.0.0.0/0, IPv4 endpoints are configured. The "enabled" (0x4) flag means that MPTCP handling is explicitly enabled. This flag can also be implied from the presence of other flags. If MPTCP handling is enabled, then endpoints will be configured with the specified address flags "signal" (0x10), "subflow" (0x20), "backup" (0x40), "fullmesh" (0x80). See ip-mptcp(8) manual for additional information about the flags. If the flags are zero, the global connection default from NetworkManager.conf is honored. If still unspecified, the fallback is either "disabled" or "enabled-on-global-iface,subflow" depending on "/proc/sys/net/mptcp/enabled". NetworkManager does not change the MPTCP limits nor enable MPTCP via "/proc/sys/net/mptcp/enabled". That is a host configuration which the admin can change via sysctl and ip-mptcp. Strict reverse path filtering (rp_filter) breaks many MPTCP use cases, so when MPTCP handling for IPv4 addresses on the interface is enabled, NetworkManager would loosen the strict reverse path filtering (1) to the loose setting (2). Whether to configure MPTCP endpoints and the address flags. If MPTCP is enabled in NetworkManager, it will configure the addresses of the interface as MPTCP endpoints. Note that IPv4 loopback addresses (127.0.0.0/8), IPv4 link local addresses (169.254.0.0/16), the IPv6 loopback address (::1), IPv6 link local addresses (fe80::/10), IPv6 unique local addresses (ULA, fc00::/7) and IPv6 privacy extension addresses (rfc3041, ipv6.ip6-privacy) will be excluded from being configured as endpoints. + + If "disabled" (0x1), MPTCP handling for the interface is disabled and no endpoints are registered. + + The flag "enabled-on-global-iface" (0x2) means that MPTCP handling is enabled if the interface configures a default route in the main routing table. This choice is per-address family, for example if there is an IPv4 default route 0.0.0.0/0, IPv4 endpoints are configured. + + The "enabled" (0x4) flag means that MPTCP handling is explicitly enabled. This flag can also be implied from the presence of other flags. + + If MPTCP handling is enabled, then endpoints will be configured with the specified address flags "signal" (0x10), "subflow" (0x20), "backup" (0x40), "fullmesh" (0x80). See ip-mptcp(8) manual for additional information about the flags. + + If the flags are zero, the global connection default from NetworkManager.conf is honored. If still unspecified, the fallback is either "disabled" or "enabled-on-global-iface,subflow" depending on "/proc/sys/net/mptcp/enabled". + + NetworkManager does not change the MPTCP limits nor enable MPTCP via "/proc/sys/net/mptcp/enabled". That is a host configuration which the admin can change via sysctl and ip-mptcp. + + Strict reverse path filtering (rp_filter) breaks many MPTCP use cases, so when MPTCP handling for IPv4 addresses on the interface is enabled, NetworkManager would loosen the strict reverse path filtering (1) to the loose setting (2). If configured, set to a Manufacturer Usage Description (MUD) URL that points to manufacturer-recommended network policies for IoT devices. It is transmitted as a DHCPv4 or DHCPv6 option. The value must be a valid URL starting with "https://". The special value "none" is allowed to indicate that no MUD URL is used. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the ultimate default is "none". If configured, set to a Manufacturer Usage Description (MUD) URL that points to manufacturer-recommended network policies for IoT devices. It is transmitted as a DHCPv4 or DHCPv6 option. The value must be a valid URL starting with "https://". + + The special value "none" is allowed to indicate that no MUD URL is used. + + If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the ultimate default is "none". Specifies whether the profile can be active multiple times at a particular moment. The value is of type NMConnectionMultiConnect. Specifies whether the profile can be active multiple times at a particular moment. The value is of type NMConnectionMultiConnect. An array of strings defining what access a given user has to this connection. If this is NULL or empty, all users are allowed to access this connection; otherwise users are allowed if and only if they are in this list. When this is not empty, the connection can be active only when one of the specified users is logged into an active session. Each entry is of the form "[type]:[id]:[reserved]"; for example, "user:dcbw:blah". At this time only the "user" [type] is allowed. Any other values are ignored and reserved for future use. [id] is the username that this permission refers to, which may not contain the ":" character. Any [reserved] information present must be ignored and is reserved for future use. All of [type], [id], and [reserved] must be valid UTF-8. An array of strings defining what access a given user has to this connection. If this is NULL or empty, all users are allowed to access this connection; otherwise users are allowed if and only if they are in this list. When this is not empty, the connection can be active only when one of the specified users is logged into an active session. Each entry is of the form "[type]:[id]:[reserved]"; for example, "user:dcbw:blah". + + At this time only the "user" [type] is allowed. Any other values are ignored and reserved for future use. [id] is the username that this permission refers to, which may not contain the ":" character. Any [reserved] information present must be ignored and is reserved for future use. All of [type], [id], and [reserved] must be valid UTF-8. FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified. FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified. List of connection UUIDs that should be activated when the base connection itself is activated. Currently, only VPN connections are supported. List of connection UUIDs that should be activated when the base connection itself is activated. Currently, only VPN connections are supported. Setting name of the device type of this slave's master connection (eg, "bond"), or NULL if this connection is not a slave. Setting name of the device type of this slave's master connection (eg, "bond"), or NULL if this connection is not a slave. This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. The '$' character is treated special to perform dynamic substitutions at runtime. Currently, supported are "${CONNECTION}", "${DEVICE}", "${MAC}", "${BOOT}", "${RANDOM}". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that "${DEVICE}" corresponds to the interface name of the device and "${MAC}" is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as "$$". For example, set it to "${CONNECTION}-${BOOT}-${DEVICE}" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to "${CONNECTION}" and uses a unique, fixed ID for the connection. This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. + + The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. + + Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. + + The '$' character is treated special to perform dynamic substitutions at runtime. Currently, supported are "${CONNECTION}", "${DEVICE}", "${MAC}", "${BOOT}", "${RANDOM}". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that "${DEVICE}" corresponds to the interface name of the device and "${MAC}" is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as "$$". For example, set it to "${CONNECTION}-${BOOT}-${DEVICE}" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. + + If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to "${CONNECTION}" and uses a unique, fixed ID for the connection. The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved). The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. + + NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved). Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, "802-3-ethernet" or "802-11-wireless" or "bluetooth", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, "vpn" or "bridge", etc). Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, "802-3-ethernet" or "802-11-wireless" or "bluetooth", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, "vpn" or "bridge", etc). A universally unique identifier for the connection, for example generated with libuuid. It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network. For example, it should not be changed when the "id" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or "type" property changes. The UUID must be in the format "2815492f-7e56-435e-b2e9-246bd7cdc664" (ie, contains only hexadecimal characters and "-"). A universally unique identifier for the connection, for example generated with libuuid. It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network. For example, it should not be changed when the "id" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or "type" property changes. + + The UUID must be in the format "2815492f-7e56-435e-b2e9-246bd7cdc664" (ie, contains only hexadecimal characters and "-"). Time in milliseconds to wait for connection to be considered activated. The wait will start after the pre-up dispatcher event. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time. Time in milliseconds to wait for connection to be considered activated. The wait will start after the pre-up dispatcher event. + + The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time. Timeout in milliseconds to wait for device at startup. During boot, devices may take a while to be detected by the driver. This property will cause to delay NetworkManager-wait-online.service and nm-online to give the device a chance to appear. This works by waiting for the given timeout until a compatible device for the profile is available and managed. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time. Timeout in milliseconds to wait for device at startup. During boot, devices may take a while to be detected by the driver. This property will cause to delay NetworkManager-wait-online.service and nm-online to give the device a chance to appear. This works by waiting for the given timeout until a compatible device for the profile is available and managed. + + The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time. The trust level of a the connection. Free form case-insensitive string (for example "Home", "Work", "Public"). NULL or unspecified zone means the connection will be placed in the default zone as defined by the firewall. When updating this property on a currently activated connection, the change takes effect immediately. The trust level of a the connection. Free form case-insensitive string (for example "Home", "Work", "Public"). NULL or unspecified zone means the connection will be placed in the default zone as defined by the firewall. + + When updating this property on a currently activated connection, the change takes effect immediately. If given, specifies the parent interface name or parent connection UUID from which this 6LowPAN interface should be created. If given, specifies the parent interface name or parent connection UUID from which this 6LowPAN interface should be created. List of strings to be matched against the altSubjectName of the certificate presented by the authentication server. If the list is empty, no verification of the server certificate's altSubjectName is performed. List of strings to be matched against the altSubjectName of the certificate presented by the authentication server. If the list is empty, no verification of the server certificate's altSubjectName is performed. Anonymous identity string for EAP authentication methods. Used as the unencrypted identity with EAP types that support different tunneled identity like EAP-TTLS. Anonymous identity string for EAP authentication methods. Used as the unencrypted identity with EAP types that support different tunneled identity like EAP-TTLS. A timeout for the authentication. Zero means the global default; if the global default is not set, the authentication timeout is 25 seconds. A timeout for the authentication. Zero means the global default; if the global default is not set, the authentication timeout is 25 seconds. Contains the CA certificate if used by the EAP method specified in the "eap" property. Certificate data is specified using a "scheme"; three are currently supported: blob, path and pkcs#11 URL. When using the blob scheme this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended. Note that enabling NMSetting8021x:system-ca-certs will override this setting to use the built-in path, if the built-in path is not a directory. Contains the CA certificate if used by the EAP method specified in the "eap" property. + + Certificate data is specified using a "scheme"; three are currently supported: blob, path and pkcs#11 URL. When using the blob scheme this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended. + + Note that enabling NMSetting8021x:system-ca-certs will override this setting to use the built-in path, if the built-in path is not a directory. The password used to access the CA certificate stored in "ca-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. The password used to access the CA certificate stored in "ca-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. Flags indicating how to handle the "ca-cert-password" property. Flags indicating how to handle the "ca-cert-password" property. UTF-8 encoded path to a directory containing PEM or DER formatted certificates to be added to the verification chain in addition to the certificate specified in the "ca-cert" property. If NMSetting8021x:system-ca-certs is enabled and the built-in CA path is an existing directory, then this setting is ignored. UTF-8 encoded path to a directory containing PEM or DER formatted certificates to be added to the verification chain in addition to the certificate specified in the "ca-cert" property. + + If NMSetting8021x:system-ca-certs is enabled and the built-in CA path is an existing directory, then this setting is ignored. Contains the client certificate if used by the EAP method specified in the "eap" property. Certificate data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme (which is backwards compatible with NM 0.7.x) this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. Contains the client certificate if used by the EAP method specified in the "eap" property. + + Certificate data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme (which is backwards compatible with NM 0.7.x) this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. The password used to access the client certificate stored in "client-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. The password used to access the client certificate stored in "client-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. Flags indicating how to handle the "client-cert-password" property. Flags indicating how to handle the "client-cert-password" property. Constraint for server domain name. If set, this list of FQDNs is used as a match requirement for dNSName element(s) of the certificate presented by the authentication server. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using the same comparison. Multiple valid FQDNs can be passed as a ";" delimited list. Constraint for server domain name. If set, this list of FQDNs is used as a match requirement for dNSName element(s) of the certificate presented by the authentication server. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using the same comparison. Multiple valid FQDNs can be passed as a ";" delimited list. Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison. Since version 1.24, multiple valid FQDNs can be passed as a ";" delimited list. Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison. Since version 1.24, multiple valid FQDNs can be passed as a ";" delimited list. The allowed EAP method to be used when authenticating to the network with 802.1x. Valid methods are: "leap", "md5", "tls", "peap", "ttls", "pwd", and "fast". Each method requires different configuration using the properties of this setting; refer to wpa_supplicant documentation for the allowed combinations. The allowed EAP method to be used when authenticating to the network with 802.1x. Valid methods are: "leap", "md5", "tls", "peap", "ttls", "pwd", and "fast". Each method requires different configuration using the properties of this setting; refer to wpa_supplicant documentation for the allowed combinations. Identity string for EAP authentication methods. Often the user's user or login name. Identity string for EAP authentication methods. Often the user's user or login name. Whether the 802.1X authentication is optional. If TRUE, the activation will continue even after a timeout or an authentication failure. Setting the property to TRUE is currently allowed only for Ethernet connections. If set to FALSE, the activation can continue only after a successful authentication. Whether the 802.1X authentication is optional. If TRUE, the activation will continue even after a timeout or an authentication failure. Setting the property to TRUE is currently allowed only for Ethernet connections. If set to FALSE, the activation can continue only after a successful authentication. UTF-8 encoded file path containing PAC for EAP-FAST. UTF-8 encoded file path containing PAC for EAP-FAST. UTF-8 encoded password used for EAP authentication methods. If both the "password" property and the "password-raw" property are specified, "password" is preferred. UTF-8 encoded password used for EAP authentication methods. If both the "password" property and the "password-raw" property are specified, "password" is preferred. Flags indicating how to handle the "password" property. Flags indicating how to handle the "password" property. Password used for EAP authentication methods, given as a byte array to allow passwords in other encodings than UTF-8 to be used. If both the "password" property and the "password-raw" property are specified, "password" is preferred. Password used for EAP authentication methods, given as a byte array to allow passwords in other encodings than UTF-8 to be used. If both the "password" property and the "password-raw" property are specified, "password" is preferred. Flags indicating how to handle the "password-raw" property. Flags indicating how to handle the "password-raw" property. Specifies authentication flags to use in "phase 1" outer authentication using NMSetting8021xAuthFlags options. The individual TLS versions can be explicitly disabled. If a certain TLS disable flag is not set, it is up to the supplicant to allow or forbid it. The TLS options map to tls_disable_tlsv1_x settings. See the wpa_supplicant documentation for more details. Specifies authentication flags to use in "phase 1" outer authentication using NMSetting8021xAuthFlags options. The individual TLS versions can be explicitly disabled. If a certain TLS disable flag is not set, it is up to the supplicant to allow or forbid it. The TLS options map to tls_disable_tlsv1_x settings. See the wpa_supplicant documentation for more details. Enables or disables in-line provisioning of EAP-FAST credentials when FAST is specified as the EAP method in the "eap" property. Recognized values are "0" (disabled), "1" (allow unauthenticated provisioning), "2" (allow authenticated provisioning), and "3" (allow both authenticated and unauthenticated provisioning). See the wpa_supplicant documentation for more details. Enables or disables in-line provisioning of EAP-FAST credentials when FAST is specified as the EAP method in the "eap" property. Recognized values are "0" (disabled), "1" (allow unauthenticated provisioning), "2" (allow authenticated provisioning), and "3" (allow both authenticated and unauthenticated provisioning). See the wpa_supplicant documentation for more details. Forces use of the new PEAP label during key derivation. Some RADIUS servers may require forcing the new PEAP label to interoperate with PEAPv1. Set to "1" to force use of the new PEAP label. See the wpa_supplicant documentation for more details. Forces use of the new PEAP label during key derivation. Some RADIUS servers may require forcing the new PEAP label to interoperate with PEAPv1. Set to "1" to force use of the new PEAP label. See the wpa_supplicant documentation for more details. Forces which PEAP version is used when PEAP is set as the EAP method in the "eap" property. When unset, the version reported by the server will be used. Sometimes when using older RADIUS servers, it is necessary to force the client to use a particular PEAP version. To do so, this property may be set to "0" or "1" to force that specific PEAP version. Forces which PEAP version is used when PEAP is set as the EAP method in the "eap" property. When unset, the version reported by the server will be used. Sometimes when using older RADIUS servers, it is necessary to force the client to use a particular PEAP version. To do so, this property may be set to "0" or "1" to force that specific PEAP version. List of strings to be matched against the altSubjectName of the certificate presented by the authentication server during the inner "phase 2" authentication. If the list is empty, no verification of the server certificate's altSubjectName is performed. List of strings to be matched against the altSubjectName of the certificate presented by the authentication server during the inner "phase 2" authentication. If the list is empty, no verification of the server certificate's altSubjectName is performed. Specifies the allowed "phase 2" inner authentication method when an EAP method that uses an inner TLS tunnel is specified in the "eap" property. For TTLS this property selects one of the supported non-EAP inner methods: "pap", "chap", "mschap", "mschapv2" while "phase2-autheap" selects an EAP inner method. For PEAP this selects an inner EAP method, one of: "gtc", "otp", "md5" and "tls". Each "phase 2" inner method requires specific parameters for successful authentication; see the wpa_supplicant documentation for more details. Both "phase2-auth" and "phase2-autheap" cannot be specified. Specifies the allowed "phase 2" inner authentication method when an EAP method that uses an inner TLS tunnel is specified in the "eap" property. For TTLS this property selects one of the supported non-EAP inner methods: "pap", "chap", "mschap", "mschapv2" while "phase2-autheap" selects an EAP inner method. For PEAP this selects an inner EAP method, one of: "gtc", "otp", "md5" and "tls". Each "phase 2" inner method requires specific parameters for successful authentication; see the wpa_supplicant documentation for more details. Both "phase2-auth" and "phase2-autheap" cannot be specified. Specifies the allowed "phase 2" inner EAP-based authentication method when TTLS is specified in the "eap" property. Recognized EAP-based "phase 2" methods are "md5", "mschapv2", "otp", "gtc", and "tls". Each "phase 2" inner method requires specific parameters for successful authentication; see the wpa_supplicant documentation for more details. Specifies the allowed "phase 2" inner EAP-based authentication method when TTLS is specified in the "eap" property. Recognized EAP-based "phase 2" methods are "md5", "mschapv2", "otp", "gtc", and "tls". Each "phase 2" inner method requires specific parameters for successful authentication; see the wpa_supplicant documentation for more details. Contains the "phase 2" CA certificate if used by the EAP method specified in the "phase2-auth" or "phase2-autheap" properties. Certificate data is specified using a "scheme"; three are currently supported: blob, path and pkcs#11 URL. When using the blob scheme this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended. Note that enabling NMSetting8021x:system-ca-certs will override this setting to use the built-in path, if the built-in path is not a directory. Contains the "phase 2" CA certificate if used by the EAP method specified in the "phase2-auth" or "phase2-autheap" properties. + + Certificate data is specified using a "scheme"; three are currently supported: blob, path and pkcs#11 URL. When using the blob scheme this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended. + + Note that enabling NMSetting8021x:system-ca-certs will override this setting to use the built-in path, if the built-in path is not a directory. The password used to access the "phase2" CA certificate stored in "phase2-ca-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. The password used to access the "phase2" CA certificate stored in "phase2-ca-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. Flags indicating how to handle the "phase2-ca-cert-password" property. Flags indicating how to handle the "phase2-ca-cert-password" property. UTF-8 encoded path to a directory containing PEM or DER formatted certificates to be added to the verification chain in addition to the certificate specified in the "phase2-ca-cert" property. If NMSetting8021x:system-ca-certs is enabled and the built-in CA path is an existing directory, then this setting is ignored. UTF-8 encoded path to a directory containing PEM or DER formatted certificates to be added to the verification chain in addition to the certificate specified in the "phase2-ca-cert" property. + + If NMSetting8021x:system-ca-certs is enabled and the built-in CA path is an existing directory, then this setting is ignored. Contains the "phase 2" client certificate if used by the EAP method specified in the "phase2-auth" or "phase2-autheap" properties. Certificate data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme (which is backwards compatible with NM 0.7.x) this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended. Contains the "phase 2" client certificate if used by the EAP method specified in the "phase2-auth" or "phase2-autheap" properties. + + Certificate data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme (which is backwards compatible with NM 0.7.x) this property should be set to the certificate's DER encoded data. When using the path scheme, this property should be set to the full UTF-8 encoded path of the certificate, prefixed with the string "file://" and ending with a terminating NUL byte. This property can be unset even if the EAP method supports CA certificates, but this allows man-in-the-middle attacks and is NOT recommended. The password used to access the "phase2" client certificate stored in "phase2-client-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. The password used to access the "phase2" client certificate stored in "phase2-client-cert" property. Only makes sense if the certificate is stored on a PKCS#11 token that requires a login. Flags indicating how to handle the "phase2-client-cert-password" property. Flags indicating how to handle the "phase2-client-cert-password" property. Constraint for server domain name. If set, this list of FQDNs is used as a match requirement for dNSName element(s) of the certificate presented by the authentication server during the inner "phase 2" authentication. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using the same comparison. Multiple valid FQDNs can be passed as a ";" delimited list. Constraint for server domain name. If set, this list of FQDNs is used as a match requirement for dNSName element(s) of the certificate presented by the authentication server during the inner "phase 2" authentication. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using the same comparison. Multiple valid FQDNs can be passed as a ";" delimited list. Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server during the inner "phase 2" authentication. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison. Since version 1.24, multiple valid FQDNs can be passed as a ";" delimited list. Constraint for server domain name. If set, this FQDN is used as a suffix match requirement for dNSName element(s) of the certificate presented by the authentication server during the inner "phase 2" authentication. If a matching dNSName is found, this constraint is met. If no dNSName values are present, this constraint is matched against SubjectName CN using same suffix match comparison. Since version 1.24, multiple valid FQDNs can be passed as a ";" delimited list. Contains the "phase 2" inner private key when the "phase2-auth" or "phase2-autheap" property is set to "tls". Key data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme and private keys, this property should be set to the key's encrypted PEM encoded data. When using private keys with the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte. When using PKCS#12 format private keys and the blob scheme, this property should be set to the PKCS#12 data and the "phase2-private-key-password" property must be set to password used to decrypt the PKCS#12 certificate and key. When using PKCS#12 files and the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte, and as with the blob scheme the "phase2-private-key-password" property must be set to the password used to decode the PKCS#12 private key and certificate. Contains the "phase 2" inner private key when the "phase2-auth" or "phase2-autheap" property is set to "tls". + + Key data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme and private keys, this property should be set to the key's encrypted PEM encoded data. When using private keys with the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte. When using PKCS#12 format private keys and the blob scheme, this property should be set to the PKCS#12 data and the "phase2-private-key-password" property must be set to password used to decrypt the PKCS#12 certificate and key. When using PKCS#12 files and the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte, and as with the blob scheme the "phase2-private-key-password" property must be set to the password used to decode the PKCS#12 private key and certificate. The password used to decrypt the "phase 2" private key specified in the "phase2-private-key" property when the private key either uses the path scheme, or is a PKCS#12 format key. The password used to decrypt the "phase 2" private key specified in the "phase2-private-key" property when the private key either uses the path scheme, or is a PKCS#12 format key. Flags indicating how to handle the "phase2-private-key-password" property. Flags indicating how to handle the "phase2-private-key-password" property. Substring to be matched against the subject of the certificate presented by the authentication server during the inner "phase 2" authentication. When unset, no verification of the authentication server certificate's subject is performed. This property provides little security, if any, and its use is deprecated in favor of NMSetting8021x:phase2-domain-suffix-match. Substring to be matched against the subject of the certificate presented by the authentication server during the inner "phase 2" authentication. When unset, no verification of the authentication server certificate's subject is performed. This property provides little security, if any, and its use is deprecated in favor of NMSetting8021x:phase2-domain-suffix-match. PIN used for EAP authentication methods. PIN used for EAP authentication methods. Flags indicating how to handle the "pin" property. Flags indicating how to handle the "pin" property. Contains the private key when the "eap" property is set to "tls". Key data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme and private keys, this property should be set to the key's encrypted PEM encoded data. When using private keys with the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte. When using PKCS#12 format private keys and the blob scheme, this property should be set to the PKCS#12 data and the "private-key-password" property must be set to password used to decrypt the PKCS#12 certificate and key. When using PKCS#12 files and the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte, and as with the blob scheme the "private-key-password" property must be set to the password used to decode the PKCS#12 private key and certificate. WARNING: "private-key" is not a "secret" property, and thus unencrypted private key data using the BLOB scheme may be readable by unprivileged users. Private keys should always be encrypted with a private key password to prevent unauthorized access to unencrypted private key data. Contains the private key when the "eap" property is set to "tls". + + Key data is specified using a "scheme"; two are currently supported: blob and path. When using the blob scheme and private keys, this property should be set to the key's encrypted PEM encoded data. When using private keys with the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte. When using PKCS#12 format private keys and the blob scheme, this property should be set to the PKCS#12 data and the "private-key-password" property must be set to password used to decrypt the PKCS#12 certificate and key. When using PKCS#12 files and the path scheme, this property should be set to the full UTF-8 encoded path of the key, prefixed with the string "file://" and ending with a terminating NUL byte, and as with the blob scheme the "private-key-password" property must be set to the password used to decode the PKCS#12 private key and certificate. + + WARNING: "private-key" is not a "secret" property, and thus unencrypted private key data using the BLOB scheme may be readable by unprivileged users. Private keys should always be encrypted with a private key password to prevent unauthorized access to unencrypted private key data. The password used to decrypt the private key specified in the "private-key" property when the private key either uses the path scheme, or if the private key is a PKCS#12 format key. The password used to decrypt the private key specified in the "private-key" property when the private key either uses the path scheme, or if the private key is a PKCS#12 format key. Flags indicating how to handle the "private-key-password" property. Flags indicating how to handle the "private-key-password" property. Substring to be matched against the subject of the certificate presented by the authentication server. When unset, no verification of the authentication server certificate's subject is performed. This property provides little security, if any, and its use is deprecated in favor of NMSetting8021x:domain-suffix-match. Substring to be matched against the subject of the certificate presented by the authentication server. When unset, no verification of the authentication server certificate's subject is performed. This property provides little security, if any, and its use is deprecated in favor of NMSetting8021x:domain-suffix-match. When TRUE, overrides the "ca-path" and "phase2-ca-path" properties using the system CA directory specified at configure time with the --system-ca-path switch. The certificates in this directory are added to the verification chain in addition to any certificates specified by the "ca-cert" and "phase2-ca-cert" properties. If the path provided with --system-ca-path is rather a file name (bundle of trusted CA certificates), it overrides "ca-cert" and "phase2-ca-cert" properties instead (sets ca_cert/ca_cert2 options for wpa_supplicant). When TRUE, overrides the "ca-path" and "phase2-ca-path" properties using the system CA directory specified at configure time with the --system-ca-path switch. The certificates in this directory are added to the verification chain in addition to any certificates specified by the "ca-cert" and "phase2-ca-cert" properties. If the path provided with --system-ca-path is rather a file name (bundle of trusted CA certificates), it overrides "ca-cert" and "phase2-ca-cert" properties instead (sets ca_cert/ca_cert2 options for wpa_supplicant). Encapsulation of ADSL connection. Can be "vcmux" or "llc". Encapsulation of ADSL connection. Can be "vcmux" or "llc". Password used to authenticate with the ADSL service. Password used to authenticate with the ADSL service. Flags indicating how to handle the "password" property. Flags indicating how to handle the "password" property. ADSL connection protocol. Can be "pppoa", "pppoe" or "ipoatm". ADSL connection protocol. Can be "pppoa", "pppoe" or "ipoatm". Username used to authenticate with the ADSL service. Username used to authenticate with the ADSL service. VCI of ADSL connection VCI of ADSL connection VPI of ADSL connection VPI of ADSL connection The Bluetooth address of the device. The Bluetooth address of the device. Either "dun" for Dial-Up Networking connections or "panu" for Personal Area Networking connections to devices supporting the NAP profile. Either "dun" for Dial-Up Networking connections or "panu" for Personal Area Networking connections to devices supporting the NAP profile. Dictionary of key/value pairs of bonding options. Both keys and values must be strings. Option names must contain only alphanumeric characters (ie, [a-zA-Z0-9]). Dictionary of key/value pairs of bonding options. Both keys and values must be strings. Option names must contain only alphanumeric characters (ie, [a-zA-Z0-9]). The Ethernet MAC address aging time, in seconds. The Ethernet MAC address aging time, in seconds. The Spanning Tree Protocol (STP) forwarding delay, in seconds. The Spanning Tree Protocol (STP) forwarding delay, in seconds. If specified, The MAC address of the multicast group this bridge uses for STP. The address must be a link-local address in standard Ethernet MAC address format, ie an address of the form 01:80:C2:00:00:0X, with X in [0, 4..F]. If not specified the default value is 01:80:C2:00:00:00. If specified, The MAC address of the multicast group this bridge uses for STP. + + The address must be a link-local address in standard Ethernet MAC address format, ie an address of the form 01:80:C2:00:00:0X, with X in [0, 4..F]. If not specified the default value is 01:80:C2:00:00:00. A mask of group addresses to forward. Usually, group addresses in the range from 01:80:C2:00:00:00 to 01:80:C2:00:00:0F are not forwarded according to standards. This property is a mask of 16 bits, each corresponding to a group address in that range that must be forwarded. The mask can't have bits 0, 1 or 2 set because they are used for STP, MAC pause frames and LACP. A mask of group addresses to forward. Usually, group addresses in the range from 01:80:C2:00:00:00 to 01:80:C2:00:00:0F are not forwarded according to standards. This property is a mask of 16 bits, each corresponding to a group address in that range that must be forwarded. The mask can't have bits 0, 1 or 2 set because they are used for STP, MAC pause frames and LACP. The Spanning Tree Protocol (STP) hello time, in seconds. The Spanning Tree Protocol (STP) hello time, in seconds. If specified, the MAC address of bridge. When creating a new bridge, this MAC address will be set. If this field is left unspecified, the "ethernet.cloned-mac-address" is referred instead to generate the initial MAC address. Note that setting "ethernet.cloned-mac-address" anyway overwrites the MAC address of the bridge later while activating the bridge. Hence, this property is deprecated. Deprecated: 1 If specified, the MAC address of bridge. When creating a new bridge, this MAC address will be set. + + If this field is left unspecified, the "ethernet.cloned-mac-address" is referred instead to generate the initial MAC address. Note that setting "ethernet.cloned-mac-address" anyway overwrites the MAC address of the bridge later while activating the bridge. Hence, this property is deprecated. Deprecated: 1 The Spanning Tree Protocol (STP) maximum message age, in seconds. The Spanning Tree Protocol (STP) maximum message age, in seconds. Set maximum size of multicast hash table (value must be a power of 2). Set maximum size of multicast hash table (value must be a power of 2). Set the number of queries the bridge will send before stopping forwarding a multicast group after a "leave" message has been received. Set the number of queries the bridge will send before stopping forwarding a multicast group after a "leave" message has been received. Set interval (in deciseconds) between queries to find remaining members of a group, after a "leave" message is received. Set interval (in deciseconds) between queries to find remaining members of a group, after a "leave" message is received. Set delay (in deciseconds) after which the bridge will leave a group, if no membership reports for this group are received. Set delay (in deciseconds) after which the bridge will leave a group, if no membership reports for this group are received. Enable or disable sending of multicast queries by the bridge. If not specified the option is disabled. Enable or disable sending of multicast queries by the bridge. If not specified the option is disabled. If no queries are seen after this delay (in deciseconds) has passed, the bridge will start to send its own queries. If no queries are seen after this delay (in deciseconds) has passed, the bridge will start to send its own queries. Interval (in deciseconds) between queries sent by the bridge after the end of the startup phase. Interval (in deciseconds) between queries sent by the bridge after the end of the startup phase. Set the Max Response Time/Max Response Delay (in deciseconds) for IGMP/MLD queries sent by the bridge. Set the Max Response Time/Max Response Delay (in deciseconds) for IGMP/MLD queries sent by the bridge. If enabled the bridge's own IP address is used as the source address for IGMP queries otherwise the default of 0.0.0.0 is used. If enabled the bridge's own IP address is used as the source address for IGMP queries otherwise the default of 0.0.0.0 is used. Sets bridge's multicast router. Multicast-snooping must be enabled for this option to work. Supported values are: 'auto', 'disabled', 'enabled' to which kernel assigns the numbers 1, 0, and 2, respectively. If not specified the default value is 'auto' (1). Sets bridge's multicast router. Multicast-snooping must be enabled for this option to work. + + Supported values are: 'auto', 'disabled', 'enabled' to which kernel assigns the numbers 1, 0, and 2, respectively. If not specified the default value is 'auto' (1). Controls whether IGMP snooping is enabled for this bridge. Note that if snooping was automatically disabled due to hash collisions, the system may refuse to enable the feature until the collisions are resolved. Controls whether IGMP snooping is enabled for this bridge. Note that if snooping was automatically disabled due to hash collisions, the system may refuse to enable the feature until the collisions are resolved. Set the number of IGMP queries to send during startup phase. Set the number of IGMP queries to send during startup phase. Sets the time (in deciseconds) between queries sent out at startup to determine membership information. Sets the time (in deciseconds) between queries sent out at startup to determine membership information. Sets the Spanning Tree Protocol (STP) priority for this bridge. Lower values are "better"; the lowest priority bridge will be elected the root bridge. Sets the Spanning Tree Protocol (STP) priority for this bridge. Lower values are "better"; the lowest priority bridge will be elected the root bridge. Controls whether Spanning Tree Protocol (STP) is enabled for this bridge. Controls whether Spanning Tree Protocol (STP) is enabled for this bridge. The default PVID for the ports of the bridge, that is the VLAN id assigned to incoming untagged frames. The default PVID for the ports of the bridge, that is the VLAN id assigned to incoming untagged frames. Control whether VLAN filtering is enabled on the bridge. Control whether VLAN filtering is enabled on the bridge. If specified, the protocol used for VLAN filtering. Supported values are: '802.1Q', '802.1ad'. If not specified the default value is '802.1Q'. If specified, the protocol used for VLAN filtering. + + Supported values are: '802.1Q', '802.1ad'. If not specified the default value is '802.1Q'. Controls whether per-VLAN stats accounting is enabled. Controls whether per-VLAN stats accounting is enabled. Array of bridge VLAN objects. In addition to the VLANs specified here, the bridge will also have the default-pvid VLAN configured by the bridge.vlan-default-pvid property. In nmcli the VLAN list can be specified with the following syntax: $vid [pvid] [untagged] [, $vid [pvid] [untagged]]... where $vid is either a single id between 1 and 4094 or a range, represented as a couple of ids separated by a dash. Array of bridge VLAN objects. In addition to the VLANs specified here, the bridge will also have the default-pvid VLAN configured by the bridge.vlan-default-pvid property. + + In nmcli the VLAN list can be specified with the following syntax: + + $vid [pvid] [untagged] [, $vid [pvid] [untagged]]... + + where $vid is either a single id between 1 and 4094 or a range, represented as a couple of ids separated by a dash. Enables or disables "hairpin mode" for the port, which allows frames to be sent back out through the port the frame was received on. Enables or disables "hairpin mode" for the port, which allows frames to be sent back out through the port the frame was received on. The Spanning Tree Protocol (STP) port cost for destinations via this port. The Spanning Tree Protocol (STP) port cost for destinations via this port. The Spanning Tree Protocol (STP) priority of this bridge port. The Spanning Tree Protocol (STP) priority of this bridge port. Array of bridge VLAN objects. In addition to the VLANs specified here, the port will also have the default-pvid VLAN configured on the bridge by the bridge.vlan-default-pvid property. In nmcli the VLAN list can be specified with the following syntax: $vid [pvid] [untagged] [, $vid [pvid] [untagged]]... where $vid is either a single id between 1 and 4094 or a range, represented as a couple of ids separated by a dash. Array of bridge VLAN objects. In addition to the VLANs specified here, the port will also have the default-pvid VLAN configured on the bridge by the bridge.vlan-default-pvid property. + + In nmcli the VLAN list can be specified with the following syntax: + + $vid [pvid] [untagged] [, $vid [pvid] [untagged]]... + + where $vid is either a single id between 1 and 4094 or a range, represented as a couple of ids separated by a dash. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames. The number to dial to establish the connection to the CDMA-based mobile broadband network, if any. If not specified, the default number (#777) is used when required. The number to dial to establish the connection to the CDMA-based mobile broadband network, if any. If not specified, the default number (#777) is used when required. The password used to authenticate with the network, if required. Many providers do not require a password, or accept any password. But if a password is required, it is specified here. The password used to authenticate with the network, if required. Many providers do not require a password, or accept any password. But if a password is required, it is specified here. Flags indicating how to handle the "password" property. Flags indicating how to handle the "password" property. The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here. The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here. Specifies the NMSettingDcbFlags for the DCB FCoE application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). Specifies the NMSettingDcbFlags for the DCB FCoE application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). The FCoE controller mode; either "fabric" or "vn2vn". Since 1.34, NULL is the default and means "fabric". Before 1.34, NULL was rejected as invalid and the default was "fabric". The FCoE controller mode; either "fabric" or "vn2vn". + + Since 1.34, NULL is the default and means "fabric". Before 1.34, NULL was rejected as invalid and the default was "fabric". The highest User Priority (0 - 7) which FCoE frames should use, or -1 for default priority. Only used when the "app-fcoe-flags" property includes the NM_SETTING_DCB_FLAG_ENABLE (0x1) flag. The highest User Priority (0 - 7) which FCoE frames should use, or -1 for default priority. Only used when the "app-fcoe-flags" property includes the NM_SETTING_DCB_FLAG_ENABLE (0x1) flag. Specifies the NMSettingDcbFlags for the DCB FIP application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). Specifies the NMSettingDcbFlags for the DCB FIP application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). The highest User Priority (0 - 7) which FIP frames should use, or -1 for default priority. Only used when the "app-fip-flags" property includes the NM_SETTING_DCB_FLAG_ENABLE (0x1) flag. The highest User Priority (0 - 7) which FIP frames should use, or -1 for default priority. Only used when the "app-fip-flags" property includes the NM_SETTING_DCB_FLAG_ENABLE (0x1) flag. Specifies the NMSettingDcbFlags for the DCB iSCSI application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). Specifies the NMSettingDcbFlags for the DCB iSCSI application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). The highest User Priority (0 - 7) which iSCSI frames should use, or -1 for default priority. Only used when the "app-iscsi-flags" property includes the NM_SETTING_DCB_FLAG_ENABLE (0x1) flag. The highest User Priority (0 - 7) which iSCSI frames should use, or -1 for default priority. Only used when the "app-iscsi-flags" property includes the NM_SETTING_DCB_FLAG_ENABLE (0x1) flag. An array of 8 uint values, where the array index corresponds to the User Priority (0 - 7) and the value indicates the percentage of bandwidth of the priority's assigned group that the priority may use. The sum of all percentages for priorities which belong to the same group must total 100 percents. An array of 8 uint values, where the array index corresponds to the User Priority (0 - 7) and the value indicates the percentage of bandwidth of the priority's assigned group that the priority may use. The sum of all percentages for priorities which belong to the same group must total 100 percents. An array of 8 boolean values, where the array index corresponds to the User Priority (0 - 7) and the value indicates whether or not the corresponding priority should transmit priority pause. An array of 8 boolean values, where the array index corresponds to the User Priority (0 - 7) and the value indicates whether or not the corresponding priority should transmit priority pause. Specifies the NMSettingDcbFlags for DCB Priority Flow Control (PFC). Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). Specifies the NMSettingDcbFlags for DCB Priority Flow Control (PFC). Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). An array of 8 uint values, where the array index corresponds to the Priority Group ID (0 - 7) and the value indicates the percentage of link bandwidth allocated to that group. Allowed values are 0 - 100, and the sum of all values must total 100 percents. An array of 8 uint values, where the array index corresponds to the Priority Group ID (0 - 7) and the value indicates the percentage of link bandwidth allocated to that group. Allowed values are 0 - 100, and the sum of all values must total 100 percents. Specifies the NMSettingDcbFlags for DCB Priority Groups. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). Specifies the NMSettingDcbFlags for DCB Priority Groups. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4). An array of 8 uint values, where the array index corresponds to the User Priority (0 - 7) and the value indicates the Priority Group ID. Allowed Priority Group ID values are 0 - 7 or 15 for the unrestricted group. An array of 8 uint values, where the array index corresponds to the User Priority (0 - 7) and the value indicates the Priority Group ID. Allowed Priority Group ID values are 0 - 7 or 15 for the unrestricted group. An array of 8 boolean values, where the array index corresponds to the User Priority (0 - 7) and the value indicates whether or not the priority may use all of the bandwidth allocated to its assigned group. An array of 8 boolean values, where the array index corresponds to the User Priority (0 - 7) and the value indicates whether or not the priority may use all of the bandwidth allocated to its assigned group. An array of 8 uint values, where the array index corresponds to the User Priority (0 - 7) and the value indicates the traffic class (0 - 7) to which the priority is mapped. An array of 8 uint values, where the array index corresponds to the User Priority (0 - 7) and the value indicates the traffic class (0 - 7) to which the priority is mapped. The GPRS Access Point Name specifying the APN used when establishing a data session with the GSM-based network. The APN often determines how the user will be billed for their network usage and whether the user has access to the Internet or just a provider-specific walled-garden, so it is important to use the correct APN for the user's mobile broadband plan. The APN may only be composed of the characters a-z, 0-9, ., and - per GSM 03.60 Section 14.9. The GPRS Access Point Name specifying the APN used when establishing a data session with the GSM-based network. The APN often determines how the user will be billed for their network usage and whether the user has access to the Internet or just a provider-specific walled-garden, so it is important to use the correct APN for the user's mobile broadband plan. The APN may only be composed of the characters a-z, 0-9, ., and - per GSM 03.60 Section 14.9. When TRUE, the settings such as APN, username, or password will default to values that match the network the modem will register to in the Mobile Broadband Provider database. When TRUE, the settings such as APN, username, or password will default to values that match the network the modem will register to in the Mobile Broadband Provider database. The device unique identifier (as given by the WWAN management service) which this connection applies to. If given, the connection will only apply to the specified device. The device unique identifier (as given by the WWAN management service) which this connection applies to. If given, the connection will only apply to the specified device. When TRUE, only connections to the home network will be allowed. Connections to roaming networks will not be made. When TRUE, only connections to the home network will be allowed. Connections to roaming networks will not be made. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames. The Network ID (GSM LAI format, ie MCC-MNC) to force specific network registration. If the Network ID is specified, NetworkManager will attempt to force the device to register only on the specified network. This can be used to ensure that the device does not roam when direct roaming control of the device is not otherwise possible. The Network ID (GSM LAI format, ie MCC-MNC) to force specific network registration. If the Network ID is specified, NetworkManager will attempt to force the device to register only on the specified network. This can be used to ensure that the device does not roam when direct roaming control of the device is not otherwise possible. Legacy setting that used to help establishing PPP data sessions for GSM-based modems. Deprecated: 1 Legacy setting that used to help establishing PPP data sessions for GSM-based modems. Deprecated: 1 The password used to authenticate with the network, if required. Many providers do not require a password, or accept any password. But if a password is required, it is specified here. The password used to authenticate with the network, if required. Many providers do not require a password, or accept any password. But if a password is required, it is specified here. Flags indicating how to handle the "password" property. Flags indicating how to handle the "password" property. If the SIM is locked with a PIN it must be unlocked before any other operations are requested. Specify the PIN here to allow operation of the device. If the SIM is locked with a PIN it must be unlocked before any other operations are requested. Specify the PIN here to allow operation of the device. Flags indicating how to handle the "pin" property. Flags indicating how to handle the "pin" property. The SIM card unique identifier (as given by the WWAN management service) which this connection applies to. If given, the connection will apply to any device also allowed by "device-id" which contains a SIM card matching the given identifier. The SIM card unique identifier (as given by the WWAN management service) which this connection applies to. If given, the connection will apply to any device also allowed by "device-id" which contains a SIM card matching the given identifier. A MCC/MNC string like "310260" or "21601" identifying the specific mobile network operator which this connection applies to. If given, the connection will apply to any device also allowed by "device-id" and "sim-id" which contains a SIM card provisioned by the given operator. A MCC/MNC string like "310260" or "21601" identifying the specific mobile network operator which this connection applies to. If given, the connection will apply to any device also allowed by "device-id" and "sim-id" which contains a SIM card provisioned by the given operator. The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here. The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here. If specified, this connection will only apply to the IPoIB device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing). If specified, this connection will only apply to the IPoIB device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing). If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames. The InfiniBand P_Key to use for this device. A value of -1 means to use the default P_Key (aka "the P_Key at index 0"). Otherwise, it is a 16-bit unsigned integer, whose high bit is set if it is a "full membership" P_Key. The InfiniBand P_Key to use for this device. A value of -1 means to use the default P_Key (aka "the P_Key at index 0"). Otherwise, it is a 16-bit unsigned integer, whose high bit is set if it is a "full membership" P_Key. The interface name of the parent device of this device. Normally NULL, but if the "p_key" property is set, then you must specify the base device by setting either this property or "mac-address". The interface name of the parent device of this device. Normally NULL, but if the "p_key" property is set, then you must specify the base device by setting either this property or "mac-address". The IP-over-InfiniBand transport mode. Either "datagram" or "connected". The IP-over-InfiniBand transport mode. Either "datagram" or "connected". Array of IP addresses.A list of IPv4 addresses and their prefix length. Multiple addresses can be separated by comma. For example "192.168.1.5/24, 10.1.0.5/24". The addresses are listed in decreasing priority, meaning the first address will be the primary address. Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4. Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. + + The property is currently implemented only for IPv4. A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values "mac" and "perm-mac" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value "ipv6-duid" uses the DUID from "ipv6.dhcp-duid" property as an RFC4361-compliant client identifier. As IAID it uses "ipv4.dhcp-iaid" and falls back to "ipv6.dhcp-iaid" if unset. The special value "duid" generates a RFC4361-compliant client identifier based on "ipv4.dhcp-iaid" and uses a DUID generated by hashing /etc/machine-id. The special value "stable" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If you set the stable-id, you may want to include the "${DEVICE}" or "${MAC}" specifier to get a per-device key. If unset, a globally configured default is used. If still unset, the default depends on the DHCP plugin. A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. + + The special values "mac" and "perm-mac" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. + + The special value "ipv6-duid" uses the DUID from "ipv6.dhcp-duid" property as an RFC4361-compliant client identifier. As IAID it uses "ipv4.dhcp-iaid" and falls back to "ipv6.dhcp-iaid" if unset. + + The special value "duid" generates a RFC4361-compliant client identifier based on "ipv4.dhcp-iaid" and uses a DUID generated by hashing /etc/machine-id. + + The special value "stable" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If you set the stable-id, you may want to include the "${DEVICE}" or "${MAC}" specifier to get a per-device key. + + If unset, a globally configured default is used. If still unset, the default depends on the DHCP plugin. If the "dhcp-send-hostname" property is TRUE, then the specified FQDN will be sent to the DHCP server when acquiring a lease. This property and "dhcp-hostname" are mutually exclusive and cannot be set at the same time. If the "dhcp-send-hostname" property is TRUE, then the specified FQDN will be sent to the DHCP server when acquiring a lease. This property and "dhcp-hostname" are mutually exclusive and cannot be set at the same time. If the "dhcp-send-hostname" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and "dhcp-fqdn" are mutually exclusive and cannot be set at the same time. If the "dhcp-send-hostname" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and "dhcp-fqdn" are mutually exclusive and cannot be set at the same time. Flags for the DHCP hostname and FQDN. Currently, this property only includes flags to control the FQDN flags set in the DHCP FQDN option. Supported FQDN flags are NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) and NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE (0x4). When no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is set, the DHCP FQDN option will contain no flag. Otherwise, if no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is not set, the standard FQDN flags are set in the request: NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) for IPv4 and NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1) for IPv6. When this property is set to the default value NM_DHCP_HOSTNAME_FLAG_NONE (0x0), a global default is looked up in NetworkManager configuration. If that value is unset or also NM_DHCP_HOSTNAME_FLAG_NONE (0x0), then the standard FQDN flags described above are sent in the DHCP requests. Flags for the DHCP hostname and FQDN. + + Currently, this property only includes flags to control the FQDN flags set in the DHCP FQDN option. Supported FQDN flags are NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) and NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE (0x4). When no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is set, the DHCP FQDN option will contain no flag. Otherwise, if no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is not set, the standard FQDN flags are set in the request: NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) for IPv4 and NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1) for IPv6. + + When this property is set to the default value NM_DHCP_HOSTNAME_FLAG_NONE (0x0), a global default is looked up in NetworkManager configuration. If that value is unset or also NM_DHCP_HOSTNAME_FLAG_NONE (0x0), then the standard FQDN flags described above are sent in the DHCP requests. A string containing the "Identity Association Identifier" (IAID) used by the DHCP client. The property is a 32-bit decimal value or a special value among "mac", "perm-mac", "ifname" and "stable". When set to "mac" (or "perm-mac"), the last 4 bytes of the current (or permanent) MAC address are used as IAID. When set to "ifname", the IAID is computed by hashing the interface name. The special value "stable" can be used to generate an IAID based on the stable-id (see connection.stable-id), a per-host key and the interface name. When the property is unset, the value from global configuration is used; if no global default is set then the IAID is assumed to be "ifname". Note that at the moment this property is ignored for IPv6 by dhclient, which always derives the IAID from the MAC address. A string containing the "Identity Association Identifier" (IAID) used by the DHCP client. The property is a 32-bit decimal value or a special value among "mac", "perm-mac", "ifname" and "stable". When set to "mac" (or "perm-mac"), the last 4 bytes of the current (or permanent) MAC address are used as IAID. When set to "ifname", the IAID is computed by hashing the interface name. The special value "stable" can be used to generate an IAID based on the stable-id (see connection.stable-id), a per-host key and the interface name. When the property is unset, the value from global configuration is used; if no global default is set then the IAID is assumed to be "ifname". Note that at the moment this property is ignored for IPv6 by dhclient, which always derives the IAID from the MAC address. Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers. For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. "192.168.122.0/24"). This property is currently not implemented for DHCPv6. Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers. + + For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. "192.168.122.0/24"). + + This property is currently not implemented for DHCPv6. If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer. If the "dhcp-hostname" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent. If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer. If the "dhcp-hostname" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent. A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). Set to 2147483647 (MAXINT32) for infinity. A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). + + Set to 2147483647 (MAXINT32) for infinity. The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server. Since 1.28 The Vendor Class Identifier DHCP option (60). Special characters in the data string may be escaped using C-style escapes, nevertheless this property cannot contain nul bytes. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the DHCP option is not sent to the server. + + Since 1.28 Array of IP addresses of DNS servers. Array of IP addresses of DNS servers. Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are "attempts", "debug", "edns0", "inet6", "ip6-bytestring", "ip6-dotint", "ndots", "no-check-names", "no-ip6-dotint", "no-reload", "no-tld-query", "rotate", "single-request", "single-request-reopen", "timeout", "trust-ad", "use-vc". The "trust-ad" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have "trust-ad" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then "edns0" and "trust-ad" are automatically added. Array of DNS options as described in man 5 resolv.conf. + + NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. + + The currently supported options are "attempts", "debug", "edns0", "inet6", "ip6-bytestring", "ip6-dotint", "ndots", "no-check-names", "no-ip6-dotint", "no-reload", "no-tld-query", "rotate", "single-request", "single-request-reopen", "timeout", "trust-ad", "use-vc". + + The "trust-ad" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have "trust-ad" enabled. + + When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then "edns0" and "trust-ad" are automatically added. DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the "rotate" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured. DNS servers priority. + + The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). + + Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. + + Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. + + Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. + + When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. + + When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the "rotate" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. + + When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured. List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting "ignore-auto-dns". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15). List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. + + When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. + + When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting "ignore-auto-dns". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15). The gateway associated with this configuration. This is only meaningful if "addresses" is also set. The gateway's main purpose is to control the next hop of the standard default route on the device. Hence, the gateway property conflicts with "never-default" and will be automatically dropped if the IP configuration is set to never-default. As an alternative to set the gateway, configure a static default route with /0 as prefix length. The gateway associated with this configuration. This is only meaningful if "addresses" is also set. + + The gateway's main purpose is to control the next hop of the standard default route on the device. Hence, the gateway property conflicts with "never-default" and will be automatically dropped if the IP configuration is set to never-default. + + As an alternative to set the gateway, configure a static default route with /0 as prefix length. When "method" is set to "auto" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the "dns" and "dns-search" properties, if any, are used. When "method" is set to "auto" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the "dns" and "dns-search" properties, if any, are used. When "method" is set to "auto" and this property to TRUE, automatically configured routes are ignored and only routes specified in the "routes" property, if any, are used. When "method" is set to "auto" and this property to TRUE, automatically configured routes are ignored and only routes specified in the "routes" property, if any, are used. Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. When set to "auto", the value is dependent on "ipv4.method". When set to "default", it honors the global connection default, before falling back to "auto". Note that if "ipv4.method" is "disabled", then link local addressing is always disabled too. The default is "default". Since 1.40 Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. + + When set to "auto", the value is dependent on "ipv4.method". When set to "default", it honors the global connection default, before falling back to "auto". Note that if "ipv4.method" is "disabled", then link local addressing is always disabled too. The default is "default". + + Since 1.40 If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out. Note that at least one IP configuration must succeed or overall network configuration will still fail. For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully. If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out. Note that at least one IP configuration must succeed or overall network configuration will still fail. For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully. IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support "disabled", "auto", "manual", and "link-local". See the subclass-specific documentation for other values. In general, for the "auto" method, properties such as "dns" and "routes" specify information that is added on to the information returned from automatic configuration. The "ignore-auto-routes" and "ignore-auto-dns" properties modify this behavior. For methods that imply no upstream network, such as "shared" or "link-local", these properties must be empty. For IPv4 method "shared", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared. IP configuration method. + + NMSettingIP4Config and NMSettingIP6Config both support "disabled", "auto", "manual", and "link-local". See the subclass-specific documentation for other values. + + In general, for the "auto" method, properties such as "dns" and "routes" specify information that is added on to the information returned from automatic configuration. The "ignore-auto-routes" and "ignore-auto-dns" properties modify this behavior. + + For methods that imply no upstream network, such as "shared" or "link-local", these properties must be empty. + + For IPv4 method "shared", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared. If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager. If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager. The minimum time interval in milliseconds for which dynamic IP configuration should be tried before the connection succeeds. This property is useful for example if both IPv4 and IPv6 are enabled and are allowed to fail. Normally the connection succeeds as soon as one of the two address families completes; by setting a required timeout for e.g. IPv4, one can ensure that even if IP6 succeeds earlier than IPv4, NetworkManager waits some time for IPv4 before the connection becomes active. Note that if "may-fail" is FALSE for the same address family, this property has no effect as NetworkManager needs to wait for the full DHCP timeout. A zero value means that no required timeout is present, -1 means the default value (either configuration ipvx.required-timeout override or zero). The minimum time interval in milliseconds for which dynamic IP configuration should be tried before the connection succeeds. + + This property is useful for example if both IPv4 and IPv6 are enabled and are allowed to fail. Normally the connection succeeds as soon as one of the two address families completes; by setting a required timeout for e.g. IPv4, one can ensure that even if IP6 succeeds earlier than IPv4, NetworkManager waits some time for IPv4 before the connection becomes active. + + Note that if "may-fail" is FALSE for the same address family, this property has no effect as NetworkManager needs to wait for the full DHCP timeout. + + A zero value means that no required timeout is present, -1 means the default value (either configuration ipvx.required-timeout override or zero). The default metric for routes that don't explicitly specify a metric. The default value -1 means that the metric is chosen automatically based on the device type. The metric applies to dynamic routes, manual (static) routes that don't have an explicit metric setting, address prefix routes, and the default route. Note that for IPv6, the kernel accepts zero (0) but coerces it to 1024 (user default). Hence, setting this property to zero effectively mean setting it to 1024. For IPv4, zero is a regular value for the metric. The default metric for routes that don't explicitly specify a metric. The default value -1 means that the metric is chosen automatically based on the device type. The metric applies to dynamic routes, manual (static) routes that don't have an explicit metric setting, address prefix routes, and the default route. Note that for IPv6, the kernel accepts zero (0) but coerces it to 1024 (user default). Hence, setting this property to zero effectively mean setting it to 1024. For IPv4, zero is a regular value for the metric. Enable policy routing (source routing) and set the routing table used when adding routes. This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager. Enable policy routing (source routing) and set the routing table used when adding routes. + + This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. + + If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. + + Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager. A list of IPv4 destination addresses, prefix length, optional IPv4 next hop addresses, optional route metric, optional attribute. The valid syntax is: @@ -9,6 +197,9 @@ For example "192.0.2.0/24 10.1.1.1 77, 198.51.100.0/24". Various attributes are supported: +"advmss" - an unsigned 32 bit integer. + + "cwnd" - an unsigned 32 bit integer. @@ -18,6 +209,9 @@ Various attributes are supported: "initrwnd" - an unsigned 32 bit integer. +"lock-advmss" - a boolean value. + + "lock-cwnd" - a boolean value. @@ -39,6 +233,13 @@ Various attributes are supported: "onlink" - a boolean value. +"quickack" - a boolean value. + + +"rto_min" - an unsigned 32 bit integer. +The value is in milliseconds. + + "scope" - an unsigned 8 bit integer. IPv4 only. @@ -62,7 +263,7 @@ The default is unicast. For details see also `man ip-route`. - +A list of IPv4 destination addresses, prefix length, optional IPv4 next hop addresses, optional route metric, optional attribute. The valid syntax is: "ip[/prefix] [next-hop] [metric] [attribute=val]...[,ip[/prefix]...]". For example "192.0.2.0/24 10.1.1.1 77, 198.51.100.0/24". A comma separated list of routing rules for policy routing. The format is based on ip rule add syntax and mostly compatible. @@ -71,7 +272,95 @@ fixed priority. Example: priority 5 from 192.167.4.0/24 table 45 - +A comma separated list of routing rules for policy routing. Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0), NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64 (2) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT (3). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. The special values "default" and "default-or-eui64" will fallback to the global connection default in as documented in NetworkManager.conf(5) manual. If the global default is not specified, the fallback value is "stable-privacy" or "eui64", respectively. For libnm, the property defaults to "default" since 1.40. Previously it defaulted to "stable-privacy". On D-Bus, the absence of an addr-gen-mode setting equals "default". For keyfile plugin, the absence of the setting on disk means "default-or-eui64" so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by "ip6-privacy" property and it does not affect the temporary addresses configured with this option. Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0), NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64 (2) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT (3). + + If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. + + The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. + + The special values "default" and "default-or-eui64" will fallback to the global connection default in as documented in NetworkManager.conf(5) manual. If the global default is not specified, the fallback value is "stable-privacy" or "eui64", respectively. + + For libnm, the property defaults to "default" since 1.40. Previously it defaulted to "stable-privacy". On D-Bus, the absence of an addr-gen-mode setting equals "default". For keyfile plugin, the absence of the setting on disk means "default-or-eui64" so that the property doesn't change on upgrade from older versions. + + Note that this setting is distinct from the Privacy Extensions as configured by "ip6-privacy" property and it does not affect the temporary addresses configured with this option. Array of IP addresses.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 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). Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4. Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. + + The property is currently implemented only for IPv4. A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value "lease" will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and "dhclient" is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values "llt" and "ll" will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values "stable-llt", "stable-ll" and "stable-uuid" will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. You may want to include the "${DEVICE}" or "${MAC}" specifier in the stable-id, in case this profile gets activated on multiple devices. So, the link-layer address of "stable-ll" and "stable-llt" will be a generated address derived from the stable id. The DUID-LLT time value in the "stable-llt" option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in "llt"). When the property is unset, the global value provided for "ipv6.dhcp-duid" is used. If no global value is provided, the default "lease" value is assumed. A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. + + The special value "lease" will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and "dhclient" is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. + + The special values "llt" and "ll" will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. + + The special values "stable-llt", "stable-ll" and "stable-uuid" will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. You may want to include the "${DEVICE}" or "${MAC}" specifier in the stable-id, in case this profile gets activated on multiple devices. So, the link-layer address of "stable-ll" and "stable-llt" will be a generated address derived from the stable id. The DUID-LLT time value in the "stable-llt" option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in "llt"). + + When the property is unset, the global value provided for "ipv6.dhcp-duid" is used. If no global value is provided, the default "lease" value is assumed. If the "dhcp-send-hostname" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and "dhcp-fqdn" are mutually exclusive and cannot be set at the same time. If the "dhcp-send-hostname" property is TRUE, then the specified name will be sent to the DHCP server when acquiring a lease. This property and "dhcp-fqdn" are mutually exclusive and cannot be set at the same time. Flags for the DHCP hostname and FQDN. Currently, this property only includes flags to control the FQDN flags set in the DHCP FQDN option. Supported FQDN flags are NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) and NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE (0x4). When no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is set, the DHCP FQDN option will contain no flag. Otherwise, if no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is not set, the standard FQDN flags are set in the request: NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) for IPv4 and NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1) for IPv6. When this property is set to the default value NM_DHCP_HOSTNAME_FLAG_NONE (0x0), a global default is looked up in NetworkManager configuration. If that value is unset or also NM_DHCP_HOSTNAME_FLAG_NONE (0x0), then the standard FQDN flags described above are sent in the DHCP requests. Flags for the DHCP hostname and FQDN. + + Currently, this property only includes flags to control the FQDN flags set in the DHCP FQDN option. Supported FQDN flags are NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) and NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE (0x4). When no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is set, the DHCP FQDN option will contain no flag. Otherwise, if no FQDN flag is set and NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS (0x8) is not set, the standard FQDN flags are set in the request: NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1), NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED (0x2) for IPv4 and NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE (0x1) for IPv6. + + When this property is set to the default value NM_DHCP_HOSTNAME_FLAG_NONE (0x0), a global default is looked up in NetworkManager configuration. If that value is unset or also NM_DHCP_HOSTNAME_FLAG_NONE (0x0), then the standard FQDN flags described above are sent in the DHCP requests. A string containing the "Identity Association Identifier" (IAID) used by the DHCP client. The property is a 32-bit decimal value or a special value among "mac", "perm-mac", "ifname" and "stable". When set to "mac" (or "perm-mac"), the last 4 bytes of the current (or permanent) MAC address are used as IAID. When set to "ifname", the IAID is computed by hashing the interface name. The special value "stable" can be used to generate an IAID based on the stable-id (see connection.stable-id), a per-host key and the interface name. When the property is unset, the value from global configuration is used; if no global default is set then the IAID is assumed to be "ifname". Note that at the moment this property is ignored for IPv6 by dhclient, which always derives the IAID from the MAC address. A string containing the "Identity Association Identifier" (IAID) used by the DHCP client. The property is a 32-bit decimal value or a special value among "mac", "perm-mac", "ifname" and "stable". When set to "mac" (or "perm-mac"), the last 4 bytes of the current (or permanent) MAC address are used as IAID. When set to "ifname", the IAID is computed by hashing the interface name. The special value "stable" can be used to generate an IAID based on the stable-id (see connection.stable-id), a per-host key and the interface name. When the property is unset, the value from global configuration is used; if no global default is set then the IAID is assumed to be "ifname". Note that at the moment this property is ignored for IPv6 by dhclient, which always derives the IAID from the MAC address. Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers. For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. "192.168.122.0/24"). This property is currently not implemented for DHCPv6. Array of servers from which DHCP offers must be rejected. This property is useful to avoid getting a lease from misconfigured or rogue servers. + + For DHCPv4, each element must be an IPv4 address, optionally followed by a slash and a prefix length (e.g. "192.168.122.0/24"). + + This property is currently not implemented for DHCPv6. If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer. If the "dhcp-hostname" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent. If TRUE, a hostname is sent to the DHCP server when acquiring a lease. Some DHCP servers use this hostname to update DNS databases, essentially providing a static hostname for the computer. If the "dhcp-hostname" property is NULL and this property is TRUE, the current persistent hostname of the computer is sent. A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). Set to 2147483647 (MAXINT32) for infinity. A timeout for a DHCP transaction in seconds. If zero (the default), a globally configured default is used. If still unspecified, a device specific timeout is used (usually 45 seconds). + + Set to 2147483647 (MAXINT32) for infinity. Array of IP addresses of DNS servers. Array of IP addresses of DNS servers. Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are "attempts", "debug", "edns0", "inet6", "ip6-bytestring", "ip6-dotint", "ndots", "no-check-names", "no-ip6-dotint", "no-reload", "no-tld-query", "rotate", "single-request", "single-request-reopen", "timeout", "trust-ad", "use-vc". The "trust-ad" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have "trust-ad" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then "edns0" and "trust-ad" are automatically added. Array of DNS options as described in man 5 resolv.conf. + + NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. + + The currently supported options are "attempts", "debug", "edns0", "inet6", "ip6-bytestring", "ip6-dotint", "ndots", "no-check-names", "no-ip6-dotint", "no-reload", "no-tld-query", "rotate", "single-request", "single-request-reopen", "timeout", "trust-ad", "use-vc". + + The "trust-ad" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have "trust-ad" enabled. + + When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then "edns0" and "trust-ad" are automatically added. DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the "rotate" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured. DNS servers priority. + + The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). + + Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. + + Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. + + Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. + + When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. + + When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the "rotate" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. + + When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured. List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting "ignore-auto-dns". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15). List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. + + When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. + + When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting "ignore-auto-dns". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15). The gateway associated with this configuration. This is only meaningful if "addresses" is also set. The gateway's main purpose is to control the next hop of the standard default route on the device. Hence, the gateway property conflicts with "never-default" and will be automatically dropped if the IP configuration is set to never-default. As an alternative to set the gateway, configure a static default route with /0 as prefix length. The gateway associated with this configuration. This is only meaningful if "addresses" is also set. + + The gateway's main purpose is to control the next hop of the standard default route on the device. Hence, the gateway property conflicts with "never-default" and will be automatically dropped if the IP configuration is set to never-default. + + As an alternative to set the gateway, configure a static default route with /0 as prefix length. When "method" is set to "auto" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the "dns" and "dns-search" properties, if any, are used. When "method" is set to "auto" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the "dns" and "dns-search" properties, if any, are used. When "method" is set to "auto" and this property to TRUE, automatically configured routes are ignored and only routes specified in the "routes" property, if any, are used. When "method" is set to "auto" and this property to TRUE, automatically configured routes are ignored and only routes specified in the "routes" property, if any, are used. Configure IPv6 Privacy Extensions for SLAAC, described in RFC4941. If enabled, it makes the kernel generate a temporary IPv6 address in addition to the public one generated from MAC address via modified EUI-64. This enhances privacy, but could cause problems in some applications, on the other hand. The permitted values are: -1: unknown, 0: disabled, 1: enabled (prefer public address), 2: enabled (prefer temporary addresses). Having a per-connection setting set to "-1" (unknown) means fallback to global configuration "ipv6.ip6-privacy". If also global configuration is unspecified or set to "-1", fallback to read "/proc/sys/net/ipv6/conf/default/use_tempaddr". Note that this setting is distinct from the Stable Privacy addresses that can be enabled with the "addr-gen-mode" property's "stable-privacy" setting as another way of avoiding host tracking with IPv6 addresses. Configure IPv6 Privacy Extensions for SLAAC, described in RFC4941. If enabled, it makes the kernel generate a temporary IPv6 address in addition to the public one generated from MAC address via modified EUI-64. This enhances privacy, but could cause problems in some applications, on the other hand. The permitted values are: -1: unknown, 0: disabled, 1: enabled (prefer public address), 2: enabled (prefer temporary addresses). + + Having a per-connection setting set to "-1" (unknown) means fallback to global configuration "ipv6.ip6-privacy". + + If also global configuration is unspecified or set to "-1", fallback to read "/proc/sys/net/ipv6/conf/default/use_tempaddr". + + Note that this setting is distinct from the Stable Privacy addresses that can be enabled with the "addr-gen-mode" property's "stable-privacy" setting as another way of avoiding host tracking with IPv6 addresses. If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out. Note that at least one IP configuration must succeed or overall network configuration will still fail. For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully. If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out. Note that at least one IP configuration must succeed or overall network configuration will still fail. For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully. IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support "disabled", "auto", "manual", and "link-local". See the subclass-specific documentation for other values. In general, for the "auto" method, properties such as "dns" and "routes" specify information that is added on to the information returned from automatic configuration. The "ignore-auto-routes" and "ignore-auto-dns" properties modify this behavior. For methods that imply no upstream network, such as "shared" or "link-local", these properties must be empty. For IPv4 method "shared", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared. IP configuration method. + + NMSettingIP4Config and NMSettingIP6Config both support "disabled", "auto", "manual", and "link-local". See the subclass-specific documentation for other values. + + In general, for the "auto" method, properties such as "dns" and "routes" specify information that is added on to the information returned from automatic configuration. The "ignore-auto-routes" and "ignore-auto-dns" properties modify this behavior. + + For methods that imply no upstream network, such as "shared" or "link-local", these properties must be empty. + + For IPv4 method "shared", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared. Maximum transmission unit size, in bytes. If zero (the default), the MTU is set automatically from router advertisements or is left equal to the link-layer MTU. If greater than the link-layer MTU, or greater than zero but less than the minimum IPv6 MTU of 1280, this value has no effect. Maximum transmission unit size, in bytes. If zero (the default), the MTU is set automatically from router advertisements or is left equal to the link-layer MTU. If greater than the link-layer MTU, or greater than zero but less than the minimum IPv6 MTU of 1280, this value has no effect. If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager. If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager. A timeout for waiting Router Advertisements in seconds. If zero (the default), a globally configured default is used. If still unspecified, the timeout depends on the sysctl settings of the device. Set to 2147483647 (MAXINT32) for infinity. A timeout for waiting Router Advertisements in seconds. If zero (the default), a globally configured default is used. If still unspecified, the timeout depends on the sysctl settings of the device. + + Set to 2147483647 (MAXINT32) for infinity. The minimum time interval in milliseconds for which dynamic IP configuration should be tried before the connection succeeds. This property is useful for example if both IPv4 and IPv6 are enabled and are allowed to fail. Normally the connection succeeds as soon as one of the two address families completes; by setting a required timeout for e.g. IPv4, one can ensure that even if IP6 succeeds earlier than IPv4, NetworkManager waits some time for IPv4 before the connection becomes active. Note that if "may-fail" is FALSE for the same address family, this property has no effect as NetworkManager needs to wait for the full DHCP timeout. A zero value means that no required timeout is present, -1 means the default value (either configuration ipvx.required-timeout override or zero). The minimum time interval in milliseconds for which dynamic IP configuration should be tried before the connection succeeds. + + This property is useful for example if both IPv4 and IPv6 are enabled and are allowed to fail. Normally the connection succeeds as soon as one of the two address families completes; by setting a required timeout for e.g. IPv4, one can ensure that even if IP6 succeeds earlier than IPv4, NetworkManager waits some time for IPv4 before the connection becomes active. + + Note that if "may-fail" is FALSE for the same address family, this property has no effect as NetworkManager needs to wait for the full DHCP timeout. + + A zero value means that no required timeout is present, -1 means the default value (either configuration ipvx.required-timeout override or zero). The default metric for routes that don't explicitly specify a metric. The default value -1 means that the metric is chosen automatically based on the device type. The metric applies to dynamic routes, manual (static) routes that don't have an explicit metric setting, address prefix routes, and the default route. Note that for IPv6, the kernel accepts zero (0) but coerces it to 1024 (user default). Hence, setting this property to zero effectively mean setting it to 1024. For IPv4, zero is a regular value for the metric. The default metric for routes that don't explicitly specify a metric. The default value -1 means that the metric is chosen automatically based on the device type. The metric applies to dynamic routes, manual (static) routes that don't have an explicit metric setting, address prefix routes, and the default route. Note that for IPv6, the kernel accepts zero (0) but coerces it to 1024 (user default). Hence, setting this property to zero effectively mean setting it to 1024. For IPv4, zero is a regular value for the metric. Enable policy routing (source routing) and set the routing table used when adding routes. This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager. Enable policy routing (source routing) and set the routing table used when adding routes. + + This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. + + If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. + + Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager. A list of IPv6 destination addresses, prefix length, optional IPv6 next hop addresses, optional route metric, optional attribute. The valid syntax is: @@ -81,6 +370,9 @@ next hop addresses, optional route metric, optional attribute. The valid syntax Various attributes are supported: +"advmss" - an unsigned 32 bit integer. + + "cwnd" - an unsigned 32 bit integer. @@ -93,6 +385,9 @@ Various attributes are supported: "initrwnd" - an unsigned 32 bit integer. +"lock-advmss" - a boolean value. + + "lock-cwnd" - a boolean value. @@ -114,6 +409,13 @@ Various attributes are supported: "onlink" - a boolean value. +"quickack" - a boolean value. + + +"rto_min" - an unsigned 32 bit integer. +The value is in milliseconds. + + "src" - an IPv6 address. @@ -131,7 +433,7 @@ The default is unicast. For details see also `man ip-route`. - + Array of IP routes. A comma separated list of routing rules for policy routing. The format is based on ip rule add syntax and mostly compatible. @@ -140,7 +442,49 @@ fixed priority. Example: priority 5 from 1:2:3::5/128 table 45 - +A comma separated list of routing rules for policy routing. Configure the token for draft-chown-6man-tokenised-ipv6-identifiers-02 IPv6 tokenized interface identifiers. Useful with eui64 addr-gen-mode. Configure the token for draft-chown-6man-tokenised-ipv6-identifiers-02 IPv6 tokenized interface identifiers. Useful with eui64 addr-gen-mode. How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels. How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels. Tunnel flags. Currently, the following values are supported: NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS (0x2), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL (0x4), NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV (0x8), NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY (0x10), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK (0x20). They are valid only for IPv6 tunnels. Tunnel flags. Currently, the following values are supported: NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS (0x2), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL (0x4), NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV (0x8), NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY (0x10), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK (0x20). They are valid only for IPv6 tunnels. The flow label to assign to tunnel packets. This property applies only to IPv6 tunnels. The flow label to assign to tunnel packets. This property applies only to IPv6 tunnels. The key used for tunnel input packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used. The key used for tunnel input packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used. The local endpoint of the tunnel; the value can be empty, otherwise it must contain an IPv4 or IPv6 address. The local endpoint of the tunnel; the value can be empty, otherwise it must contain an IPv4 or IPv6 address. The tunneling mode, for example NM_IP_TUNNEL_MODE_IPIP (1) or NM_IP_TUNNEL_MODE_GRE (2). The tunneling mode, for example NM_IP_TUNNEL_MODE_IPIP (1) or NM_IP_TUNNEL_MODE_GRE (2). If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. The key used for tunnel output packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used. The key used for tunnel output packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used. If given, specifies the parent interface name or parent connection UUID the new device will be bound to so that tunneled packets will only be routed via that interface. If given, specifies the parent interface name or parent connection UUID the new device will be bound to so that tunneled packets will only be routed via that interface. Whether to enable Path MTU Discovery on this tunnel. Whether to enable Path MTU Discovery on this tunnel. The remote endpoint of the tunnel; the value must contain an IPv4 or IPv6 address. The remote endpoint of the tunnel; the value must contain an IPv4 or IPv6 address. The type of service (IPv4) or traffic class (IPv6) field to be set on tunneled packets. The type of service (IPv4) or traffic class (IPv6) field to be set on tunneled packets. The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value. The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value. Whether the transmitted traffic must be encrypted. Whether the transmitted traffic must be encrypted. The pre-shared CAK (Connectivity Association Key) for MACsec Key Agreement. The pre-shared CAK (Connectivity Association Key) for MACsec Key Agreement. Flags indicating how to handle the "mka-cak" property. Flags indicating how to handle the "mka-cak" property. The pre-shared CKN (Connectivity-association Key Name) for MACsec Key Agreement. The pre-shared CKN (Connectivity-association Key Name) for MACsec Key Agreement. Specifies how the CAK (Connectivity Association Key) for MKA (MACsec Key Agreement) is obtained. Specifies how the CAK (Connectivity Association Key) for MKA (MACsec Key Agreement) is obtained. If given, specifies the parent interface name or parent connection UUID from which this MACSEC interface should be created. If this property is not specified, the connection must contain an "802-3-ethernet" setting with a "mac-address" property. If given, specifies the parent interface name or parent connection UUID from which this MACSEC interface should be created. If this property is not specified, the connection must contain an "802-3-ethernet" setting with a "mac-address" property. The port component of the SCI (Secure Channel Identifier), between 1 and 65534. The port component of the SCI (Secure Channel Identifier), between 1 and 65534. Specifies whether the SCI (Secure Channel Identifier) is included in every packet. Specifies whether the SCI (Secure Channel Identifier) is included in every packet. Specifies the validation mode for incoming frames. Specifies the validation mode for incoming frames. The macvlan mode, which specifies the communication mechanism between multiple macvlans on the same lower device. The macvlan mode, which specifies the communication mechanism between multiple macvlans on the same lower device. If given, specifies the parent interface name or parent connection UUID from which this MAC-VLAN interface should be created. If this property is not specified, the connection must contain an "802-3-ethernet" setting with a "mac-address" property. If given, specifies the parent interface name or parent connection UUID from which this MAC-VLAN interface should be created. If this property is not specified, the connection must contain an "802-3-ethernet" setting with a "mac-address" property. Whether the interface should be put in promiscuous mode. Whether the interface should be put in promiscuous mode. Whether the interface should be a MACVTAP. Whether the interface should be a MACVTAP. A list of driver names to match. Each element is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern. A list of driver names to match. Each element is a shell wildcard pattern. + + See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern. A list of interface names to match. Each element is a shell wildcard pattern. An element can be prefixed with a pipe symbol (|) or an ampersand (&). The former means that the element is optional and the latter means that it is mandatory. If there are any optional elements, than the match evaluates to true if at least one of the optional element matches (logical OR). If there are any mandatory elements, then they all must match (logical AND). By default, an element is optional. This means that an element "foo" behaves the same as "|foo". An element can also be inverted with exclamation mark (!) between the pipe symbol (or the ampersand) and before the pattern. Note that "!foo" is a shortcut for the mandatory match "&!foo". Finally, a backslash can be used at the beginning of the element (after the optional special characters) to escape the start of the pattern. For example, "&\\!a" is an mandatory match for literally "!a". A list of interface names to match. Each element is a shell wildcard pattern. + + An element can be prefixed with a pipe symbol (|) or an ampersand (&). The former means that the element is optional and the latter means that it is mandatory. If there are any optional elements, than the match evaluates to true if at least one of the optional element matches (logical OR). If there are any mandatory elements, then they all must match (logical AND). By default, an element is optional. This means that an element "foo" behaves the same as "|foo". An element can also be inverted with exclamation mark (!) between the pipe symbol (or the ampersand) and before the pattern. Note that "!foo" is a shortcut for the mandatory match "&!foo". Finally, a backslash can be used at the beginning of the element (after the optional special characters) to escape the start of the pattern. For example, "&\\!a" is an mandatory match for literally "!a". A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or unset, if prefixed with the exclamation mark). The argument must either be a single word, or an assignment (i.e. two words, joined by "="). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching. Wildcard patterns are not supported. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the match. A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or unset, if prefixed with the exclamation mark). The argument must either be a single word, or an assignment (i.e. two words, joined by "="). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching. Wildcard patterns are not supported. + + See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the match. A list of paths to match against the ID_PATH udev property of devices. ID_PATH represents the topological persistent path of a device. It typically contains a subsystem string (pci, usb, platform, etc.) and a subsystem-specific identifier. For PCI devices the path has the form "pci-$domain:$bus:$device.$function", where each variable is an hexadecimal value; for example "pci-0000:0a:00.0". The path of a device can be obtained with "udevadm info /sys/class/net/$dev | grep ID_PATH=" or by looking at the "path" property exported by NetworkManager ("nmcli -f general.path device show $dev"). Each element of the list is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern. A list of paths to match against the ID_PATH udev property of devices. ID_PATH represents the topological persistent path of a device. It typically contains a subsystem string (pci, usb, platform, etc.) and a subsystem-specific identifier. + + For PCI devices the path has the form "pci-$domain:$bus:$device.$function", where each variable is an hexadecimal value; for example "pci-0000:0a:00.0". + + The path of a device can be obtained with "udevadm info /sys/class/net/$dev | grep ID_PATH=" or by looking at the "path" property exported by NetworkManager ("nmcli -f general.path device show $dev"). + + Each element of the list is a shell wildcard pattern. + + See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern. Channel on which the mesh network to join is located. Channel on which the mesh network to join is located. Anycast DHCP MAC address used when requesting an IP address via DHCP. The specific anycast address used determines which DHCP server class answers the request. This is currently only implemented by dhclient DHCP plugin. Anycast DHCP MAC address used when requesting an IP address via DHCP. The specific anycast address used determines which DHCP server class answers the request. + + This is currently only implemented by dhclient DHCP plugin. SSID of the mesh network to join. SSID of the mesh network to join. The data path type. One of "system", "netdev" or empty. The data path type. One of "system", "netdev" or empty. The bridge failure mode. One of "secure", "standalone" or empty. The bridge failure mode. One of "secure", "standalone" or empty. Enable or disable multicast snooping. Enable or disable multicast snooping. Enable or disable RSTP. Enable or disable RSTP. Enable or disable STP. Enable or disable STP. Open vSwitch DPDK device arguments. Open vSwitch DPDK device arguments. Open vSwitch DPDK number of rx queues. Defaults to zero which means to leave the parameter in OVS unspecified and effectively configures one queue. Open vSwitch DPDK number of rx queues. Defaults to zero which means to leave the parameter in OVS unspecified and effectively configures one queue. The interface type. Either "internal", "system", "patch", "dpdk", or empty. The interface type. Either "internal", "system", "patch", "dpdk", or empty. Specifies the name of the interface for the other side of the patch. The patch on the other side must also set this interface as peer. Specifies the name of the interface for the other side of the patch. The patch on the other side must also set this interface as peer. The time port must be inactive in order to be considered down. The time port must be inactive in order to be considered down. Bonding mode. One of "active-backup", "balance-slb", or "balance-tcp". Bonding mode. One of "active-backup", "balance-slb", or "balance-tcp". The time port must be active before it starts forwarding traffic. The time port must be active before it starts forwarding traffic. LACP mode. One of "active", "off", or "passive". LACP mode. One of "active", "off", or "passive". The VLAN tag in the range 0-4095. The VLAN tag in the range 0-4095. The VLAN mode. One of "access", "native-tagged", "native-untagged", "trunk" or unset. The VLAN mode. One of "access", "native-tagged", "native-untagged", "trunk" or unset. If non-zero, instruct pppd to set the serial port to the specified baudrate. This value should normally be left as 0 to automatically choose the speed. If non-zero, instruct pppd to set the serial port to the specified baudrate. This value should normally be left as 0 to automatically choose the speed. If TRUE, specify that pppd should set the serial port to use hardware flow control with RTS and CTS signals. This value should normally be set to FALSE. If TRUE, specify that pppd should set the serial port to use hardware flow control with RTS and CTS signals. This value should normally be set to FALSE. If non-zero, instruct pppd to presume the connection to the peer has failed if the specified number of LCP echo-requests go unanswered by the peer. The "lcp-echo-interval" property must also be set to a non-zero value if this property is used. If non-zero, instruct pppd to presume the connection to the peer has failed if the specified number of LCP echo-requests go unanswered by the peer. The "lcp-echo-interval" property must also be set to a non-zero value if this property is used. If non-zero, instruct pppd to send an LCP echo-request frame to the peer every n seconds (where n is the specified value). Note that some PPP peers will respond to echo requests and some will not, and it is not possible to autodetect this. If non-zero, instruct pppd to send an LCP echo-request frame to the peer every n seconds (where n is the specified value). Note that some PPP peers will respond to echo requests and some will not, and it is not possible to autodetect this. If TRUE, stateful MPPE is used. See pppd documentation for more information on stateful MPPE. If TRUE, stateful MPPE is used. See pppd documentation for more information on stateful MPPE. If non-zero, instruct pppd to request that the peer send packets no larger than the specified size. If non-zero, the MRU should be between 128 and 16384. If non-zero, instruct pppd to request that the peer send packets no larger than the specified size. If non-zero, the MRU should be between 128 and 16384. If non-zero, instruct pppd to send packets no larger than the specified size. If non-zero, instruct pppd to send packets no larger than the specified size. If TRUE, Van Jacobsen TCP header compression will not be requested. If TRUE, Van Jacobsen TCP header compression will not be requested. If TRUE, do not require the other side (usually the PPP server) to authenticate itself to the client. If FALSE, require authentication from the remote side. In almost all cases, this should be TRUE. If TRUE, do not require the other side (usually the PPP server) to authenticate itself to the client. If FALSE, require authentication from the remote side. In almost all cases, this should be TRUE. If TRUE, BSD compression will not be requested. If TRUE, BSD compression will not be requested. If TRUE, "deflate" compression will not be requested. If TRUE, "deflate" compression will not be requested. If TRUE, the CHAP authentication method will not be used. If TRUE, the CHAP authentication method will not be used. If TRUE, the EAP authentication method will not be used. If TRUE, the EAP authentication method will not be used. If TRUE, the MSCHAP authentication method will not be used. If TRUE, the MSCHAP authentication method will not be used. If TRUE, the MSCHAPv2 authentication method will not be used. If TRUE, the MSCHAPv2 authentication method will not be used. If TRUE, the PAP authentication method will not be used. If TRUE, the PAP authentication method will not be used. If TRUE, MPPE (Microsoft Point-to-Point Encryption) will be required for the PPP session. If either 64-bit or 128-bit MPPE is not available the session will fail. Note that MPPE is not used on mobile broadband connections. If TRUE, MPPE (Microsoft Point-to-Point Encryption) will be required for the PPP session. If either 64-bit or 128-bit MPPE is not available the session will fail. Note that MPPE is not used on mobile broadband connections. If TRUE, 128-bit MPPE (Microsoft Point-to-Point Encryption) will be required for the PPP session, and the "require-mppe" property must also be set to TRUE. If 128-bit MPPE is not available the session will fail. If TRUE, 128-bit MPPE (Microsoft Point-to-Point Encryption) will be required for the PPP session, and the "require-mppe" property must also be set to TRUE. If 128-bit MPPE is not available the session will fail. If given, specifies the parent interface name on which this PPPoE connection should be created. If this property is not specified, the connection is activated on the interface specified in "interface-name" of NMSettingConnection. If given, specifies the parent interface name on which this PPPoE connection should be created. If this property is not specified, the connection is activated on the interface specified in "interface-name" of NMSettingConnection. Password used to authenticate with the PPPoE service. Password used to authenticate with the PPPoE service. Flags indicating how to handle the "password" property. Flags indicating how to handle the "password" property. If specified, instruct PPPoE to only initiate sessions with access concentrators that provide the specified service. For most providers, this should be left blank. It is only required if there are multiple access concentrators or a specific service is known to be required. If specified, instruct PPPoE to only initiate sessions with access concentrators that provide the specified service. For most providers, this should be left blank. It is only required if there are multiple access concentrators or a specific service is known to be required. Username used to authenticate with the PPPoE service. Username used to authenticate with the PPPoE service. Whether the proxy configuration is for browser only. Whether the proxy configuration is for browser only. Method for proxy configuration, Default is NM_SETTING_PROXY_METHOD_NONE (0) Method for proxy configuration, Default is NM_SETTING_PROXY_METHOD_NONE (0) PAC script for the connection. This is an UTF-8 encoded javascript code that defines a FindProxyForURL() function.The PAC script. In the profile this must be an UTF-8 encoded javascript code that defines a FindProxyForURL() function. When setting the property in nmcli, a filename is accepted too. In that case, nmcli will read the content of the file and set the script. The prefixes "file://" and "js://" are supported to explicitly differentiate between the two. PAC URL for obtaining PAC file. PAC URL for obtaining PAC file. Speed to use for communication over the serial port. Note that this value usually has no effect for mobile broadband modems as they generally ignore speed settings and use the highest available speed. Speed to use for communication over the serial port. Note that this value usually has no effect for mobile broadband modems as they generally ignore speed settings and use the highest available speed. Byte-width of the serial communication. The 8 in "8n1" for example. Byte-width of the serial communication. The 8 in "8n1" for example. Parity setting of the serial port. Parity setting of the serial port. Time to delay between each byte sent to the modem, in microseconds. Time to delay between each byte sent to the modem, in microseconds. Number of stop bits for communication on the serial port. Either 1 or 2. The 1 in "8n1" for example. Number of stop bits for communication on the serial port. Either 1 or 2. The 1 in "8n1" for example. Whether to autoprobe virtual functions by a compatible driver. If set to NM_TERNARY_TRUE (1), the kernel will try to bind VFs to a compatible driver and if this succeeds a new network interface will be instantiated for each VF. If set to NM_TERNARY_FALSE (0), VFs will not be claimed and no network interfaces will be created for them. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_TRUE (1). Whether to autoprobe virtual functions by a compatible driver. + + If set to NM_TERNARY_TRUE (1), the kernel will try to bind VFs to a compatible driver and if this succeeds a new network interface will be instantiated for each VF. + + If set to NM_TERNARY_FALSE (0), VFs will not be claimed and no network interfaces will be created for them. + + When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_TRUE (1). The total number of virtual functions to create. Note that when the sriov setting is present NetworkManager enforces the number of virtual functions on the interface (also when it is zero) during activation and resets it upon deactivation. To prevent any changes to SR-IOV parameters don't add a sriov setting to the connection. The total number of virtual functions to create. + + Note that when the sriov setting is present NetworkManager enforces the number of virtual functions on the interface (also when it is zero) during activation and resets it upon deactivation. To prevent any changes to SR-IOV parameters don't add a sriov setting to the connection. Array of virtual function descriptors. Each VF descriptor is a dictionary mapping attribute names to GVariant values. The 'index' entry is mandatory for each VF. When represented as string a VF is in the form: "INDEX [ATTR=VALUE[ ATTR=VALUE]...]". for example: "2 mac=00:11:22:33:44:55 spoof-check=true". Multiple VFs can be specified using a comma as separator. Currently, the following attributes are supported: mac, spoof-check, trust, min-tx-rate, max-tx-rate, vlans. The "vlans" attribute is represented as a semicolon-separated list of VLAN descriptors, where each descriptor has the form "ID[.PRIORITY[.PROTO]]". PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad. Array of virtual function descriptors. + + Each VF descriptor is a dictionary mapping attribute names to GVariant values. The 'index' entry is mandatory for each VF. + + When represented as string a VF is in the form: + + "INDEX [ATTR=VALUE[ ATTR=VALUE]...]". + + for example: + + "2 mac=00:11:22:33:44:55 spoof-check=true". + + Multiple VFs can be specified using a comma as separator. Currently, the following attributes are supported: mac, spoof-check, trust, min-tx-rate, max-tx-rate, vlans. + + The "vlans" attribute is represented as a semicolon-separated list of VLAN descriptors, where each descriptor has the form + + "ID[.PRIORITY[.PROTO]]". + + PROTO can be either 'q' for 802.1Q (the default) or 'ad' for 802.1ad. Array of TC queueing disciplines. qdisc is a basic block in the Linux traffic control subsystem @@ -410,7 +754,11 @@ the size of the bucket, the rate and possibly the peakrate - + Array of TC queueing disciplines. + + When the "tc" setting is present, qdiscs from this property are applied upon activation. If the property is empty, all qdiscs are removed and the device will only have the default qdisc assigned by kernel according to the "net.core.default_qdisc" sysctl. + + If the "tc" setting is not present, NetworkManager doesn't touch the qdiscs present on the interface. Array of TC traffic filters. Traffic control can manage the packet content during classification by using filters. @@ -507,4 +855,86 @@ The actual string to print. - \ No newline at end of file + Array of TC traffic filters. + + When the "tc" setting is present, filters from this property are applied upon activation. If the property is empty, NetworkManager removes all the filters. + + If the "tc" setting is not present, NetworkManager doesn't touch the filters present on the interface. The JSON configuration for the team network interface. The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used. See man teamd.conf for the format details. The JSON configuration for the team network interface. The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used. See man teamd.conf for the format details. Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are: ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-inactive', 'send-always'. See teamd.conf man for more details. Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are: ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-inactive', 'send-always'. See teamd.conf man for more details. Corresponds to the teamd mcast_rejoin.count. Corresponds to the teamd mcast_rejoin.count. Corresponds to the teamd mcast_rejoin.interval. Corresponds to the teamd mcast_rejoin.interval. Corresponds to the teamd notify_peers.count. Corresponds to the teamd notify_peers.count. Corresponds to the teamd notify_peers.interval. Corresponds to the teamd notify_peers.interval. Corresponds to the teamd runner.name. Permitted values are: "roundrobin", "broadcast", "activebackup", "loadbalance", "lacp", "random". Corresponds to the teamd runner.name. Permitted values are: "roundrobin", "broadcast", "activebackup", "loadbalance", "lacp", "random". Corresponds to the teamd runner.active. Corresponds to the teamd runner.active. Corresponds to the teamd runner.agg_select_policy. Corresponds to the teamd runner.agg_select_policy. Corresponds to the teamd runner.fast_rate. Corresponds to the teamd runner.fast_rate. Corresponds to the teamd runner.hwaddr_policy. Corresponds to the teamd runner.hwaddr_policy. Corresponds to the teamd runner.min_ports. Corresponds to the teamd runner.min_ports. Corresponds to the teamd runner.sys_prio. Corresponds to the teamd runner.sys_prio. Corresponds to the teamd runner.tx_balancer.name. Corresponds to the teamd runner.tx_balancer.name. Corresponds to the teamd runner.tx_balancer.interval. Corresponds to the teamd runner.tx_balancer.interval. Corresponds to the teamd runner.tx_hash. Corresponds to the teamd runner.tx_hash. The JSON configuration for the team port. The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used. See man teamd.conf for the format details. The JSON configuration for the team port. The property should contain raw JSON configuration data suitable for teamd, because the value is passed directly to teamd. If not specified, the default configuration is used. See man teamd.conf for the format details. Corresponds to the teamd ports.PORTIFNAME.lacp_key. Corresponds to the teamd ports.PORTIFNAME.lacp_key. Corresponds to the teamd ports.PORTIFNAME.lacp_prio. Corresponds to the teamd ports.PORTIFNAME.lacp_prio. Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are: ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-inactive', 'send-always'. See teamd.conf man for more details. Link watchers configuration for the connection: each link watcher is defined by a dictionary, whose keys depend upon the selected link watcher. Available link watchers are 'ethtool', 'nsna_ping' and 'arp_ping' and it is specified in the dictionary with the key 'name'. Available keys are: ethtool: 'delay-up', 'delay-down', 'init-wait'; nsna_ping: 'init-wait', 'interval', 'missed-max', 'target-host'; arp_ping: all the ones in nsna_ping and 'source-host', 'validate-active', 'validate-inactive', 'send-always'. See teamd.conf man for more details. Corresponds to the teamd ports.PORTIFNAME.prio. Corresponds to the teamd ports.PORTIFNAME.prio. Corresponds to the teamd ports.PORTIFNAME.queue_id. When set to -1 means the parameter is skipped from the json config. Corresponds to the teamd ports.PORTIFNAME.queue_id. When set to -1 means the parameter is skipped from the json config. Corresponds to the teamd ports.PORTIFNAME.sticky. Corresponds to the teamd ports.PORTIFNAME.sticky. The group ID which will own the device. If set to NULL everyone will be able to use the device. The group ID which will own the device. If set to NULL everyone will be able to use the device. The operating mode of the virtual device. Allowed values are NM_SETTING_TUN_MODE_TUN (1) to create a layer 3 device and NM_SETTING_TUN_MODE_TAP (2) to create an Ethernet-like layer 2 one. The operating mode of the virtual device. Allowed values are NM_SETTING_TUN_MODE_TUN (1) to create a layer 3 device and NM_SETTING_TUN_MODE_TAP (2) to create an Ethernet-like layer 2 one. If the property is set to TRUE, the interface will support multiple file descriptors (queues) to parallelize packet sending or receiving. Otherwise, the interface will only support a single queue. If the property is set to TRUE, the interface will support multiple file descriptors (queues) to parallelize packet sending or receiving. Otherwise, the interface will only support a single queue. The user ID which will own the device. If set to NULL everyone will be able to use the device. The user ID which will own the device. If set to NULL everyone will be able to use the device. If TRUE the interface will prepend a 4 byte header describing the physical interface to the packets. If TRUE the interface will prepend a 4 byte header describing the physical interface to the packets. If TRUE the IFF_VNET_HDR the tunnel packets will include a virtio network header. If TRUE the IFF_VNET_HDR the tunnel packets will include a virtio network header. A dictionary of key/value pairs with user data. This data is ignored by NetworkManager and can be used at the users discretion. The keys only support a strict ascii format, but the values can be arbitrary UTF8 strings up to a certain length. A dictionary of key/value pairs with user data. This data is ignored by NetworkManager and can be used at the users discretion. The keys only support a strict ascii format, but the values can be arbitrary UTF8 strings up to a certain length. For outgoing packets, a list of mappings from Linux SKB priorities to 802.1p priorities. The mapping is given in the format "from:to" where both "from" and "to" are unsigned integers, ie "7:3". For outgoing packets, a list of mappings from Linux SKB priorities to 802.1p priorities. The mapping is given in the format "from:to" where both "from" and "to" are unsigned integers, ie "7:3". One or more flags which control the behavior and features of the VLAN interface. Flags include NM_VLAN_FLAG_REORDER_HEADERS (0x1) (reordering of output packet headers), NM_VLAN_FLAG_GVRP (0x2) (use of the GVRP protocol), and NM_VLAN_FLAG_LOOSE_BINDING (0x4) (loose binding of the interface to its master device's operating state). NM_VLAN_FLAG_MVRP (0x8) (use of the MVRP protocol). The default value of this property is NM_VLAN_FLAG_REORDER_HEADERS, but it used to be 0. To preserve backward compatibility, the default-value in the D-Bus API continues to be 0 and a missing property on D-Bus is still considered as 0. One or more flags which control the behavior and features of the VLAN interface. Flags include NM_VLAN_FLAG_REORDER_HEADERS (0x1) (reordering of output packet headers), NM_VLAN_FLAG_GVRP (0x2) (use of the GVRP protocol), and NM_VLAN_FLAG_LOOSE_BINDING (0x4) (loose binding of the interface to its master device's operating state). NM_VLAN_FLAG_MVRP (0x8) (use of the MVRP protocol). + + The default value of this property is NM_VLAN_FLAG_REORDER_HEADERS, but it used to be 0. To preserve backward compatibility, the default-value in the D-Bus API continues to be 0 and a missing property on D-Bus is still considered as 0. The VLAN identifier that the interface created by this connection should be assigned. The valid range is from 0 to 4094, without the reserved id 4095. The VLAN identifier that the interface created by this connection should be assigned. The valid range is from 0 to 4094, without the reserved id 4095. For incoming packets, a list of mappings from 802.1p priorities to Linux SKB priorities. The mapping is given in the format "from:to" where both "from" and "to" are unsigned integers, ie "7:3". For incoming packets, a list of mappings from 802.1p priorities to Linux SKB priorities. The mapping is given in the format "from:to" where both "from" and "to" are unsigned integers, ie "7:3". If given, specifies the parent interface name or parent connection UUID from which this VLAN interface should be created. If this property is not specified, the connection must contain an "802-3-ethernet" setting with a "mac-address" property. If given, specifies the parent interface name or parent connection UUID from which this VLAN interface should be created. If this property is not specified, the connection must contain an "802-3-ethernet" setting with a "mac-address" property. Dictionary of key/value pairs of VPN plugin specific data. Both keys and values must be strings. Dictionary of key/value pairs of VPN plugin specific data. Both keys and values must be strings. If the VPN service supports persistence, and this property is TRUE, the VPN will attempt to stay connected across link changes and outages, until explicitly disconnected. If the VPN service supports persistence, and this property is TRUE, the VPN will attempt to stay connected across link changes and outages, until explicitly disconnected. Dictionary of key/value pairs of VPN plugin specific secrets like passwords or private keys. Both keys and values must be strings. Dictionary of key/value pairs of VPN plugin specific secrets like passwords or private keys. Both keys and values must be strings. D-Bus service name of the VPN plugin that this setting uses to connect to its network. i.e. org.freedesktop.NetworkManager.vpnc for the vpnc plugin. D-Bus service name of the VPN plugin that this setting uses to connect to its network. i.e. org.freedesktop.NetworkManager.vpnc for the vpnc plugin. Timeout for the VPN service to establish the connection. Some services may take quite a long time to connect. Value of 0 means a default timeout, which is 60 seconds (unless overridden by vpn.timeout in configuration file). Values greater than zero mean timeout in seconds. Timeout for the VPN service to establish the connection. Some services may take quite a long time to connect. Value of 0 means a default timeout, which is 60 seconds (unless overridden by vpn.timeout in configuration file). Values greater than zero mean timeout in seconds. If the VPN connection requires a user name for authentication, that name should be provided here. If the connection is available to more than one user, and the VPN requires each user to supply a different name, then leave this property empty. If this property is empty, NetworkManager will automatically supply the username of the user which requested the VPN connection. If the VPN connection requires a user name for authentication, that name should be provided here. If the connection is available to more than one user, and the VPN requires each user to supply a different name, then leave this property empty. If this property is empty, NetworkManager will automatically supply the username of the user which requested the VPN connection. The routing table for this VRF. The routing table for this VRF. Specifies the lifetime in seconds of FDB entries learnt by the kernel. Specifies the lifetime in seconds of FDB entries learnt by the kernel. Specifies the UDP destination port to communicate to the remote VXLAN tunnel endpoint. Specifies the UDP destination port to communicate to the remote VXLAN tunnel endpoint. Specifies the VXLAN Network Identifier (or VXLAN Segment Identifier) to use. Specifies the VXLAN Network Identifier (or VXLAN Segment Identifier) to use. Specifies whether netlink LL ADDR miss notifications are generated. Specifies whether netlink LL ADDR miss notifications are generated. Specifies whether netlink IP ADDR miss notifications are generated. Specifies whether netlink IP ADDR miss notifications are generated. Specifies whether unknown source link layer addresses and IP addresses are entered into the VXLAN device forwarding database. Specifies whether unknown source link layer addresses and IP addresses are entered into the VXLAN device forwarding database. Specifies the maximum number of FDB entries. A value of zero means that the kernel will store unlimited entries. Specifies the maximum number of FDB entries. A value of zero means that the kernel will store unlimited entries. If given, specifies the source IP address to use in outgoing packets. If given, specifies the source IP address to use in outgoing packets. If given, specifies the parent interface name or parent connection UUID. If given, specifies the parent interface name or parent connection UUID. Specifies whether ARP proxy is turned on. Specifies whether ARP proxy is turned on. Specifies the unicast destination IP address to use in outgoing packets when the destination link layer address is not known in the VXLAN device forwarding database, or the multicast IP address to join. Specifies the unicast destination IP address to use in outgoing packets when the destination link layer address is not known in the VXLAN device forwarding database, or the multicast IP address to join. Specifies whether route short circuit is turned on. Specifies whether route short circuit is turned on. Specifies the maximum UDP source port to communicate to the remote VXLAN tunnel endpoint. Specifies the maximum UDP source port to communicate to the remote VXLAN tunnel endpoint. Specifies the minimum UDP source port to communicate to the remote VXLAN tunnel endpoint. Specifies the minimum UDP source port to communicate to the remote VXLAN tunnel endpoint. Specifies the TOS value to use in outgoing packets. Specifies the TOS value to use in outgoing packets. Specifies the time-to-live value to use in outgoing packets. Specifies the time-to-live value to use in outgoing packets. The P2P device that should be connected to. Currently, this is the only way to create or join a group. The P2P device that should be connected to. Currently, this is the only way to create or join a group. The Wi-Fi Display (WFD) Information Elements (IEs) to set. Wi-Fi Display requires a protocol specific information element to be set in certain Wi-Fi frames. These can be specified here for the purpose of establishing a connection. This setting is only useful when implementing a Wi-Fi Display client. The Wi-Fi Display (WFD) Information Elements (IEs) to set. + + Wi-Fi Display requires a protocol specific information element to be set in certain Wi-Fi frames. These can be specified here for the purpose of establishing a connection. This setting is only useful when implementing a Wi-Fi Display client. Flags indicating which mode of WPS is to be used. There's little point in changing the default setting as NetworkManager will automatically determine the best method to use. Flags indicating which mode of WPS is to be used. + + There's little point in changing the default setting as NetworkManager will automatically determine the best method to use. If specified, this connection will only apply to the WiMAX device whose MAC address matches. This property does not change the MAC address of the device (known as MAC spoofing). Deprecated: 1 If specified, this connection will only apply to the WiMAX device whose MAC address matches. This property does not change the MAC address of the device (known as MAC spoofing). Deprecated: 1 Network Service Provider (NSP) name of the WiMAX network this connection should use. Deprecated: 1 Network Service Provider (NSP) name of the WiMAX network this connection should use. Deprecated: 1 When TRUE, setup the interface to accept packets for all MAC addresses. This is enabling the kernel interface flag IFF_PROMISC. When FALSE, the interface will only accept the packets with the interface destination mac address or broadcast. When TRUE, setup the interface to accept packets for all MAC addresses. This is enabling the kernel interface flag IFF_PROMISC. When FALSE, the interface will only accept the packets with the interface destination mac address or broadcast. When TRUE, enforce auto-negotiation of speed and duplex mode. If "speed" and "duplex" properties are both specified, only that single mode will be advertised and accepted during the link auto-negotiation process: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. When FALSE, "speed" and "duplex" properties should be both set or link configuration will be skipped. When TRUE, enforce auto-negotiation of speed and duplex mode. If "speed" and "duplex" properties are both specified, only that single mode will be advertised and accepted during the link auto-negotiation process: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. When FALSE, "speed" and "duplex" properties should be both set or link configuration will be skipped. If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. Beside explicitly specifying a MAC address, the special values "preserve", "permanent", "random" and "stable" are supported. "preserve" means not to touch the MAC address on activation. "permanent" means to use the permanent hardware address if the device has one (otherwise this is treated as "preserve"). "random" creates a random MAC address on each connect. "stable" creates a hashed MAC address based on connection.stable-id and a machine dependent key. If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to "preserve" (older versions of NetworkManager may use a different default value). On D-Bus, this field is expressed as "assigned-mac-address" or the deprecated "cloned-mac-address". If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. + + Beside explicitly specifying a MAC address, the special values "preserve", "permanent", "random" and "stable" are supported. "preserve" means not to touch the MAC address on activation. "permanent" means to use the permanent hardware address if the device has one (otherwise this is treated as "preserve"). "random" creates a random MAC address on each connect. "stable" creates a hashed MAC address based on connection.stable-id and a machine dependent key. + + If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to "preserve" (older versions of NetworkManager may use a different default value). + + On D-Bus, this field is expressed as "assigned-mac-address" or the deprecated "cloned-mac-address". When a value is set, either "half" or "full", configures the device to use the specified duplex mode. If "auto-negotiate" is "yes" the specified duplex mode will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. If the value is unset (the default), the link configuration will be either skipped (if "auto-negotiate" is "no", the default) or will be auto-negotiated (if "auto-negotiate" is "yes") and the local device will advertise all the supported duplex modes. Must be set together with the "speed" property if specified. Before specifying a duplex mode be sure your device supports it. When a value is set, either "half" or "full", configures the device to use the specified duplex mode. If "auto-negotiate" is "yes" the specified duplex mode will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. If the value is unset (the default), the link configuration will be either skipped (if "auto-negotiate" is "no", the default) or will be auto-negotiated (if "auto-negotiate" is "yes") and the local device will advertise all the supported duplex modes. Must be set together with the "speed" property if specified. Before specifying a duplex mode be sure your device supports it. With "cloned-mac-address" setting "random" or "stable", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting "FE:FF:FF:00:00:00" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the "random" or "stable" algorithm. If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of "FE:FF:FF:00:00:00 68:F7:28:00:00:00" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of "02:00:00:00:00:00 00:00:00:00:00:00" will create a fully scrambled globally-administered, burned-in MAC address. If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, "02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00" will create a fully scrambled MAC address, randomly locally or globally administered. With "cloned-mac-address" setting "random" or "stable", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. + + If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. + + If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting "FE:FF:FF:00:00:00" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the "random" or "stable" algorithm. + + If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of "FE:FF:FF:00:00:00 68:F7:28:00:00:00" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of "02:00:00:00:00:00 00:00:00:00:00:00" will create a fully scrambled globally-administered, burned-in MAC address. + + If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, "02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00" will create a fully scrambled MAC address, randomly locally or globally administered. If specified, this connection will only apply to the Ethernet device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing). If specified, this connection will only apply to the Ethernet device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing). If specified, this connection will never apply to the Ethernet device whose permanent MAC address matches an address in the list. Each MAC address is in the standard hex-digits-and-colons notation (00:11:22:33:44:55). If specified, this connection will never apply to the Ethernet device whose permanent MAC address matches an address in the list. Each MAC address is in the standard hex-digits-and-colons notation (00:11:22:33:44:55). If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames. Specific port type to use if the device supports multiple attachment methods. One of "tp" (Twisted Pair), "aui" (Attachment Unit Interface), "bnc" (Thin Ethernet) or "mii" (Media Independent Interface). If the device supports only one port type, this setting is ignored. Specific port type to use if the device supports multiple attachment methods. One of "tp" (Twisted Pair), "aui" (Attachment Unit Interface), "bnc" (Thin Ethernet) or "mii" (Media Independent Interface). If the device supports only one port type, this setting is ignored. s390 network device type; one of "qeth", "lcs", or "ctc", representing the different types of virtual network devices available on s390 systems. s390 network device type; one of "qeth", "lcs", or "ctc", representing the different types of virtual network devices available on s390 systems. Dictionary of key/value pairs of s390-specific device options. Both keys and values must be strings. Allowed keys include "portno", "layer2", "portname", "protocol", among others. Key names must contain only alphanumeric characters (ie, [a-zA-Z0-9]). Currently, NetworkManager itself does nothing with this information. However, s390utils ships a udev rule which parses this information and applies it to the interface. Dictionary of key/value pairs of s390-specific device options. Both keys and values must be strings. Allowed keys include "portno", "layer2", "portname", "protocol", among others. Key names must contain only alphanumeric characters (ie, [a-zA-Z0-9]). + + Currently, NetworkManager itself does nothing with this information. However, s390utils ships a udev rule which parses this information and applies it to the interface. Identifies specific subchannels that this network device uses for communication with z/VM or s390 host. Like the "mac-address" property for non-z/VM devices, this property can be used to ensure this connection only applies to the network device that uses these subchannels. The list should contain exactly 3 strings, and each string may only be composed of hexadecimal characters and the period (.) character. Identifies specific subchannels that this network device uses for communication with z/VM or s390 host. Like the "mac-address" property for non-z/VM devices, this property can be used to ensure this connection only applies to the network device that uses these subchannels. The list should contain exactly 3 strings, and each string may only be composed of hexadecimal characters and the period (.) character. When a value greater than 0 is set, configures the device to use the specified speed. If "auto-negotiate" is "yes" the specified speed will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabit speeds, as in this case link negotiation is mandatory. If the value is unset (0, the default), the link configuration will be either skipped (if "auto-negotiate" is "no", the default) or will be auto-negotiated (if "auto-negotiate" is "yes") and the local device will advertise all the supported speeds. In Mbit/s, ie 100 == 100Mbit/s. Must be set together with the "duplex" property when non-zero. Before specifying a speed value be sure your device supports it. When a value greater than 0 is set, configures the device to use the specified speed. If "auto-negotiate" is "yes" the specified speed will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabit speeds, as in this case link negotiation is mandatory. If the value is unset (0, the default), the link configuration will be either skipped (if "auto-negotiate" is "no", the default) or will be auto-negotiated (if "auto-negotiate" is "yes") and the local device will advertise all the supported speeds. In Mbit/s, ie 100 == 100Mbit/s. Must be set together with the "duplex" property when non-zero. Before specifying a speed value be sure your device supports it. The NMSettingWiredWakeOnLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRED_WAKE_ON_LAN_PHY (0x2), NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST (0x4), NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST (0x8), NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST (0x10), NM_SETTING_WIRED_WAKE_ON_LAN_ARP (0x20), NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC (0x40) or the special values NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager). The NMSettingWiredWakeOnLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRED_WAKE_ON_LAN_PHY (0x2), NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST (0x4), NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST (0x8), NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST (0x10), NM_SETTING_WIRED_WAKE_ON_LAN_ARP (0x20), NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC (0x40) or the special values NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager). If specified, the password used with magic-packet-based Wake-on-LAN, represented as an Ethernet MAC address. If NULL, no password will be required. If specified, the password used with magic-packet-based Wake-on-LAN, represented as an Ethernet MAC address. If NULL, no password will be required. The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise, it is a 32-bit fwmark for outgoing packets. Note that "ip4-auto-default-route" or "ip6-auto-default-route" enabled, implies to automatically choose a fwmark. The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise, it is a 32-bit fwmark for outgoing packets. + + Note that "ip4-auto-default-route" or "ip6-auto-default-route" enabled, implies to automatically choose a fwmark. Whether to enable special handling of the IPv4 default route. If enabled, the IPv4 default route from wireguard.peer-routes will be placed to a dedicated routing-table and two policy routing rules will be added. The fwmark number is also used as routing-table for the default-route, and if fwmark is zero, an unused fwmark/table is chosen automatically. This corresponds to what wg-quick does with Table=auto and what WireGuard calls "Improved Rule-based Routing". Note that for this automatism to work, you usually don't want to set ipv4.gateway, because that will result in a conflicting default route. Leaving this at the default will enable this option automatically if ipv4.never-default is not set and there are any peers that use a default-route as allowed-ips. Since this automatism only makes sense if you also have a peer with an /0 allowed-ips, it is usually not necessary to enable this explicitly. However, you can disable it if you want to configure your own routing and rules. Whether to enable special handling of the IPv4 default route. If enabled, the IPv4 default route from wireguard.peer-routes will be placed to a dedicated routing-table and two policy routing rules will be added. The fwmark number is also used as routing-table for the default-route, and if fwmark is zero, an unused fwmark/table is chosen automatically. This corresponds to what wg-quick does with Table=auto and what WireGuard calls "Improved Rule-based Routing". + + Note that for this automatism to work, you usually don't want to set ipv4.gateway, because that will result in a conflicting default route. + + Leaving this at the default will enable this option automatically if ipv4.never-default is not set and there are any peers that use a default-route as allowed-ips. Since this automatism only makes sense if you also have a peer with an /0 allowed-ips, it is usually not necessary to enable this explicitly. However, you can disable it if you want to configure your own routing and rules. Like ip4-auto-default-route, but for the IPv6 default route. Like ip4-auto-default-route, but for the IPv6 default route. The listen-port. If listen-port is not specified, the port will be chosen randomly when the interface comes up. The listen-port. If listen-port is not specified, the port will be chosen randomly when the interface comes up. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. If zero a default MTU is used. Note that contrary to wg-quick's MTU setting, this does not take into account the current routes at the time of activation. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. + + If zero a default MTU is used. Note that contrary to wg-quick's MTU setting, this does not take into account the current routes at the time of activation. Whether to automatically add routes for the AllowedIPs ranges of the peers. If TRUE (the default), NetworkManager will automatically add routes in the routing tables according to ipv4.route-table and ipv6.route-table. Usually you want this automatism enabled. If FALSE, no such routes are added automatically. In this case, the user may want to configure static routes in ipv4.routes and ipv6.routes, respectively. Note that if the peer's AllowedIPs is "0.0.0.0/0" or "::/0" and the profile's ipv4.never-default or ipv6.never-default setting is enabled, the peer route for this peer won't be added automatically. Whether to automatically add routes for the AllowedIPs ranges of the peers. If TRUE (the default), NetworkManager will automatically add routes in the routing tables according to ipv4.route-table and ipv6.route-table. Usually you want this automatism enabled. If FALSE, no such routes are added automatically. In this case, the user may want to configure static routes in ipv4.routes and ipv6.routes, respectively. + + Note that if the peer's AllowedIPs is "0.0.0.0/0" or "::/0" and the profile's ipv4.never-default or ipv6.never-default setting is enabled, the peer route for this peer won't be added automatically. The 256 bit private-key in base64 encoding. The 256 bit private-key in base64 encoding. Flags indicating how to handle the "private-key" property. Flags indicating how to handle the "private-key" property. Configures AP isolation, which prevents communication between wireless devices connected to this AP. This property can be set to a value different from NM_TERNARY_DEFAULT (-1) only when the interface is configured in AP mode. If set to NM_TERNARY_TRUE (1), devices are not able to communicate with each other. This increases security because it protects devices against attacks from other clients in the network. At the same time, it prevents devices to access resources on the same wireless networks as file shares, printers, etc. If set to NM_TERNARY_FALSE (0), devices can talk to each other. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_FALSE (0). Configures AP isolation, which prevents communication between wireless devices connected to this AP. This property can be set to a value different from NM_TERNARY_DEFAULT (-1) only when the interface is configured in AP mode. + + If set to NM_TERNARY_TRUE (1), devices are not able to communicate with each other. This increases security because it protects devices against attacks from other clients in the network. At the same time, it prevents devices to access resources on the same wireless networks as file shares, printers, etc. + + If set to NM_TERNARY_FALSE (0), devices can talk to each other. + + When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_FALSE (0). 802.11 frequency band of the network. One of "a" for 5GHz 802.11a or "bg" for 2.4GHz 802.11. This will lock associations to the Wi-Fi network to the specific band, i.e. if "a" is specified, the device will not associate with the same network in the 2.4GHz band even if the network's settings are compatible. This setting depends on specific driver capability and may not work with all drivers. 802.11 frequency band of the network. One of "a" for 5GHz 802.11a or "bg" for 2.4GHz 802.11. This will lock associations to the Wi-Fi network to the specific band, i.e. if "a" is specified, the device will not associate with the same network in the 2.4GHz band even if the network's settings are compatible. This setting depends on specific driver capability and may not work with all drivers. If specified, directs the device to only associate with the given access point. This capability is highly driver dependent and not supported by all devices. Note: this property does not control the BSSID used when creating an Ad-Hoc network and is unlikely to in the future. Locking a client profile to a certain BSSID will prevent roaming and also disable background scanning. That can be useful, if there is only one access point for the SSID. If specified, directs the device to only associate with the given access point. This capability is highly driver dependent and not supported by all devices. Note: this property does not control the BSSID used when creating an Ad-Hoc network and is unlikely to in the future. + + Locking a client profile to a certain BSSID will prevent roaming and also disable background scanning. That can be useful, if there is only one access point for the SSID. Wireless channel to use for the Wi-Fi connection. The device will only join (or create for Ad-Hoc networks) a Wi-Fi network on the specified channel. Because channel numbers overlap between bands, this property also requires the "band" property to be set. Wireless channel to use for the Wi-Fi connection. The device will only join (or create for Ad-Hoc networks) a Wi-Fi network on the specified channel. Because channel numbers overlap between bands, this property also requires the "band" property to be set. If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. Beside explicitly specifying a MAC address, the special values "preserve", "permanent", "random" and "stable" are supported. "preserve" means not to touch the MAC address on activation. "permanent" means to use the permanent hardware address of the device. "random" creates a random MAC address on each connect. "stable" creates a hashed MAC address based on connection.stable-id and a machine dependent key. If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to "preserve" (older versions of NetworkManager may use a different default value). On D-Bus, this field is expressed as "assigned-mac-address" or the deprecated "cloned-mac-address". If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. + + Beside explicitly specifying a MAC address, the special values "preserve", "permanent", "random" and "stable" are supported. "preserve" means not to touch the MAC address on activation. "permanent" means to use the permanent hardware address of the device. "random" creates a random MAC address on each connect. "stable" creates a hashed MAC address based on connection.stable-id and a machine dependent key. + + If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to "preserve" (older versions of NetworkManager may use a different default value). + + On D-Bus, this field is expressed as "assigned-mac-address" or the deprecated "cloned-mac-address". With "cloned-mac-address" setting "random" or "stable", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting "FE:FF:FF:00:00:00" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the "random" or "stable" algorithm. If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of "FE:FF:FF:00:00:00 68:F7:28:00:00:00" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of "02:00:00:00:00:00 00:00:00:00:00:00" will create a fully scrambled globally-administered, burned-in MAC address. If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, "02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00" will create a fully scrambled MAC address, randomly locally or globally administered. With "cloned-mac-address" setting "random" or "stable", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. + + If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. + + If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting "FE:FF:FF:00:00:00" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the "random" or "stable" algorithm. + + If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of "FE:FF:FF:00:00:00 68:F7:28:00:00:00" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of "02:00:00:00:00:00 00:00:00:00:00:00" will create a fully scrambled globally-administered, burned-in MAC address. + + If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, "02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00" will create a fully scrambled MAC address, randomly locally or globally administered. If TRUE, indicates that the network is a non-broadcasting network that hides its SSID. This works both in infrastructure and AP mode. In infrastructure mode, various workarounds are used for a more reliable discovery of hidden networks, such as probe-scanning the SSID. However, these workarounds expose inherent insecurities with hidden SSID networks, and thus hidden SSID networks should be used with caution. In AP mode, the created network does not broadcast its SSID. Note that marking the network as hidden may be a privacy issue for you (in infrastructure mode) or client stations (in AP mode), as the explicit probe-scans are distinctly recognizable on the air. If TRUE, indicates that the network is a non-broadcasting network that hides its SSID. This works both in infrastructure and AP mode. + + In infrastructure mode, various workarounds are used for a more reliable discovery of hidden networks, such as probe-scanning the SSID. However, these workarounds expose inherent insecurities with hidden SSID networks, and thus hidden SSID networks should be used with caution. + + In AP mode, the created network does not broadcast its SSID. + + Note that marking the network as hidden may be a privacy issue for you (in infrastructure mode) or client stations (in AP mode), as the explicit probe-scans are distinctly recognizable on the air. If specified, this connection will only apply to the Wi-Fi device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing). If specified, this connection will only apply to the Wi-Fi device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing). A list of permanent MAC addresses of Wi-Fi devices to which this connection should never apply. Each MAC address should be given in the standard hex-digits-and-colons notation (eg "00:11:22:33:44:55"). A list of permanent MAC addresses of Wi-Fi devices to which this connection should never apply. Each MAC address should be given in the standard hex-digits-and-colons notation (eg "00:11:22:33:44:55"). One of NM_SETTING_MAC_RANDOMIZATION_DEFAULT (0) (never randomize unless the user has set a global default to randomize and the supplicant supports randomization), NM_SETTING_MAC_RANDOMIZATION_NEVER (1) (never randomize the MAC address), or NM_SETTING_MAC_RANDOMIZATION_ALWAYS (2) (always randomize the MAC address). This property is deprecated for 'cloned-mac-address'. Deprecated: 1 One of NM_SETTING_MAC_RANDOMIZATION_DEFAULT (0) (never randomize unless the user has set a global default to randomize and the supplicant supports randomization), NM_SETTING_MAC_RANDOMIZATION_NEVER (1) (never randomize the MAC address), or NM_SETTING_MAC_RANDOMIZATION_ALWAYS (2) (always randomize the MAC address). This property is deprecated for 'cloned-mac-address'. Deprecated: 1 Wi-Fi network mode; one of "infrastructure", "mesh", "adhoc" or "ap". If blank, infrastructure is assumed. Wi-Fi network mode; one of "infrastructure", "mesh", "adhoc" or "ap". If blank, infrastructure is assumed. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames. If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames. One of NM_SETTING_WIRELESS_POWERSAVE_DISABLE (2) (disable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_ENABLE (3) (enable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_IGNORE (1) (don't touch currently configure setting) or NM_SETTING_WIRELESS_POWERSAVE_DEFAULT (0) (use the globally configured value). All other values are reserved. One of NM_SETTING_WIRELESS_POWERSAVE_DISABLE (2) (disable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_ENABLE (3) (enable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_IGNORE (1) (don't touch currently configure setting) or NM_SETTING_WIRELESS_POWERSAVE_DEFAULT (0) (use the globally configured value). All other values are reserved. If non-zero, directs the device to only use the specified bitrate for communication with the access point. Units are in Kb/s, ie 5500 = 5.5 Mbit/s. This property is highly driver dependent and not all devices support setting a static bitrate. If non-zero, directs the device to only use the specified bitrate for communication with the access point. Units are in Kb/s, ie 5500 = 5.5 Mbit/s. This property is highly driver dependent and not all devices support setting a static bitrate. A list of BSSIDs (each BSSID formatted as a MAC address like "00:11:22:33:44:55") that have been detected as part of the Wi-Fi network. NetworkManager internally tracks previously seen BSSIDs. The property is only meant for reading and reflects the BSSID list of NetworkManager. The changes you make to this property will not be preserved. A list of BSSIDs (each BSSID formatted as a MAC address like "00:11:22:33:44:55") that have been detected as part of the Wi-Fi network. NetworkManager internally tracks previously seen BSSIDs. The property is only meant for reading and reflects the BSSID list of NetworkManager. The changes you make to this property will not be preserved. SSID of the Wi-Fi network. Must be specified. SSID of the Wi-Fi network. Must be specified. If non-zero, directs the device to use the specified transmit power. Units are dBm. This property is highly driver dependent and not all devices support setting a static transmit power. If non-zero, directs the device to use the specified transmit power. Units are dBm. This property is highly driver dependent and not all devices support setting a static transmit power. The NMSettingWirelessWakeOnWLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY (0x2), NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT (0x4), NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC (0x8), NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE (0x10), NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST (0x20), NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE (0x40), NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE (0x80), NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP (0x100) or the special values NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager). The NMSettingWirelessWakeOnWLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY (0x2), NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT (0x4), NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC (0x8), NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE (0x10), NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST (0x20), NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE (0x40), NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE (0x80), NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP (0x100) or the special values NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager). When WEP is used (ie, key-mgmt = "none" or "ieee8021x") indicate the 802.11 authentication algorithm required by the AP here. One of "open" for Open System, "shared" for Shared Key, or "leap" for Cisco LEAP. When using Cisco LEAP (ie, key-mgmt = "ieee8021x" and auth-alg = "leap") the "leap-username" and "leap-password" properties must be specified. When WEP is used (ie, key-mgmt = "none" or "ieee8021x") indicate the 802.11 authentication algorithm required by the AP here. One of "open" for Open System, "shared" for Shared Key, or "leap" for Cisco LEAP. When using Cisco LEAP (ie, key-mgmt = "ieee8021x" and auth-alg = "leap") the "leap-username" and "leap-password" properties must be specified. Indicates whether Fast Initial Link Setup (802.11ai) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE (1) (disable FILS), NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL (2) (enable FILS if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED (3) (enable FILS and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) and no global default is set, FILS will be optionally enabled. Indicates whether Fast Initial Link Setup (802.11ai) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE (1) (disable FILS), NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL (2) (enable FILS if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED (3) (enable FILS and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) and no global default is set, FILS will be optionally enabled. A list of group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of "wep40", "wep104", "tkip", or "ccmp". A list of group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of "wep40", "wep104", "tkip", or "ccmp". Key management used for the connection. One of "none" (WEP or no password protection), "ieee8021x" (Dynamic WEP), "owe" (Opportunistic Wireless Encryption), "wpa-psk" (WPA2 + WPA3 personal), "sae" (WPA3 personal only), "wpa-eap" (WPA2 + WPA3 enterprise) or "wpa-eap-suite-b-192" (WPA3 enterprise only). This property must be set for any Wi-Fi connection that uses security. Key management used for the connection. One of "none" (WEP or no password protection), "ieee8021x" (Dynamic WEP), "owe" (Opportunistic Wireless Encryption), "wpa-psk" (WPA2 + WPA3 personal), "sae" (WPA3 personal only), "wpa-eap" (WPA2 + WPA3 enterprise) or "wpa-eap-suite-b-192" (WPA3 enterprise only). + + This property must be set for any Wi-Fi connection that uses security. The login password for legacy LEAP connections (ie, key-mgmt = "ieee8021x" and auth-alg = "leap"). The login password for legacy LEAP connections (ie, key-mgmt = "ieee8021x" and auth-alg = "leap"). Flags indicating how to handle the "leap-password" property. Flags indicating how to handle the "leap-password" property. The login username for legacy LEAP connections (ie, key-mgmt = "ieee8021x" and auth-alg = "leap"). The login username for legacy LEAP connections (ie, key-mgmt = "ieee8021x" and auth-alg = "leap"). A list of pairwise encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of "tkip" or "ccmp". A list of pairwise encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of "tkip" or "ccmp". Indicates whether Protected Management Frames (802.11w) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE (1) (disable PMF), NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL (2) (enable PMF if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED (3) (enable PMF and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) and no global default is set, PMF will be optionally enabled. Indicates whether Protected Management Frames (802.11w) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE (1) (disable PMF), NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL (2) (enable PMF if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED (3) (enable PMF and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) and no global default is set, PMF will be optionally enabled. List of strings specifying the allowed WPA protocol versions to use. Each element may be one "wpa" (allow WPA) or "rsn" (allow WPA2/RSN). If not specified, both WPA and RSN connections are allowed. List of strings specifying the allowed WPA protocol versions to use. Each element may be one "wpa" (allow WPA) or "rsn" (allow WPA2/RSN). If not specified, both WPA and RSN connections are allowed. Pre-Shared-Key for WPA networks. For WPA-PSK, it's either an ASCII passphrase of 8 to 63 characters that is (as specified in the 802.11i standard) hashed to derive the actual key, or the key in form of 64 hexadecimal character. The WPA3-Personal networks use a passphrase of any length for SAE authentication. Pre-Shared-Key for WPA networks. For WPA-PSK, it's either an ASCII passphrase of 8 to 63 characters that is (as specified in the 802.11i standard) hashed to derive the actual key, or the key in form of 64 hexadecimal character. The WPA3-Personal networks use a passphrase of any length for SAE authentication. Flags indicating how to handle the "psk" property. Flags indicating how to handle the "psk" property. Flags indicating how to handle the "wep-key0", "wep-key1", "wep-key2", and "wep-key3" properties. Flags indicating how to handle the "wep-key0", "wep-key1", "wep-key2", and "wep-key3" properties. Controls the interpretation of WEP keys. Allowed values are NM_WEP_KEY_TYPE_KEY (1), in which case the key is either a 10- or 26-character hexadecimal string, or a 5- or 13-character ASCII password; or NM_WEP_KEY_TYPE_PASSPHRASE (2), in which case the passphrase is provided as a string and will be hashed using the de-facto MD5 method to derive the actual WEP key. Controls the interpretation of WEP keys. Allowed values are NM_WEP_KEY_TYPE_KEY (1), in which case the key is either a 10- or 26-character hexadecimal string, or a 5- or 13-character ASCII password; or NM_WEP_KEY_TYPE_PASSPHRASE (2), in which case the passphrase is provided as a string and will be hashed using the de-facto MD5 method to derive the actual WEP key. Index 0 WEP key. This is the WEP key used in most networks. See the "wep-key-type" property for a description of how this key is interpreted. Index 0 WEP key. This is the WEP key used in most networks. See the "wep-key-type" property for a description of how this key is interpreted. Index 1 WEP key. This WEP index is not used by most networks. See the "wep-key-type" property for a description of how this key is interpreted. Index 1 WEP key. This WEP index is not used by most networks. See the "wep-key-type" property for a description of how this key is interpreted. Index 2 WEP key. This WEP index is not used by most networks. See the "wep-key-type" property for a description of how this key is interpreted. Index 2 WEP key. This WEP index is not used by most networks. See the "wep-key-type" property for a description of how this key is interpreted. Index 3 WEP key. This WEP index is not used by most networks. See the "wep-key-type" property for a description of how this key is interpreted. Index 3 WEP key. This WEP index is not used by most networks. See the "wep-key-type" property for a description of how this key is interpreted. When static WEP is used (ie, key-mgmt = "none") and a non-default WEP key index is used by the AP, put that WEP key index here. Valid values are 0 (default key) through 3. Note that some consumer access points (like the Linksys WRT54G) number the keys 1 - 4. When static WEP is used (ie, key-mgmt = "none") and a non-default WEP key index is used by the AP, put that WEP key index here. Valid values are 0 (default key) through 3. Note that some consumer access points (like the Linksys WRT54G) number the keys 1 - 4. Flags indicating which mode of WPS is to be used if any. There's little point in changing the default setting as NetworkManager will automatically determine whether it's feasible to start WPS enrollment from the Access Point capabilities. WPS can be disabled by setting this property to a value of 1. Flags indicating which mode of WPS is to be used if any. + + There's little point in changing the default setting as NetworkManager will automatically determine whether it's feasible to start WPS enrollment from the Access Point capabilities. + + WPS can be disabled by setting this property to a value of 1. IEEE 802.15.4 channel. A positive integer or -1, meaning "do not set, use whatever the device is already set to". IEEE 802.15.4 channel. A positive integer or -1, meaning "do not set, use whatever the device is already set to". If specified, this connection will only apply to the IEEE 802.15.4 (WPAN) MAC layer device whose permanent MAC address matches. If specified, this connection will only apply to the IEEE 802.15.4 (WPAN) MAC layer device whose permanent MAC address matches. IEEE 802.15.4 channel page. A positive integer or -1, meaning "do not set, use whatever the device is already set to". IEEE 802.15.4 channel page. A positive integer or -1, meaning "do not set, use whatever the device is already set to". IEEE 802.15.4 Personal Area Network (PAN) identifier. IEEE 802.15.4 Personal Area Network (PAN) identifier. Short IEEE 802.15.4 address to be used within a restricted environment. Short IEEE 802.15.4 address to be used within a restricted environment. The queue ID of this bond port. The maximum value of queue ID is the number of TX queues currently active in device. The queue ID of this bond port. The maximum value of queue ID is the number of TX queues currently active in device. Whether the system hostname can be determined from DHCP on this connection. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1). Whether the system hostname can be determined from DHCP on this connection. + + When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1). Whether the system hostname can be determined from reverse DNS lookup of addresses on this device. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1). Whether the system hostname can be determined from reverse DNS lookup of addresses on this device. + + When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1). If set to NM_TERNARY_TRUE (1), NetworkManager attempts to get the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this device only when the device has the default route for the given address family (IPv4/IPv6). If set to NM_TERNARY_FALSE (0), the hostname can be set from this device even if it doesn't have the default route. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_FALSE (0). If set to NM_TERNARY_TRUE (1), NetworkManager attempts to get the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this device only when the device has the default route for the given address family (IPv4/IPv6). + + If set to NM_TERNARY_FALSE (0), the hostname can be set from this device even if it doesn't have the default route. + + When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_FALSE (0). The relative priority of this connection to determine the system hostname. A lower numerical value is better (higher priority). A connection with higher priority is considered before connections with lower priority. If the value is zero, it can be overridden by a global value from NetworkManager configuration. If the property doesn't have a value in the global configuration, the value is assumed to be 100. Negative values have the special effect of excluding other connections with a greater numerical priority value; so in presence of at least one negative priority, only connections with the lowest priority value will be used to determine the hostname. The relative priority of this connection to determine the system hostname. A lower numerical value is better (higher priority). A connection with higher priority is considered before connections with lower priority. + + If the value is zero, it can be overridden by a global value from NetworkManager configuration. If the property doesn't have a value in the global configuration, the value is assumed to be 100. + + Negative values have the special effect of excluding other connections with a greater numerical priority value; so in presence of at least one negative priority, only connections with the lowest priority value will be used to determine the hostname. A dictionary of key/value pairs with exernal-ids for OVS. A dictionary of key/value pairs with exernal-ids for OVS. This property specifies the peer interface name of the veth. This property is mandatory. This property specifies the peer interface name of the veth. This property is mandatory. \ No newline at end of file diff --git a/src/libnmc-setting/settings-docs.h b/src/libnmc-setting/settings-docs.h index 2a582ad7..3e86c04b 100644 --- a/src/libnmc-setting/settings-docs.h +++ b/src/libnmc-setting/settings-docs.h @@ -1,47 +1,34 @@ /* Generated file. Do not edit. */ +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTH_RETRIES N_("The number of retries for the authentication. Zero means to try indefinitely; -1 means to use a global default. If the global default is not set, the authentication retries for 3 times before failing the connection. Currently, this only applies to 802-1x authentication.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT N_("Whether or not the connection should be automatically connected by NetworkManager when the resources for the connection are available. TRUE to automatically activate the connection, FALSE to require manual intervention to activate the connection. Autoconnect happens when the circumstances are suitable. That means for example that the device is currently managed and not active. Autoconnect thus never replaces or competes with an already active profile. Note that autoconnect is not implemented for VPN profiles. See \"secondaries\" as an alternative to automatically connect VPN profiles. If multiple profiles are ready to autoconnect on the same device, the one with the better \"connection.autoconnect-priority\" is chosen. If the priorities are equal, then the most recently connected profile is activated. If the profiles were not connected earlier or their \"connection.timestamp\" is identical, the choice is undefined. Depending on \"connection.multi-connect\", a profile can (auto)connect only once at a time or multiple times.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY N_("The autoconnect priority in range -999 to 999. If the connection is set to autoconnect, connections with higher priority will be preferred. The higher number means higher priority. Defaults to 0. Note that this property only matters if there are more than one candidate profile to select for autoconnect. In case of equal priority, the profile used most recently is chosen.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES N_("The number of times a connection should be tried when autoactivating before giving up. Zero means forever, -1 means the global default (4 times if not overridden). Setting this to 1 means to try activation only once before blocking autoconnect. Note that after a timeout, NetworkManager will try to autoconnect again.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES N_("Whether or not slaves of this connection should be automatically brought up when NetworkManager activates this connection. This only has a real effect for master connections. The properties \"autoconnect\", \"autoconnect-priority\" and \"autoconnect-retries\" are unrelated to this setting. The permitted values are: 0: leave slave connections untouched, 1: activate all the slave connections with this connection, -1: default. If -1 (default) is set, global connection.autoconnect-slaves is read to determine the real value. If it is default as well, this fallbacks to 0.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_DNS_OVER_TLS N_("Whether DNSOverTls (dns-over-tls) is enabled for the connection. DNSOverTls is a technology which uses TLS to encrypt dns traffic. The permitted values are: \"yes\" (2) use DNSOverTls and disabled fallback, \"opportunistic\" (1) use DNSOverTls but allow fallback to unencrypted resolution, \"no\" (0) don't ever use DNSOverTls. If unspecified \"default\" depends on the plugin used. Systemd-resolved uses global setting. This feature requires a plugin which supports DNSOverTls. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT N_("If greater than zero, delay success of IP addressing until either the timeout is reached, or an IP gateway replies to a ping.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_ID N_("A human readable unique identifier for the connection, like \"Work Wi-Fi\" or \"T-Mobile 3G\".") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_INTERFACE_NAME N_("The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). For software devices this specifies the name of the created device. For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_LLDP N_("Whether LLDP is enabled for the connection.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_LLMNR N_("Whether Link-Local Multicast Name Resolution (LLMNR) is enabled for the connection. LLMNR is a protocol based on the Domain Name System (DNS) packet format that allows both IPv4 and IPv6 hosts to perform name resolution for hosts on the same local link. The permitted values are: \"yes\" (2) register hostname and resolving for the connection, \"no\" (0) disable LLMNR for the interface, \"resolve\" (1) do not register hostname but allow resolving of LLMNR host names If unspecified, \"default\" ultimately depends on the DNS plugin (which for systemd-resolved currently means \"yes\"). This feature requires a plugin which supports LLMNR. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MASTER N_("Interface name of the master device or UUID of the master connection.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MDNS N_("Whether mDNS is enabled for the connection. The permitted values are: \"yes\" (2) register hostname and resolving for the connection, \"no\" (0) disable mDNS for the interface, \"resolve\" (1) do not register hostname but allow resolving of mDNS host names and \"default\" (-1) to allow lookup of a global default in NetworkManager.conf. If unspecified, \"default\" ultimately depends on the DNS plugin (which for systemd-resolved currently means \"no\"). This feature requires a plugin which supports mDNS. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_METERED N_("Whether the connection is metered. When updating this property on a currently activated connection, the change takes effect immediately.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MPTCP_FLAGS N_("Whether to configure MPTCP endpoints and the address flags. If MPTCP is enabled in NetworkManager, it will configure the addresses of the interface as MPTCP endpoints. Note that IPv4 loopback addresses (127.0.0.0/8), IPv4 link local addresses (169.254.0.0/16), the IPv6 loopback address (::1), IPv6 link local addresses (fe80::/10), IPv6 unique local addresses (ULA, fc00::/7) and IPv6 privacy extension addresses (rfc3041, ipv6.ip6-privacy) will be excluded from being configured as endpoints. If \"disabled\" (0x1), MPTCP handling for the interface is disabled and no endpoints are registered. The flag \"enabled-on-global-iface\" (0x2) means that MPTCP handling is enabled if the interface configures a default route in the main routing table. This choice is per-address family, for example if there is an IPv4 default route 0.0.0.0/0, IPv4 endpoints are configured. The \"enabled\" (0x4) flag means that MPTCP handling is explicitly enabled. This flag can also be implied from the presence of other flags. If MPTCP handling is enabled, then endpoints will be configured with the specified address flags \"signal\" (0x10), \"subflow\" (0x20), \"backup\" (0x40), \"fullmesh\" (0x80). See ip-mptcp(8) manual for additional information about the flags. If the flags are zero, the global connection default from NetworkManager.conf is honored. If still unspecified, the fallback is either \"disabled\" or \"enabled-on-global-iface,subflow\" depending on \"/proc/sys/net/mptcp/enabled\". NetworkManager does not change the MPTCP limits nor enable MPTCP via \"/proc/sys/net/mptcp/enabled\". That is a host configuration which the admin can change via sysctl and ip-mptcp. Strict reverse path filtering (rp_filter) breaks many MPTCP use cases, so when MPTCP handling for IPv4 addresses on the interface is enabled, NetworkManager would loosen the strict reverse path filtering (1) to the loose setting (2).") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MUD_URL N_("If configured, set to a Manufacturer Usage Description (MUD) URL that points to manufacturer-recommended network policies for IoT devices. It is transmitted as a DHCPv4 or DHCPv6 option. The value must be a valid URL starting with \"https://\". The special value \"none\" is allowed to indicate that no MUD URL is used. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the ultimate default is \"none\".") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MULTI_CONNECT N_("Specifies whether the profile can be active multiple times at a particular moment. The value is of type NMConnectionMultiConnect.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_PERMISSIONS N_("An array of strings defining what access a given user has to this connection. If this is NULL or empty, all users are allowed to access this connection; otherwise users are allowed if and only if they are in this list. When this is not empty, the connection can be active only when one of the specified users is logged into an active session. Each entry is of the form \"[type]:[id]:[reserved]\"; for example, \"user:dcbw:blah\". At this time only the \"user\" [type] is allowed. Any other values are ignored and reserved for future use. [id] is the username that this permission refers to, which may not contain the \":\" character. Any [reserved] information present must be ignored and is reserved for future use. All of [type], [id], and [reserved] must be valid UTF-8.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_READ_ONLY N_("FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_SECONDARIES N_("List of connection UUIDs that should be activated when the base connection itself is activated. Currently, only VPN connections are supported.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_SLAVE_TYPE N_("Setting name of the device type of this slave's master connection (eg, \"bond\"), or NULL if this connection is not a slave.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. The '$' character is treated special to perform dynamic substitutions at runtime. Currently, supported are \"${CONNECTION}\", \"${DEVICE}\", \"${MAC}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that \"${DEVICE}\" corresponds to the interface name of the device and \"${MAC}\" is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}-${BOOT}-${DEVICE}\" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to \"${CONNECTION}\" and uses a unique, fixed ID for the connection.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_TIMESTAMP N_("The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved).") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_TYPE N_("Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, \"802-3-ethernet\" or \"802-11-wireless\" or \"bluetooth\", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, \"vpn\" or \"bridge\", etc).") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_UUID N_("A universally unique identifier for the connection, for example generated with libuuid. It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network. For example, it should not be changed when the \"id\" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or \"type\" property changes. The UUID must be in the format \"2815492f-7e56-435e-b2e9-246bd7cdc664\" (ie, contains only hexadecimal characters and \"-\").") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY N_("Time in milliseconds to wait for connection to be considered activated. The wait will start after the pre-up dispatcher event. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT N_("Timeout in milliseconds to wait for device at startup. During boot, devices may take a while to be detected by the driver. This property will cause to delay NetworkManager-wait-online.service and nm-online to give the device a chance to appear. This works by waiting for the given timeout until a compatible device for the profile is available and managed. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_ZONE N_("The trust level of a the connection. Free form case-insensitive string (for example \"Home\", \"Work\", \"Public\"). NULL or unspecified zone means the connection will be placed in the default zone as defined by the firewall. When updating this property on a currently activated connection, the change takes effect immediately.") #define DESCRIBE_DOC_NM_SETTING_6LOWPAN_PARENT N_("If given, specifies the parent interface name or parent connection UUID from which this 6LowPAN interface should be created.") -#define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_CHANNEL N_("Channel on which the mesh network to join is located.") -#define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS N_("Anycast DHCP MAC address used when requesting an IP address via DHCP. The specific anycast address used determines which DHCP server class answers the request. This is currently only implemented by dhclient DHCP plugin.") -#define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_SSID N_("SSID of the mesh network to join.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_AP_ISOLATION N_("Configures AP isolation, which prevents communication between wireless devices connected to this AP. This property can be set to a value different from NM_TERNARY_DEFAULT (-1) only when the interface is configured in AP mode. If set to NM_TERNARY_TRUE (1), devices are not able to communicate with each other. This increases security because it protects devices against attacks from other clients in the network. At the same time, it prevents devices to access resources on the same wireless networks as file shares, printers, etc. If set to NM_TERNARY_FALSE (0), devices can talk to each other. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_FALSE (0).") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_BAND N_("802.11 frequency band of the network. One of \"a\" for 5GHz 802.11a or \"bg\" for 2.4GHz 802.11. This will lock associations to the Wi-Fi network to the specific band, i.e. if \"a\" is specified, the device will not associate with the same network in the 2.4GHz band even if the network's settings are compatible. This setting depends on specific driver capability and may not work with all drivers.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_BSSID N_("If specified, directs the device to only associate with the given access point. This capability is highly driver dependent and not supported by all devices. Note: this property does not control the BSSID used when creating an Ad-Hoc network and is unlikely to in the future.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_CHANNEL N_("Wireless channel to use for the Wi-Fi connection. The device will only join (or create for Ad-Hoc networks) a Wi-Fi network on the specified channel. Because channel numbers overlap between bands, this property also requires the \"band\" property to be set.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS N_("If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. Beside explicitly specifying a MAC address, the special values \"preserve\", \"permanent\", \"random\" and \"stable\" are supported. \"preserve\" means not to touch the MAC address on activation. \"permanent\" means to use the permanent hardware address of the device. \"random\" creates a random MAC address on each connect. \"stable\" creates a hashed MAC address based on connection.stable-id and a machine dependent key. If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to \"preserve\" (older versions of NetworkManager may use a different default value). On D-Bus, this field is expressed as \"assigned-mac-address\" or the deprecated \"cloned-mac-address\".") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK N_("With \"cloned-mac-address\" setting \"random\" or \"stable\", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting \"FE:FF:FF:00:00:00\" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the \"random\" or \"stable\" algorithm. If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of \"FE:FF:FF:00:00:00 68:F7:28:00:00:00\" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of \"02:00:00:00:00:00 00:00:00:00:00:00\" will create a fully scrambled globally-administered, burned-in MAC address. If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, \"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00\" will create a fully scrambled MAC address, randomly locally or globally administered.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_HIDDEN N_("If TRUE, indicates that the network is a non-broadcasting network that hides its SSID. This works both in infrastructure and AP mode. In infrastructure mode, various workarounds are used for a more reliable discovery of hidden networks, such as probe-scanning the SSID. However, these workarounds expose inherent insecurities with hidden SSID networks, and thus hidden SSID networks should be used with caution. In AP mode, the created network does not broadcast its SSID. Note that marking the network as hidden may be a privacy issue for you (in infrastructure mode) or client stations (in AP mode), as the explicit probe-scans are distinctly recognizable on the air.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS N_("If specified, this connection will only apply to the Wi-Fi device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST N_("A list of permanent MAC addresses of Wi-Fi devices to which this connection should never apply. Each MAC address should be given in the standard hex-digits-and-colons notation (eg \"00:11:22:33:44:55\").") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION N_("One of NM_SETTING_MAC_RANDOMIZATION_DEFAULT (0) (never randomize unless the user has set a global default to randomize and the supplicant supports randomization), NM_SETTING_MAC_RANDOMIZATION_NEVER (1) (never randomize the MAC address), or NM_SETTING_MAC_RANDOMIZATION_ALWAYS (2) (always randomize the MAC address). This property is deprecated for 'cloned-mac-address'. Deprecated: 1") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MODE N_("Wi-Fi network mode; one of \"infrastructure\", \"mesh\", \"adhoc\" or \"ap\". If blank, infrastructure is assumed.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_POWERSAVE N_("One of NM_SETTING_WIRELESS_POWERSAVE_DISABLE (2) (disable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_ENABLE (3) (enable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_IGNORE (1) (don't touch currently configure setting) or NM_SETTING_WIRELESS_POWERSAVE_DEFAULT (0) (use the globally configured value). All other values are reserved.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_RATE N_("If non-zero, directs the device to only use the specified bitrate for communication with the access point. Units are in Kb/s, ie 5500 = 5.5 Mbit/s. This property is highly driver dependent and not all devices support setting a static bitrate.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SEEN_BSSIDS N_("A list of BSSIDs (each BSSID formatted as a MAC address like \"00:11:22:33:44:55\") that have been detected as part of the Wi-Fi network. NetworkManager internally tracks previously seen BSSIDs. The property is only meant for reading and reflects the BSSID list of NetworkManager. The changes you make to this property will not be preserved.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SSID N_("SSID of the Wi-Fi network. Must be specified.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_TX_POWER N_("If non-zero, directs the device to use the specified transmit power. Units are dBm. This property is highly driver dependent and not all devices support setting a static transmit power.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_WAKE_ON_WLAN N_("The NMSettingWirelessWakeOnWLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY (0x2), NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT (0x4), NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC (0x8), NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE (0x10), NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST (0x20), NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE (0x40), NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE (0x80), NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP (0x100) or the special values NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager).") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_AUTH_ALG N_("When WEP is used (ie, key-mgmt = \"none\" or \"ieee8021x\") indicate the 802.11 authentication algorithm required by the AP here. One of \"open\" for Open System, \"shared\" for Shared Key, or \"leap\" for Cisco LEAP. When using Cisco LEAP (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\") the \"leap-username\" and \"leap-password\" properties must be specified.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_FILS N_("Indicates whether Fast Initial Link Setup (802.11ai) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE (1) (disable FILS), NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL (2) (enable FILS if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED (3) (enable FILS and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) and no global default is set, FILS will be optionally enabled.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_GROUP N_("A list of group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of \"wep40\", \"wep104\", \"tkip\", or \"ccmp\".") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_KEY_MGMT N_("Key management used for the connection. One of \"none\" (WEP or no password protection), \"ieee8021x\" (Dynamic WEP), \"owe\" (Opportunistic Wireless Encryption), \"wpa-psk\" (WPA2 + WPA3 personal), \"sae\" (WPA3 personal only), \"wpa-eap\" (WPA2 + WPA3 enterprise) or \"wpa-eap-suite-b-192\" (WPA3 enterprise only). This property must be set for any Wi-Fi connection that uses security.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD N_("The login password for legacy LEAP connections (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\").") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS N_("Flags indicating how to handle the \"leap-password\" property.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME N_("The login username for legacy LEAP connections (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\").") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PAIRWISE N_("A list of pairwise encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of \"tkip\" or \"ccmp\".") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PMF N_("Indicates whether Protected Management Frames (802.11w) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE (1) (disable PMF), NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL (2) (enable PMF if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED (3) (enable PMF and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) and no global default is set, PMF will be optionally enabled.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PROTO N_("List of strings specifying the allowed WPA protocol versions to use. Each element may be one \"wpa\" (allow WPA) or \"rsn\" (allow WPA2/RSN). If not specified, both WPA and RSN connections are allowed.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PSK N_("Pre-Shared-Key for WPA networks. For WPA-PSK, it's either an ASCII passphrase of 8 to 63 characters that is (as specified in the 802.11i standard) hashed to derive the actual key, or the key in form of 64 hexadecimal character. The WPA3-Personal networks use a passphrase of any length for SAE authentication.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS N_("Flags indicating how to handle the \"psk\" property.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS N_("Flags indicating how to handle the \"wep-key0\", \"wep-key1\", \"wep-key2\", and \"wep-key3\" properties.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE N_("Controls the interpretation of WEP keys. Allowed values are NM_WEP_KEY_TYPE_KEY (1), in which case the key is either a 10- or 26-character hexadecimal string, or a 5- or 13-character ASCII password; or NM_WEP_KEY_TYPE_PASSPHRASE (2), in which case the passphrase is provided as a string and will be hashed using the de-facto MD5 method to derive the actual WEP key.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY0 N_("Index 0 WEP key. This is the WEP key used in most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY1 N_("Index 1 WEP key. This WEP index is not used by most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY2 N_("Index 2 WEP key. This WEP index is not used by most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY3 N_("Index 3 WEP key. This WEP index is not used by most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX N_("When static WEP is used (ie, key-mgmt = \"none\") and a non-default WEP key index is used by the AP, put that WEP key index here. Valid values are 0 (default key) through 3. Note that some consumer access points (like the Linksys WRT54G) number the keys 1 - 4.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WPS_METHOD N_("Flags indicating which mode of WPS is to be used if any. There's little point in changing the default setting as NetworkManager will automatically determine whether it's feasible to start WPS enrollment from the Access Point capabilities. WPS can be disabled by setting this property to a value of 1.") #define DESCRIBE_DOC_NM_SETTING_802_1X_ALTSUBJECT_MATCHES N_("List of strings to be matched against the altSubjectName of the certificate presented by the authentication server. If the list is empty, no verification of the server certificate's altSubjectName is performed.") #define DESCRIBE_DOC_NM_SETTING_802_1X_ANONYMOUS_IDENTITY N_("Anonymous identity string for EAP authentication methods. Used as the unencrypted identity with EAP types that support different tunneled identity like EAP-TTLS.") #define DESCRIBE_DOC_NM_SETTING_802_1X_AUTH_TIMEOUT N_("A timeout for the authentication. Zero means the global default; if the global default is not set, the authentication timeout is 25 seconds.") @@ -89,21 +76,6 @@ #define DESCRIBE_DOC_NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS N_("Flags indicating how to handle the \"private-key-password\" property.") #define DESCRIBE_DOC_NM_SETTING_802_1X_SUBJECT_MATCH N_("Substring to be matched against the subject of the certificate presented by the authentication server. When unset, no verification of the authentication server certificate's subject is performed. This property provides little security, if any, and its use is deprecated in favor of NMSetting8021x:domain-suffix-match.") #define DESCRIBE_DOC_NM_SETTING_802_1X_SYSTEM_CA_CERTS N_("When TRUE, overrides the \"ca-path\" and \"phase2-ca-path\" properties using the system CA directory specified at configure time with the --system-ca-path switch. The certificates in this directory are added to the verification chain in addition to any certificates specified by the \"ca-cert\" and \"phase2-ca-cert\" properties. If the path provided with --system-ca-path is rather a file name (bundle of trusted CA certificates), it overrides \"ca-cert\" and \"phase2-ca-cert\" properties instead (sets ca_cert/ca_cert2 options for wpa_supplicant).") -#define DESCRIBE_DOC_NM_SETTING_WIRED_ACCEPT_ALL_MAC_ADDRESSES N_("When TRUE, setup the interface to accept packets for all MAC addresses. This is enabling the kernel interface flag IFF_PROMISC. When FALSE, the interface will only accept the packets with the interface destination mac address or broadcast.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_AUTO_NEGOTIATE N_("When TRUE, enforce auto-negotiation of speed and duplex mode. If \"speed\" and \"duplex\" properties are both specified, only that single mode will be advertised and accepted during the link auto-negotiation process: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. When FALSE, \"speed\" and \"duplex\" properties should be both set or link configuration will be skipped.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_CLONED_MAC_ADDRESS N_("If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. Beside explicitly specifying a MAC address, the special values \"preserve\", \"permanent\", \"random\" and \"stable\" are supported. \"preserve\" means not to touch the MAC address on activation. \"permanent\" means to use the permanent hardware address if the device has one (otherwise this is treated as \"preserve\"). \"random\" creates a random MAC address on each connect. \"stable\" creates a hashed MAC address based on connection.stable-id and a machine dependent key. If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to \"preserve\" (older versions of NetworkManager may use a different default value). On D-Bus, this field is expressed as \"assigned-mac-address\" or the deprecated \"cloned-mac-address\".") -#define DESCRIBE_DOC_NM_SETTING_WIRED_DUPLEX N_("When a value is set, either \"half\" or \"full\", configures the device to use the specified duplex mode. If \"auto-negotiate\" is \"yes\" the specified duplex mode will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. If the value is unset (the default), the link configuration will be either skipped (if \"auto-negotiate\" is \"no\", the default) or will be auto-negotiated (if \"auto-negotiate\" is \"yes\") and the local device will advertise all the supported duplex modes. Must be set together with the \"speed\" property if specified. Before specifying a duplex mode be sure your device supports it.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK N_("With \"cloned-mac-address\" setting \"random\" or \"stable\", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting \"FE:FF:FF:00:00:00\" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the \"random\" or \"stable\" algorithm. If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of \"FE:FF:FF:00:00:00 68:F7:28:00:00:00\" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of \"02:00:00:00:00:00 00:00:00:00:00:00\" will create a fully scrambled globally-administered, burned-in MAC address. If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, \"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00\" will create a fully scrambled MAC address, randomly locally or globally administered.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_MAC_ADDRESS N_("If specified, this connection will only apply to the Ethernet device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).") -#define DESCRIBE_DOC_NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST N_("If specified, this connection will never apply to the Ethernet device whose permanent MAC address matches an address in the list. Each MAC address is in the standard hex-digits-and-colons notation (00:11:22:33:44:55).") -#define DESCRIBE_DOC_NM_SETTING_WIRED_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_PORT N_("Specific port type to use if the device supports multiple attachment methods. One of \"tp\" (Twisted Pair), \"aui\" (Attachment Unit Interface), \"bnc\" (Thin Ethernet) or \"mii\" (Media Independent Interface). If the device supports only one port type, this setting is ignored.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_S390_NETTYPE N_("s390 network device type; one of \"qeth\", \"lcs\", or \"ctc\", representing the different types of virtual network devices available on s390 systems.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_S390_OPTIONS N_("Dictionary of key/value pairs of s390-specific device options. Both keys and values must be strings. Allowed keys include \"portno\", \"layer2\", \"portname\", \"protocol\", among others. Key names must contain only alphanumeric characters (ie, [a-zA-Z0-9]). Currently, NetworkManager itself does nothing with this information. However, s390utils ships a udev rule which parses this information and applies it to the interface.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_S390_SUBCHANNELS N_("Identifies specific subchannels that this network device uses for communication with z/VM or s390 host. Like the \"mac-address\" property for non-z/VM devices, this property can be used to ensure this connection only applies to the network device that uses these subchannels. The list should contain exactly 3 strings, and each string may only be composed of hexadecimal characters and the period (.) character.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_SPEED N_("When a value greater than 0 is set, configures the device to use the specified speed. If \"auto-negotiate\" is \"yes\" the specified speed will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabit speeds, as in this case link negotiation is mandatory. If the value is unset (0, the default), the link configuration will be either skipped (if \"auto-negotiate\" is \"no\", the default) or will be auto-negotiated (if \"auto-negotiate\" is \"yes\") and the local device will advertise all the supported speeds. In Mbit/s, ie 100 == 100Mbit/s. Must be set together with the \"duplex\" property when non-zero. Before specifying a speed value be sure your device supports it.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_WAKE_ON_LAN N_("The NMSettingWiredWakeOnLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRED_WAKE_ON_LAN_PHY (0x2), NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST (0x4), NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST (0x8), NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST (0x10), NM_SETTING_WIRED_WAKE_ON_LAN_ARP (0x20), NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC (0x40) or the special values NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager).") -#define DESCRIBE_DOC_NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD N_("If specified, the password used with magic-packet-based Wake-on-LAN, represented as an Ethernet MAC address. If NULL, no password will be required.") #define DESCRIBE_DOC_NM_SETTING_ADSL_ENCAPSULATION N_("Encapsulation of ADSL connection. Can be \"vcmux\" or \"llc\".") #define DESCRIBE_DOC_NM_SETTING_ADSL_PASSWORD N_("Password used to authenticate with the ADSL service.") #define DESCRIBE_DOC_NM_SETTING_ADSL_PASSWORD_FLAGS N_("Flags indicating how to handle the \"password\" property.") @@ -114,7 +86,6 @@ #define DESCRIBE_DOC_NM_SETTING_BLUETOOTH_BDADDR N_("The Bluetooth address of the device.") #define DESCRIBE_DOC_NM_SETTING_BLUETOOTH_TYPE N_("Either \"dun\" for Dial-Up Networking connections or \"panu\" for Personal Area Networking connections to devices supporting the NAP profile.") #define DESCRIBE_DOC_NM_SETTING_BOND_OPTIONS N_("Dictionary of key/value pairs of bonding options. Both keys and values must be strings. Option names must contain only alphanumeric characters (ie, [a-zA-Z0-9]).") -#define DESCRIBE_DOC_NM_SETTING_BOND_PORT_QUEUE_ID N_("The queue ID of this bond port. The maximum value of queue ID is the number of TX queues currently active in device.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_AGEING_TIME N_("The Ethernet MAC address aging time, in seconds.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_FORWARD_DELAY N_("The Spanning Tree Protocol (STP) forwarding delay, in seconds.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_GROUP_ADDRESS N_("If specified, The MAC address of the multicast group this bridge uses for STP. The address must be a link-local address in standard Ethernet MAC address format, ie an address of the form 01:80:C2:00:00:0X, with X in [0, 4..F]. If not specified the default value is 01:80:C2:00:00:00.") @@ -151,32 +122,6 @@ #define DESCRIBE_DOC_NM_SETTING_CDMA_PASSWORD N_("The password used to authenticate with the network, if required. Many providers do not require a password, or accept any password. But if a password is required, it is specified here.") #define DESCRIBE_DOC_NM_SETTING_CDMA_PASSWORD_FLAGS N_("Flags indicating how to handle the \"password\" property.") #define DESCRIBE_DOC_NM_SETTING_CDMA_USERNAME N_("The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTH_RETRIES N_("The number of retries for the authentication. Zero means to try indefinitely; -1 means to use a global default. If the global default is not set, the authentication retries for 3 times before failing the connection. Currently, this only applies to 802-1x authentication.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT N_("Whether or not the connection should be automatically connected by NetworkManager when the resources for the connection are available. TRUE to automatically activate the connection, FALSE to require manual intervention to activate the connection. Autoconnect happens when the circumstances are suitable. That means for example that the device is currently managed and not active. Autoconnect thus never replaces or competes with an already active profile. Note that autoconnect is not implemented for VPN profiles. See \"secondaries\" as an alternative to automatically connect VPN profiles. If multiple profiles are ready to autoconnect on the same device, the one with the better \"connection.autoconnect-priority\" is chosen. If the priorities are equal, then the most recently connected profile is activated. If the profiles were not connected earlier or their \"connection.timestamp\" is identical, the choice is undefined. Depending on \"connection.multi-connect\", a profile can (auto)connect only once at a time or multiple times.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY N_("The autoconnect priority in range -999 to 999. If the connection is set to autoconnect, connections with higher priority will be preferred. The higher number means higher priority. Defaults to 0. Note that this property only matters if there are more than one candidate profile to select for autoconnect. In case of equal priority, the profile used most recently is chosen.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES N_("The number of times a connection should be tried when autoactivating before giving up. Zero means forever, -1 means the global default (4 times if not overridden). Setting this to 1 means to try activation only once before blocking autoconnect. Note that after a timeout, NetworkManager will try to autoconnect again.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES N_("Whether or not slaves of this connection should be automatically brought up when NetworkManager activates this connection. This only has a real effect for master connections. The properties \"autoconnect\", \"autoconnect-priority\" and \"autoconnect-retries\" are unrelated to this setting. The permitted values are: 0: leave slave connections untouched, 1: activate all the slave connections with this connection, -1: default. If -1 (default) is set, global connection.autoconnect-slaves is read to determine the real value. If it is default as well, this fallbacks to 0.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_DNS_OVER_TLS N_("Whether DNSOverTls (dns-over-tls) is enabled for the connection. DNSOverTls is a technology which uses TLS to encrypt dns traffic. The permitted values are: \"yes\" (2) use DNSOverTls and disabled fallback, \"opportunistic\" (1) use DNSOverTls but allow fallback to unencrypted resolution, \"no\" (0) don't ever use DNSOverTls. If unspecified \"default\" depends on the plugin used. Systemd-resolved uses global setting. This feature requires a plugin which supports DNSOverTls. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT N_("If greater than zero, delay success of IP addressing until either the timeout is reached, or an IP gateway replies to a ping.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_ID N_("A human readable unique identifier for the connection, like \"Work Wi-Fi\" or \"T-Mobile 3G\".") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_INTERFACE_NAME N_("The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). For software devices this specifies the name of the created device. For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_LLDP N_("Whether LLDP is enabled for the connection.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_LLMNR N_("Whether Link-Local Multicast Name Resolution (LLMNR) is enabled for the connection. LLMNR is a protocol based on the Domain Name System (DNS) packet format that allows both IPv4 and IPv6 hosts to perform name resolution for hosts on the same local link. The permitted values are: \"yes\" (2) register hostname and resolving for the connection, \"no\" (0) disable LLMNR for the interface, \"resolve\" (1) do not register hostname but allow resolving of LLMNR host names If unspecified, \"default\" ultimately depends on the DNS plugin (which for systemd-resolved currently means \"yes\"). This feature requires a plugin which supports LLMNR. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MASTER N_("Interface name of the master device or UUID of the master connection.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MDNS N_("Whether mDNS is enabled for the connection. The permitted values are: \"yes\" (2) register hostname and resolving for the connection, \"no\" (0) disable mDNS for the interface, \"resolve\" (1) do not register hostname but allow resolving of mDNS host names and \"default\" (-1) to allow lookup of a global default in NetworkManager.conf. If unspecified, \"default\" ultimately depends on the DNS plugin (which for systemd-resolved currently means \"no\"). This feature requires a plugin which supports mDNS. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_METERED N_("Whether the connection is metered. When updating this property on a currently activated connection, the change takes effect immediately.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MUD_URL N_("If configured, set to a Manufacturer Usage Description (MUD) URL that points to manufacturer-recommended network policies for IoT devices. It is transmitted as a DHCPv4 or DHCPv6 option. The value must be a valid URL starting with \"https://\". The special value \"none\" is allowed to indicate that no MUD URL is used. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the ultimate default is \"none\".") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MULTI_CONNECT N_("Specifies whether the profile can be active multiple times at a particular moment. The value is of type NMConnectionMultiConnect.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_PERMISSIONS N_("An array of strings defining what access a given user has to this connection. If this is NULL or empty, all users are allowed to access this connection; otherwise users are allowed if and only if they are in this list. When this is not empty, the connection can be active only when one of the specified users is logged into an active session. Each entry is of the form \"[type]:[id]:[reserved]\"; for example, \"user:dcbw:blah\". At this time only the \"user\" [type] is allowed. Any other values are ignored and reserved for future use. [id] is the username that this permission refers to, which may not contain the \":\" character. Any [reserved] information present must be ignored and is reserved for future use. All of [type], [id], and [reserved] must be valid UTF-8.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_READ_ONLY N_("FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_SECONDARIES N_("List of connection UUIDs that should be activated when the base connection itself is activated. Currently, only VPN connections are supported.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_SLAVE_TYPE N_("Setting name of the device type of this slave's master connection (eg, \"bond\"), or NULL if this connection is not a slave.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. The '$' character is treated special to perform dynamic substitutions at runtime. Currently, supported are \"${CONNECTION}\", \"${DEVICE}\", \"${MAC}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that \"${DEVICE}\" corresponds to the interface name of the device and \"${MAC}\" is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}-${BOOT}-${DEVICE}\" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to \"${CONNECTION}\" and uses a unique, fixed ID for the connection.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_TIMESTAMP N_("The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved).") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_TYPE N_("Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, \"802-3-ethernet\" or \"802-11-wireless\" or \"bluetooth\", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, \"vpn\" or \"bridge\", etc).") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_UUID N_("A universally unique identifier for the connection, for example generated with libuuid. It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network. For example, it should not be changed when the \"id\" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or \"type\" property changes. The UUID must be in the format \"2815492f-7e56-435e-b2e9-246bd7cdc664\" (ie, contains only hexadecimal characters and \"-\").") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT N_("Timeout in milliseconds to wait for device at startup. During boot, devices may take a while to be detected by the driver. This property will cause to delay NetworkManager-wait-online.service and nm-online to give the device a chance to appear. This works by waiting for the given timeout until a compatible device for the profile is available and managed. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_ZONE N_("The trust level of a the connection. Free form case-insensitive string (for example \"Home\", \"Work\", \"Public\"). NULL or unspecified zone means the connection will be placed in the default zone as defined by the firewall. When updating this property on a currently activated connection, the change takes effect immediately.") #define DESCRIBE_DOC_NM_SETTING_DCB_APP_FCOE_FLAGS N_("Specifies the NMSettingDcbFlags for the DCB FCoE application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4).") #define DESCRIBE_DOC_NM_SETTING_DCB_APP_FCOE_MODE N_("The FCoE controller mode; either \"fabric\" or \"vn2vn\". Since 1.34, NULL is the default and means \"fabric\". Before 1.34, NULL was rejected as invalid and the default was \"fabric\".") #define DESCRIBE_DOC_NM_SETTING_DCB_APP_FCOE_PRIORITY N_("The highest User Priority (0 - 7) which FCoE frames should use, or -1 for default priority. Only used when the \"app-fcoe-flags\" property includes the NM_SETTING_DCB_FLAG_ENABLE (0x1) flag.") @@ -206,28 +151,11 @@ #define DESCRIBE_DOC_NM_SETTING_GSM_SIM_ID N_("The SIM card unique identifier (as given by the WWAN management service) which this connection applies to. If given, the connection will apply to any device also allowed by \"device-id\" which contains a SIM card matching the given identifier.") #define DESCRIBE_DOC_NM_SETTING_GSM_SIM_OPERATOR_ID N_("A MCC/MNC string like \"310260\" or \"21601\" identifying the specific mobile network operator which this connection applies to. If given, the connection will apply to any device also allowed by \"device-id\" and \"sim-id\" which contains a SIM card provisioned by the given operator.") #define DESCRIBE_DOC_NM_SETTING_GSM_USERNAME N_("The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here.") -#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DHCP N_("Whether the system hostname can be determined from DHCP on this connection. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).") -#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP N_("Whether the system hostname can be determined from reverse DNS lookup of addresses on this device. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).") -#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT N_("If set to NM_TERNARY_TRUE (1), NetworkManager attempts to get the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this device only when the device has the default route for the given address family (IPv4/IPv6). If set to NM_TERNARY_FALSE (0), the hostname can be set from this device even if it doesn't have the default route. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_FALSE (0).") -#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_PRIORITY N_("The relative priority of this connection to determine the system hostname. A lower numerical value is better (higher priority). A connection with higher priority is considered before connections with lower priority. If the value is zero, it can be overridden by a global value from NetworkManager configuration. If the property doesn't have a value in the global configuration, the value is assumed to be 100. Negative values have the special effect of excluding other connections with a greater numerical priority value; so in presence of at least one negative priority, only connections with the lowest priority value will be used to determine the hostname.") #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_MAC_ADDRESS N_("If specified, this connection will only apply to the IPoIB device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).") #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames.") #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_P_KEY N_("The InfiniBand P_Key to use for this device. A value of -1 means to use the default P_Key (aka \"the P_Key at index 0\"). Otherwise, it is a 16-bit unsigned integer, whose high bit is set if it is a \"full membership\" P_Key.") #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_PARENT N_("The interface name of the parent device of this device. Normally NULL, but if the \"p_key\" property is set, then you must specify the base device by setting either this property or \"mac-address\".") #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_TRANSPORT_MODE N_("The IP-over-InfiniBand transport mode. Either \"datagram\" or \"connected\".") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT N_("How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLAGS N_("Tunnel flags. Currently, the following values are supported: NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS (0x2), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL (0x4), NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV (0x8), NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY (0x10), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK (0x20). They are valid only for IPv6 tunnels.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLOW_LABEL N_("The flow label to assign to tunnel packets. This property applies only to IPv6 tunnels.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_INPUT_KEY N_("The key used for tunnel input packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_LOCAL N_("The local endpoint of the tunnel; the value can be empty, otherwise it must contain an IPv4 or IPv6 address.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MODE N_("The tunneling mode, for example NM_IP_TUNNEL_MODE_IPIP (1) or NM_IP_TUNNEL_MODE_GRE (2).") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_OUTPUT_KEY N_("The key used for tunnel output packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_PARENT N_("If given, specifies the parent interface name or parent connection UUID the new device will be bound to so that tunneled packets will only be routed via that interface.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY N_("Whether to enable Path MTU Discovery on this tunnel.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_REMOTE N_("The remote endpoint of the tunnel; the value must contain an IPv4 or IPv6 address.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TOS N_("The type of service (IPv4) or traffic class (IPv6) field to be set on tunneled packets.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TTL N_("The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ADDRESSES N_("A list of IPv4 addresses and their prefix length. Multiple addresses can be separated by comma. For example \"192.168.1.5/24, 10.1.0.5/24\". The addresses are listed in decreasing priority, meaning the first address will be the primary address.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID N_("A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values \"mac\" and \"perm-mac\" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value \"ipv6-duid\" uses the DUID from \"ipv6.dhcp-duid\" property as an RFC4361-compliant client identifier. As IAID it uses \"ipv4.dhcp-iaid\" and falls back to \"ipv6.dhcp-iaid\" if unset. The special value \"duid\" generates a RFC4361-compliant client identifier based on \"ipv4.dhcp-iaid\" and uses a DUID generated by hashing /etc/machine-id. The special value \"stable\" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If you set the stable-id, you may want to include the \"${DEVICE}\" or \"${MAC}\" specifier to get a per-device key. If unset, a globally configured default is used. If still unset, the default depends on the DHCP plugin.") @@ -242,10 +170,11 @@ #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS N_("Array of IP addresses of DNS servers.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are \"attempts\", \"debug\", \"edns0\", \"inet6\", \"ip6-bytestring\", \"ip6-dotint\", \"ndots\", \"no-check-names\", \"no-ip6-dotint\", \"no-reload\", \"no-tld-query\", \"rotate\", \"single-request\", \"single-request-reopen\", \"timeout\", \"trust-ad\", \"use-vc\". The \"trust-ad\" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have \"trust-ad\" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then \"edns0\" and \"trust-ad\" are automatically added.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the \"rotate\" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured.") -#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting.") +#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting \"ignore-auto-dns\". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15).") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set. The gateway's main purpose is to control the next hop of the standard default route on the device. Hence, the gateway property conflicts with \"never-default\" and will be automatically dropped if the IP configuration is set to never-default. As an alternative to set the gateway, configure a static default route with /0 as prefix length.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.") +#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_LINK_LOCAL N_("Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. When set to \"auto\", the value is dependent on \"ipv4.method\". When set to \"default\", it honors the global connection default, before falling back to \"auto\". Note that if \"ipv4.method\" is \"disabled\", then link local addressing is always disabled too. The default is \"default\". Since 1.40") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_MAY_FAIL N_("If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out. Note that at least one IP configuration must succeed or overall network configuration will still fail. For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_METHOD N_("IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support \"disabled\", \"auto\", \"manual\", and \"link-local\". See the subclass-specific documentation for other values. In general, for the \"auto\" method, properties such as \"dns\" and \"routes\" specify information that is added on to the information returned from automatic configuration. The \"ignore-auto-routes\" and \"ignore-auto-dns\" properties modify this behavior. For methods that imply no upstream network, such as \"shared\" or \"link-local\", these properties must be empty. For IPv4 method \"shared\", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_NEVER_DEFAULT N_("If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager.") @@ -254,7 +183,7 @@ #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTE_TABLE N_("Enable policy routing (source routing) and set the routing table used when adding routes. This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTES N_("A list of IPv4 destination addresses, prefix length, optional IPv4 next hop addresses, optional route metric, optional attribute. The valid syntax is: \"ip[/prefix] [next-hop] [metric] [attribute=val]...[,ip[/prefix]...]\". For example \"192.0.2.0/24 10.1.1.1 77, 198.51.100.0/24\".") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTING_RULES N_("A comma separated list of routing rules for policy routing.") -#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE N_("Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. On D-Bus, the absence of an addr-gen-mode setting equals enabling stable-privacy. For keyfile plugin, the absence of the setting on disk means EUI64 so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by \"ip6-privacy\" property and it does not affect the temporary addresses configured with this option.") +#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE N_("Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0), NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64 (2) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT (3). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. The special values \"default\" and \"default-or-eui64\" will fallback to the global connection default in as documented in NetworkManager.conf(5) manual. If the global default is not specified, the fallback value is \"stable-privacy\" or \"eui64\", respectively. For libnm, the property defaults to \"default\" since 1.40. Previously it defaulted to \"stable-privacy\". On D-Bus, the absence of an addr-gen-mode setting equals \"default\". For keyfile plugin, the absence of the setting on disk means \"default-or-eui64\" so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by \"ip6-privacy\" property and it does not affect the temporary addresses configured with this option.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDRESSES N_("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 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).") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_DUID N_("A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value \"lease\" will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and \"dhclient\" is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values \"llt\" and \"ll\" will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values \"stable-llt\", \"stable-ll\" and \"stable-uuid\" will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. You may want to include the \"${DEVICE}\" or \"${MAC}\" specifier in the stable-id, in case this profile gets activated on multiple devices. So, the link-layer address of \"stable-ll\" and \"stable-llt\" will be a generated address derived from the stable id. The DUID-LLT time value in the \"stable-llt\" option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in \"llt\"). When the property is unset, the global value provided for \"ipv6.dhcp-duid\" is used. If no global value is provided, the default \"lease\" value is assumed.") @@ -267,13 +196,14 @@ #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS N_("Array of IP addresses of DNS servers.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are \"attempts\", \"debug\", \"edns0\", \"inet6\", \"ip6-bytestring\", \"ip6-dotint\", \"ndots\", \"no-check-names\", \"no-ip6-dotint\", \"no-reload\", \"no-tld-query\", \"rotate\", \"single-request\", \"single-request-reopen\", \"timeout\", \"trust-ad\", \"use-vc\". The \"trust-ad\" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have \"trust-ad\" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then \"edns0\" and \"trust-ad\" are automatically added.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the \"rotate\" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured.") -#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting.") +#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting \"ignore-auto-dns\". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15).") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set. The gateway's main purpose is to control the next hop of the standard default route on the device. Hence, the gateway property conflicts with \"never-default\" and will be automatically dropped if the IP configuration is set to never-default. As an alternative to set the gateway, configure a static default route with /0 as prefix length.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IP6_PRIVACY N_("Configure IPv6 Privacy Extensions for SLAAC, described in RFC4941. If enabled, it makes the kernel generate a temporary IPv6 address in addition to the public one generated from MAC address via modified EUI-64. This enhances privacy, but could cause problems in some applications, on the other hand. The permitted values are: -1: unknown, 0: disabled, 1: enabled (prefer public address), 2: enabled (prefer temporary addresses). Having a per-connection setting set to \"-1\" (unknown) means fallback to global configuration \"ipv6.ip6-privacy\". If also global configuration is unspecified or set to \"-1\", fallback to read \"/proc/sys/net/ipv6/conf/default/use_tempaddr\". Note that this setting is distinct from the Stable Privacy addresses that can be enabled with the \"addr-gen-mode\" property's \"stable-privacy\" setting as another way of avoiding host tracking with IPv6 addresses.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_MAY_FAIL N_("If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out. Note that at least one IP configuration must succeed or overall network configuration will still fail. For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_METHOD N_("IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support \"disabled\", \"auto\", \"manual\", and \"link-local\". See the subclass-specific documentation for other values. In general, for the \"auto\" method, properties such as \"dns\" and \"routes\" specify information that is added on to the information returned from automatic configuration. The \"ignore-auto-routes\" and \"ignore-auto-dns\" properties modify this behavior. For methods that imply no upstream network, such as \"shared\" or \"link-local\", these properties must be empty. For IPv4 method \"shared\", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.") +#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_MTU N_("Maximum transmission unit size, in bytes. If zero (the default), the MTU is set automatically from router advertisements or is left equal to the link-layer MTU. If greater than the link-layer MTU, or greater than zero but less than the minimum IPv6 MTU of 1280, this value has no effect.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_NEVER_DEFAULT N_("If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_RA_TIMEOUT N_("A timeout for waiting Router Advertisements in seconds. If zero (the default), a globally configured default is used. If still unspecified, the timeout depends on the sysctl settings of the device. Set to 2147483647 (MAXINT32) for infinity.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_REQUIRED_TIMEOUT N_("The minimum time interval in milliseconds for which dynamic IP configuration should be tried before the connection succeeds. This property is useful for example if both IPv4 and IPv6 are enabled and are allowed to fail. Normally the connection succeeds as soon as one of the two address families completes; by setting a required timeout for e.g. IPv4, one can ensure that even if IP6 succeeds earlier than IPv4, NetworkManager waits some time for IPv4 before the connection becomes active. Note that if \"may-fail\" is FALSE for the same address family, this property has no effect as NetworkManager needs to wait for the full DHCP timeout. A zero value means that no required timeout is present, -1 means the default value (either configuration ipvx.required-timeout override or zero).") @@ -282,6 +212,19 @@ #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTES N_("Array of IP routes.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTING_RULES N_("A comma separated list of routing rules for policy routing.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_TOKEN N_("Configure the token for draft-chown-6man-tokenised-ipv6-identifiers-02 IPv6 tokenized interface identifiers. Useful with eui64 addr-gen-mode.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT N_("How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLAGS N_("Tunnel flags. Currently, the following values are supported: NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS (0x2), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL (0x4), NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV (0x8), NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY (0x10), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK (0x20). They are valid only for IPv6 tunnels.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLOW_LABEL N_("The flow label to assign to tunnel packets. This property applies only to IPv6 tunnels.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_INPUT_KEY N_("The key used for tunnel input packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_LOCAL N_("The local endpoint of the tunnel; the value can be empty, otherwise it must contain an IPv4 or IPv6 address.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MODE N_("The tunneling mode, for example NM_IP_TUNNEL_MODE_IPIP (1) or NM_IP_TUNNEL_MODE_GRE (2).") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_OUTPUT_KEY N_("The key used for tunnel output packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_PARENT N_("If given, specifies the parent interface name or parent connection UUID the new device will be bound to so that tunneled packets will only be routed via that interface.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY N_("Whether to enable Path MTU Discovery on this tunnel.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_REMOTE N_("The remote endpoint of the tunnel; the value must contain an IPv4 or IPv6 address.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TOS N_("The type of service (IPv4) or traffic class (IPv6) field to be set on tunneled packets.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TTL N_("The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value.") #define DESCRIBE_DOC_NM_SETTING_MACSEC_ENCRYPT N_("Whether the transmitted traffic must be encrypted.") #define DESCRIBE_DOC_NM_SETTING_MACSEC_MKA_CAK N_("The pre-shared CAK (Connectivity Association Key) for MACsec Key Agreement.") #define DESCRIBE_DOC_NM_SETTING_MACSEC_MKA_CAK_FLAGS N_("Flags indicating how to handle the \"mka-cak\" property.") @@ -299,6 +242,9 @@ #define DESCRIBE_DOC_NM_SETTING_MATCH_INTERFACE_NAME N_("A list of interface names to match. Each element is a shell wildcard pattern. An element can be prefixed with a pipe symbol (|) or an ampersand (&). The former means that the element is optional and the latter means that it is mandatory. If there are any optional elements, than the match evaluates to true if at least one of the optional element matches (logical OR). If there are any mandatory elements, then they all must match (logical AND). By default, an element is optional. This means that an element \"foo\" behaves the same as \"|foo\". An element can also be inverted with exclamation mark (!) between the pipe symbol (or the ampersand) and before the pattern. Note that \"!foo\" is a shortcut for the mandatory match \"&!foo\". Finally, a backslash can be used at the beginning of the element (after the optional special characters) to escape the start of the pattern. For example, \"&\\!a\" is an mandatory match for literally \"!a\".") #define DESCRIBE_DOC_NM_SETTING_MATCH_KERNEL_COMMAND_LINE N_("A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or unset, if prefixed with the exclamation mark). The argument must either be a single word, or an assignment (i.e. two words, joined by \"=\"). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching. Wildcard patterns are not supported. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the match.") #define DESCRIBE_DOC_NM_SETTING_MATCH_PATH N_("A list of paths to match against the ID_PATH udev property of devices. ID_PATH represents the topological persistent path of a device. It typically contains a subsystem string (pci, usb, platform, etc.) and a subsystem-specific identifier. For PCI devices the path has the form \"pci-$domain:$bus:$device.$function\", where each variable is an hexadecimal value; for example \"pci-0000:0a:00.0\". The path of a device can be obtained with \"udevadm info /sys/class/net/$dev | grep ID_PATH=\" or by looking at the \"path\" property exported by NetworkManager (\"nmcli -f general.path device show $dev\"). Each element of the list is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern.") +#define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_CHANNEL N_("Channel on which the mesh network to join is located.") +#define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS N_("Anycast DHCP MAC address used when requesting an IP address via DHCP. The specific anycast address used determines which DHCP server class answers the request. This is currently only implemented by dhclient DHCP plugin.") +#define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_SSID N_("SSID of the mesh network to join.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_DATAPATH_TYPE N_("The data path type. One of \"system\", \"netdev\" or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_FAIL_MODE N_("The bridge failure mode. One of \"secure\", \"standalone\" or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE N_("Enable or disable multicast snooping.") @@ -306,7 +252,6 @@ #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_STP_ENABLE N_("Enable or disable STP.") #define DESCRIBE_DOC_NM_SETTING_OVS_DPDK_DEVARGS N_("Open vSwitch DPDK device arguments.") #define DESCRIBE_DOC_NM_SETTING_OVS_DPDK_N_RXQ N_("Open vSwitch DPDK number of rx queues. Defaults to zero which means to leave the parameter in OVS unspecified and effectively configures one queue.") -#define DESCRIBE_DOC_NM_SETTING_OVS_EXTERNAL_IDS_DATA N_("A dictionary of key/value pairs with exernal-ids for OVS.") #define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_TYPE N_("The interface type. Either \"internal\", \"system\", \"patch\", \"dpdk\", or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_PEER N_("Specifies the name of the interface for the other side of the patch. The patch on the other side must also set this interface as peer.") #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_DOWNDELAY N_("The time port must be inactive in order to be considered down.") @@ -382,7 +327,6 @@ #define DESCRIBE_DOC_NM_SETTING_TUN_PI N_("If TRUE the interface will prepend a 4 byte header describing the physical interface to the packets.") #define DESCRIBE_DOC_NM_SETTING_TUN_VNET_HDR N_("If TRUE the IFF_VNET_HDR the tunnel packets will include a virtio network header.") #define DESCRIBE_DOC_NM_SETTING_USER_DATA N_("A dictionary of key/value pairs with user data. This data is ignored by NetworkManager and can be used at the users discretion. The keys only support a strict ascii format, but the values can be arbitrary UTF8 strings up to a certain length.") -#define DESCRIBE_DOC_NM_SETTING_VETH_PEER N_("This property specifies the peer interface name of the veth. This property is mandatory.") #define DESCRIBE_DOC_NM_SETTING_VLAN_EGRESS_PRIORITY_MAP N_("For outgoing packets, a list of mappings from Linux SKB priorities to 802.1p priorities. The mapping is given in the format \"from:to\" where both \"from\" and \"to\" are unsigned integers, ie \"7:3\".") #define DESCRIBE_DOC_NM_SETTING_VLAN_FLAGS N_("One or more flags which control the behavior and features of the VLAN interface. Flags include NM_VLAN_FLAG_REORDER_HEADERS (0x1) (reordering of output packet headers), NM_VLAN_FLAG_GVRP (0x2) (use of the GVRP protocol), and NM_VLAN_FLAG_LOOSE_BINDING (0x4) (loose binding of the interface to its master device's operating state). NM_VLAN_FLAG_MVRP (0x8) (use of the MVRP protocol). The default value of this property is NM_VLAN_FLAG_REORDER_HEADERS, but it used to be 0. To preserve backward compatibility, the default-value in the D-Bus API continues to be 0 and a missing property on D-Bus is still considered as 0.") #define DESCRIBE_DOC_NM_SETTING_VLAN_ID N_("The VLAN identifier that the interface created by this connection should be assigned. The valid range is from 0 to 4094, without the reserved id 4095.") @@ -416,16 +360,76 @@ #define DESCRIBE_DOC_NM_SETTING_WIFI_P2P_WPS_METHOD N_("Flags indicating which mode of WPS is to be used. There's little point in changing the default setting as NetworkManager will automatically determine the best method to use.") #define DESCRIBE_DOC_NM_SETTING_WIMAX_MAC_ADDRESS N_("If specified, this connection will only apply to the WiMAX device whose MAC address matches. This property does not change the MAC address of the device (known as MAC spoofing). Deprecated: 1") #define DESCRIBE_DOC_NM_SETTING_WIMAX_NETWORK_NAME N_("Network Service Provider (NSP) name of the WiMAX network this connection should use. Deprecated: 1") +#define DESCRIBE_DOC_NM_SETTING_WIRED_ACCEPT_ALL_MAC_ADDRESSES N_("When TRUE, setup the interface to accept packets for all MAC addresses. This is enabling the kernel interface flag IFF_PROMISC. When FALSE, the interface will only accept the packets with the interface destination mac address or broadcast.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_AUTO_NEGOTIATE N_("When TRUE, enforce auto-negotiation of speed and duplex mode. If \"speed\" and \"duplex\" properties are both specified, only that single mode will be advertised and accepted during the link auto-negotiation process: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. When FALSE, \"speed\" and \"duplex\" properties should be both set or link configuration will be skipped.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_CLONED_MAC_ADDRESS N_("If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. Beside explicitly specifying a MAC address, the special values \"preserve\", \"permanent\", \"random\" and \"stable\" are supported. \"preserve\" means not to touch the MAC address on activation. \"permanent\" means to use the permanent hardware address if the device has one (otherwise this is treated as \"preserve\"). \"random\" creates a random MAC address on each connect. \"stable\" creates a hashed MAC address based on connection.stable-id and a machine dependent key. If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to \"preserve\" (older versions of NetworkManager may use a different default value). On D-Bus, this field is expressed as \"assigned-mac-address\" or the deprecated \"cloned-mac-address\".") +#define DESCRIBE_DOC_NM_SETTING_WIRED_DUPLEX N_("When a value is set, either \"half\" or \"full\", configures the device to use the specified duplex mode. If \"auto-negotiate\" is \"yes\" the specified duplex mode will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. If the value is unset (the default), the link configuration will be either skipped (if \"auto-negotiate\" is \"no\", the default) or will be auto-negotiated (if \"auto-negotiate\" is \"yes\") and the local device will advertise all the supported duplex modes. Must be set together with the \"speed\" property if specified. Before specifying a duplex mode be sure your device supports it.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK N_("With \"cloned-mac-address\" setting \"random\" or \"stable\", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting \"FE:FF:FF:00:00:00\" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the \"random\" or \"stable\" algorithm. If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of \"FE:FF:FF:00:00:00 68:F7:28:00:00:00\" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of \"02:00:00:00:00:00 00:00:00:00:00:00\" will create a fully scrambled globally-administered, burned-in MAC address. If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, \"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00\" will create a fully scrambled MAC address, randomly locally or globally administered.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_MAC_ADDRESS N_("If specified, this connection will only apply to the Ethernet device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).") +#define DESCRIBE_DOC_NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST N_("If specified, this connection will never apply to the Ethernet device whose permanent MAC address matches an address in the list. Each MAC address is in the standard hex-digits-and-colons notation (00:11:22:33:44:55).") +#define DESCRIBE_DOC_NM_SETTING_WIRED_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_PORT N_("Specific port type to use if the device supports multiple attachment methods. One of \"tp\" (Twisted Pair), \"aui\" (Attachment Unit Interface), \"bnc\" (Thin Ethernet) or \"mii\" (Media Independent Interface). If the device supports only one port type, this setting is ignored.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_S390_NETTYPE N_("s390 network device type; one of \"qeth\", \"lcs\", or \"ctc\", representing the different types of virtual network devices available on s390 systems.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_S390_OPTIONS N_("Dictionary of key/value pairs of s390-specific device options. Both keys and values must be strings. Allowed keys include \"portno\", \"layer2\", \"portname\", \"protocol\", among others. Key names must contain only alphanumeric characters (ie, [a-zA-Z0-9]). Currently, NetworkManager itself does nothing with this information. However, s390utils ships a udev rule which parses this information and applies it to the interface.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_S390_SUBCHANNELS N_("Identifies specific subchannels that this network device uses for communication with z/VM or s390 host. Like the \"mac-address\" property for non-z/VM devices, this property can be used to ensure this connection only applies to the network device that uses these subchannels. The list should contain exactly 3 strings, and each string may only be composed of hexadecimal characters and the period (.) character.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_SPEED N_("When a value greater than 0 is set, configures the device to use the specified speed. If \"auto-negotiate\" is \"yes\" the specified speed will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabit speeds, as in this case link negotiation is mandatory. If the value is unset (0, the default), the link configuration will be either skipped (if \"auto-negotiate\" is \"no\", the default) or will be auto-negotiated (if \"auto-negotiate\" is \"yes\") and the local device will advertise all the supported speeds. In Mbit/s, ie 100 == 100Mbit/s. Must be set together with the \"duplex\" property when non-zero. Before specifying a speed value be sure your device supports it.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_WAKE_ON_LAN N_("The NMSettingWiredWakeOnLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRED_WAKE_ON_LAN_PHY (0x2), NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST (0x4), NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST (0x8), NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST (0x10), NM_SETTING_WIRED_WAKE_ON_LAN_ARP (0x20), NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC (0x40) or the special values NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager).") +#define DESCRIBE_DOC_NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD N_("If specified, the password used with magic-packet-based Wake-on-LAN, represented as an Ethernet MAC address. If NULL, no password will be required.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_FWMARK N_("The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise, it is a 32-bit fwmark for outgoing packets. Note that \"ip4-auto-default-route\" or \"ip6-auto-default-route\" enabled, implies to automatically choose a fwmark.") -#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_IP4_AUTO_DEFAULT_ROUTE N_("Whether to enable special handling of the IPv4 default route. If enabled, the IPv4 default route from wireguard.peer-routes will be placed to a dedicated routing-table and two policy routing rules will be added. The fwmark number is also used as routing-table for the default-route, and if fwmark is zero, an unused fwmark/table is chosen automatically. This corresponds to what wg-quick does with Table=auto and what WireGuard calls \"Improved Rule-based Routing\". Note that for this automatism to work, you usually don't want to set ipv4.gateway, because that will result in a conflicting default route. Leaving this at the default will enable this option automatically if ipv4.never-default is not set and there are any peers that use a default-route as allowed-ips.") +#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_IP4_AUTO_DEFAULT_ROUTE N_("Whether to enable special handling of the IPv4 default route. If enabled, the IPv4 default route from wireguard.peer-routes will be placed to a dedicated routing-table and two policy routing rules will be added. The fwmark number is also used as routing-table for the default-route, and if fwmark is zero, an unused fwmark/table is chosen automatically. This corresponds to what wg-quick does with Table=auto and what WireGuard calls \"Improved Rule-based Routing\". Note that for this automatism to work, you usually don't want to set ipv4.gateway, because that will result in a conflicting default route. Leaving this at the default will enable this option automatically if ipv4.never-default is not set and there are any peers that use a default-route as allowed-ips. Since this automatism only makes sense if you also have a peer with an /0 allowed-ips, it is usually not necessary to enable this explicitly. However, you can disable it if you want to configure your own routing and rules.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_IP6_AUTO_DEFAULT_ROUTE N_("Like ip4-auto-default-route, but for the IPv6 default route.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_LISTEN_PORT N_("The listen-port. If listen-port is not specified, the port will be chosen randomly when the interface comes up.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. If zero a default MTU is used. Note that contrary to wg-quick's MTU setting, this does not take into account the current routes at the time of activation.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PEER_ROUTES N_("Whether to automatically add routes for the AllowedIPs ranges of the peers. If TRUE (the default), NetworkManager will automatically add routes in the routing tables according to ipv4.route-table and ipv6.route-table. Usually you want this automatism enabled. If FALSE, no such routes are added automatically. In this case, the user may want to configure static routes in ipv4.routes and ipv6.routes, respectively. Note that if the peer's AllowedIPs is \"0.0.0.0/0\" or \"::/0\" and the profile's ipv4.never-default or ipv6.never-default setting is enabled, the peer route for this peer won't be added automatically.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PRIVATE_KEY N_("The 256 bit private-key in base64 encoding.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS N_("Flags indicating how to handle the \"private-key\" property.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_AP_ISOLATION N_("Configures AP isolation, which prevents communication between wireless devices connected to this AP. This property can be set to a value different from NM_TERNARY_DEFAULT (-1) only when the interface is configured in AP mode. If set to NM_TERNARY_TRUE (1), devices are not able to communicate with each other. This increases security because it protects devices against attacks from other clients in the network. At the same time, it prevents devices to access resources on the same wireless networks as file shares, printers, etc. If set to NM_TERNARY_FALSE (0), devices can talk to each other. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_FALSE (0).") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_BAND N_("802.11 frequency band of the network. One of \"a\" for 5GHz 802.11a or \"bg\" for 2.4GHz 802.11. This will lock associations to the Wi-Fi network to the specific band, i.e. if \"a\" is specified, the device will not associate with the same network in the 2.4GHz band even if the network's settings are compatible. This setting depends on specific driver capability and may not work with all drivers.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_BSSID N_("If specified, directs the device to only associate with the given access point. This capability is highly driver dependent and not supported by all devices. Note: this property does not control the BSSID used when creating an Ad-Hoc network and is unlikely to in the future. Locking a client profile to a certain BSSID will prevent roaming and also disable background scanning. That can be useful, if there is only one access point for the SSID.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_CHANNEL N_("Wireless channel to use for the Wi-Fi connection. The device will only join (or create for Ad-Hoc networks) a Wi-Fi network on the specified channel. Because channel numbers overlap between bands, this property also requires the \"band\" property to be set.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS N_("If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. Beside explicitly specifying a MAC address, the special values \"preserve\", \"permanent\", \"random\" and \"stable\" are supported. \"preserve\" means not to touch the MAC address on activation. \"permanent\" means to use the permanent hardware address of the device. \"random\" creates a random MAC address on each connect. \"stable\" creates a hashed MAC address based on connection.stable-id and a machine dependent key. If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to \"preserve\" (older versions of NetworkManager may use a different default value). On D-Bus, this field is expressed as \"assigned-mac-address\" or the deprecated \"cloned-mac-address\".") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK N_("With \"cloned-mac-address\" setting \"random\" or \"stable\", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting \"FE:FF:FF:00:00:00\" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the \"random\" or \"stable\" algorithm. If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of \"FE:FF:FF:00:00:00 68:F7:28:00:00:00\" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of \"02:00:00:00:00:00 00:00:00:00:00:00\" will create a fully scrambled globally-administered, burned-in MAC address. If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, \"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00\" will create a fully scrambled MAC address, randomly locally or globally administered.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_HIDDEN N_("If TRUE, indicates that the network is a non-broadcasting network that hides its SSID. This works both in infrastructure and AP mode. In infrastructure mode, various workarounds are used for a more reliable discovery of hidden networks, such as probe-scanning the SSID. However, these workarounds expose inherent insecurities with hidden SSID networks, and thus hidden SSID networks should be used with caution. In AP mode, the created network does not broadcast its SSID. Note that marking the network as hidden may be a privacy issue for you (in infrastructure mode) or client stations (in AP mode), as the explicit probe-scans are distinctly recognizable on the air.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS N_("If specified, this connection will only apply to the Wi-Fi device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST N_("A list of permanent MAC addresses of Wi-Fi devices to which this connection should never apply. Each MAC address should be given in the standard hex-digits-and-colons notation (eg \"00:11:22:33:44:55\").") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION N_("One of NM_SETTING_MAC_RANDOMIZATION_DEFAULT (0) (never randomize unless the user has set a global default to randomize and the supplicant supports randomization), NM_SETTING_MAC_RANDOMIZATION_NEVER (1) (never randomize the MAC address), or NM_SETTING_MAC_RANDOMIZATION_ALWAYS (2) (always randomize the MAC address). This property is deprecated for 'cloned-mac-address'. Deprecated: 1") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MODE N_("Wi-Fi network mode; one of \"infrastructure\", \"mesh\", \"adhoc\" or \"ap\". If blank, infrastructure is assumed.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_POWERSAVE N_("One of NM_SETTING_WIRELESS_POWERSAVE_DISABLE (2) (disable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_ENABLE (3) (enable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_IGNORE (1) (don't touch currently configure setting) or NM_SETTING_WIRELESS_POWERSAVE_DEFAULT (0) (use the globally configured value). All other values are reserved.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_RATE N_("If non-zero, directs the device to only use the specified bitrate for communication with the access point. Units are in Kb/s, ie 5500 = 5.5 Mbit/s. This property is highly driver dependent and not all devices support setting a static bitrate.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SEEN_BSSIDS N_("A list of BSSIDs (each BSSID formatted as a MAC address like \"00:11:22:33:44:55\") that have been detected as part of the Wi-Fi network. NetworkManager internally tracks previously seen BSSIDs. The property is only meant for reading and reflects the BSSID list of NetworkManager. The changes you make to this property will not be preserved.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SSID N_("SSID of the Wi-Fi network. Must be specified.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_TX_POWER N_("If non-zero, directs the device to use the specified transmit power. Units are dBm. This property is highly driver dependent and not all devices support setting a static transmit power.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_WAKE_ON_WLAN N_("The NMSettingWirelessWakeOnWLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY (0x2), NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT (0x4), NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC (0x8), NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE (0x10), NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST (0x20), NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE (0x40), NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE (0x80), NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP (0x100) or the special values NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager).") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_AUTH_ALG N_("When WEP is used (ie, key-mgmt = \"none\" or \"ieee8021x\") indicate the 802.11 authentication algorithm required by the AP here. One of \"open\" for Open System, \"shared\" for Shared Key, or \"leap\" for Cisco LEAP. When using Cisco LEAP (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\") the \"leap-username\" and \"leap-password\" properties must be specified.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_FILS N_("Indicates whether Fast Initial Link Setup (802.11ai) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE (1) (disable FILS), NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL (2) (enable FILS if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED (3) (enable FILS and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) and no global default is set, FILS will be optionally enabled.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_GROUP N_("A list of group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of \"wep40\", \"wep104\", \"tkip\", or \"ccmp\".") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_KEY_MGMT N_("Key management used for the connection. One of \"none\" (WEP or no password protection), \"ieee8021x\" (Dynamic WEP), \"owe\" (Opportunistic Wireless Encryption), \"wpa-psk\" (WPA2 + WPA3 personal), \"sae\" (WPA3 personal only), \"wpa-eap\" (WPA2 + WPA3 enterprise) or \"wpa-eap-suite-b-192\" (WPA3 enterprise only). This property must be set for any Wi-Fi connection that uses security.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD N_("The login password for legacy LEAP connections (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\").") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS N_("Flags indicating how to handle the \"leap-password\" property.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME N_("The login username for legacy LEAP connections (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\").") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PAIRWISE N_("A list of pairwise encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of \"tkip\" or \"ccmp\".") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PMF N_("Indicates whether Protected Management Frames (802.11w) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE (1) (disable PMF), NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL (2) (enable PMF if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED (3) (enable PMF and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) and no global default is set, PMF will be optionally enabled.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PROTO N_("List of strings specifying the allowed WPA protocol versions to use. Each element may be one \"wpa\" (allow WPA) or \"rsn\" (allow WPA2/RSN). If not specified, both WPA and RSN connections are allowed.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PSK N_("Pre-Shared-Key for WPA networks. For WPA-PSK, it's either an ASCII passphrase of 8 to 63 characters that is (as specified in the 802.11i standard) hashed to derive the actual key, or the key in form of 64 hexadecimal character. The WPA3-Personal networks use a passphrase of any length for SAE authentication.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS N_("Flags indicating how to handle the \"psk\" property.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS N_("Flags indicating how to handle the \"wep-key0\", \"wep-key1\", \"wep-key2\", and \"wep-key3\" properties.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE N_("Controls the interpretation of WEP keys. Allowed values are NM_WEP_KEY_TYPE_KEY (1), in which case the key is either a 10- or 26-character hexadecimal string, or a 5- or 13-character ASCII password; or NM_WEP_KEY_TYPE_PASSPHRASE (2), in which case the passphrase is provided as a string and will be hashed using the de-facto MD5 method to derive the actual WEP key.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY0 N_("Index 0 WEP key. This is the WEP key used in most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY1 N_("Index 1 WEP key. This WEP index is not used by most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY2 N_("Index 2 WEP key. This WEP index is not used by most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY3 N_("Index 3 WEP key. This WEP index is not used by most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX N_("When static WEP is used (ie, key-mgmt = \"none\") and a non-default WEP key index is used by the AP, put that WEP key index here. Valid values are 0 (default key) through 3. Note that some consumer access points (like the Linksys WRT54G) number the keys 1 - 4.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WPS_METHOD N_("Flags indicating which mode of WPS is to be used if any. There's little point in changing the default setting as NetworkManager will automatically determine whether it's feasible to start WPS enrollment from the Access Point capabilities. WPS can be disabled by setting this property to a value of 1.") #define DESCRIBE_DOC_NM_SETTING_WPAN_CHANNEL N_("IEEE 802.15.4 channel. A positive integer or -1, meaning \"do not set, use whatever the device is already set to\".") #define DESCRIBE_DOC_NM_SETTING_WPAN_MAC_ADDRESS N_("If specified, this connection will only apply to the IEEE 802.15.4 (WPAN) MAC layer device whose permanent MAC address matches.") #define DESCRIBE_DOC_NM_SETTING_WPAN_PAGE N_("IEEE 802.15.4 channel page. A positive integer or -1, meaning \"do not set, use whatever the device is already set to\".") #define DESCRIBE_DOC_NM_SETTING_WPAN_PAN_ID N_("IEEE 802.15.4 Personal Area Network (PAN) identifier.") #define DESCRIBE_DOC_NM_SETTING_WPAN_SHORT_ADDRESS N_("Short IEEE 802.15.4 address to be used within a restricted environment.") +#define DESCRIBE_DOC_NM_SETTING_BOND_PORT_QUEUE_ID N_("The queue ID of this bond port. The maximum value of queue ID is the number of TX queues currently active in device.") +#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DHCP N_("Whether the system hostname can be determined from DHCP on this connection. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).") +#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP N_("Whether the system hostname can be determined from reverse DNS lookup of addresses on this device. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).") +#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT N_("If set to NM_TERNARY_TRUE (1), NetworkManager attempts to get the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this device only when the device has the default route for the given address family (IPv4/IPv6). If set to NM_TERNARY_FALSE (0), the hostname can be set from this device even if it doesn't have the default route. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_FALSE (0).") +#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_PRIORITY N_("The relative priority of this connection to determine the system hostname. A lower numerical value is better (higher priority). A connection with higher priority is considered before connections with lower priority. If the value is zero, it can be overridden by a global value from NetworkManager configuration. If the property doesn't have a value in the global configuration, the value is assumed to be 100. Negative values have the special effect of excluding other connections with a greater numerical priority value; so in presence of at least one negative priority, only connections with the lowest priority value will be used to determine the hostname.") +#define DESCRIBE_DOC_NM_SETTING_OVS_EXTERNAL_IDS_DATA N_("A dictionary of key/value pairs with exernal-ids for OVS.") +#define DESCRIBE_DOC_NM_SETTING_VETH_PEER N_("This property specifies the peer interface name of the veth. This property is mandatory.") diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in index 2a582ad7..3e86c04b 100644 --- a/src/libnmc-setting/settings-docs.h.in +++ b/src/libnmc-setting/settings-docs.h.in @@ -1,47 +1,34 @@ /* Generated file. Do not edit. */ +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTH_RETRIES N_("The number of retries for the authentication. Zero means to try indefinitely; -1 means to use a global default. If the global default is not set, the authentication retries for 3 times before failing the connection. Currently, this only applies to 802-1x authentication.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT N_("Whether or not the connection should be automatically connected by NetworkManager when the resources for the connection are available. TRUE to automatically activate the connection, FALSE to require manual intervention to activate the connection. Autoconnect happens when the circumstances are suitable. That means for example that the device is currently managed and not active. Autoconnect thus never replaces or competes with an already active profile. Note that autoconnect is not implemented for VPN profiles. See \"secondaries\" as an alternative to automatically connect VPN profiles. If multiple profiles are ready to autoconnect on the same device, the one with the better \"connection.autoconnect-priority\" is chosen. If the priorities are equal, then the most recently connected profile is activated. If the profiles were not connected earlier or their \"connection.timestamp\" is identical, the choice is undefined. Depending on \"connection.multi-connect\", a profile can (auto)connect only once at a time or multiple times.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY N_("The autoconnect priority in range -999 to 999. If the connection is set to autoconnect, connections with higher priority will be preferred. The higher number means higher priority. Defaults to 0. Note that this property only matters if there are more than one candidate profile to select for autoconnect. In case of equal priority, the profile used most recently is chosen.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES N_("The number of times a connection should be tried when autoactivating before giving up. Zero means forever, -1 means the global default (4 times if not overridden). Setting this to 1 means to try activation only once before blocking autoconnect. Note that after a timeout, NetworkManager will try to autoconnect again.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES N_("Whether or not slaves of this connection should be automatically brought up when NetworkManager activates this connection. This only has a real effect for master connections. The properties \"autoconnect\", \"autoconnect-priority\" and \"autoconnect-retries\" are unrelated to this setting. The permitted values are: 0: leave slave connections untouched, 1: activate all the slave connections with this connection, -1: default. If -1 (default) is set, global connection.autoconnect-slaves is read to determine the real value. If it is default as well, this fallbacks to 0.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_DNS_OVER_TLS N_("Whether DNSOverTls (dns-over-tls) is enabled for the connection. DNSOverTls is a technology which uses TLS to encrypt dns traffic. The permitted values are: \"yes\" (2) use DNSOverTls and disabled fallback, \"opportunistic\" (1) use DNSOverTls but allow fallback to unencrypted resolution, \"no\" (0) don't ever use DNSOverTls. If unspecified \"default\" depends on the plugin used. Systemd-resolved uses global setting. This feature requires a plugin which supports DNSOverTls. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT N_("If greater than zero, delay success of IP addressing until either the timeout is reached, or an IP gateway replies to a ping.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_ID N_("A human readable unique identifier for the connection, like \"Work Wi-Fi\" or \"T-Mobile 3G\".") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_INTERFACE_NAME N_("The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). For software devices this specifies the name of the created device. For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_LLDP N_("Whether LLDP is enabled for the connection.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_LLMNR N_("Whether Link-Local Multicast Name Resolution (LLMNR) is enabled for the connection. LLMNR is a protocol based on the Domain Name System (DNS) packet format that allows both IPv4 and IPv6 hosts to perform name resolution for hosts on the same local link. The permitted values are: \"yes\" (2) register hostname and resolving for the connection, \"no\" (0) disable LLMNR for the interface, \"resolve\" (1) do not register hostname but allow resolving of LLMNR host names If unspecified, \"default\" ultimately depends on the DNS plugin (which for systemd-resolved currently means \"yes\"). This feature requires a plugin which supports LLMNR. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MASTER N_("Interface name of the master device or UUID of the master connection.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MDNS N_("Whether mDNS is enabled for the connection. The permitted values are: \"yes\" (2) register hostname and resolving for the connection, \"no\" (0) disable mDNS for the interface, \"resolve\" (1) do not register hostname but allow resolving of mDNS host names and \"default\" (-1) to allow lookup of a global default in NetworkManager.conf. If unspecified, \"default\" ultimately depends on the DNS plugin (which for systemd-resolved currently means \"no\"). This feature requires a plugin which supports mDNS. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_METERED N_("Whether the connection is metered. When updating this property on a currently activated connection, the change takes effect immediately.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MPTCP_FLAGS N_("Whether to configure MPTCP endpoints and the address flags. If MPTCP is enabled in NetworkManager, it will configure the addresses of the interface as MPTCP endpoints. Note that IPv4 loopback addresses (127.0.0.0/8), IPv4 link local addresses (169.254.0.0/16), the IPv6 loopback address (::1), IPv6 link local addresses (fe80::/10), IPv6 unique local addresses (ULA, fc00::/7) and IPv6 privacy extension addresses (rfc3041, ipv6.ip6-privacy) will be excluded from being configured as endpoints. If \"disabled\" (0x1), MPTCP handling for the interface is disabled and no endpoints are registered. The flag \"enabled-on-global-iface\" (0x2) means that MPTCP handling is enabled if the interface configures a default route in the main routing table. This choice is per-address family, for example if there is an IPv4 default route 0.0.0.0/0, IPv4 endpoints are configured. The \"enabled\" (0x4) flag means that MPTCP handling is explicitly enabled. This flag can also be implied from the presence of other flags. If MPTCP handling is enabled, then endpoints will be configured with the specified address flags \"signal\" (0x10), \"subflow\" (0x20), \"backup\" (0x40), \"fullmesh\" (0x80). See ip-mptcp(8) manual for additional information about the flags. If the flags are zero, the global connection default from NetworkManager.conf is honored. If still unspecified, the fallback is either \"disabled\" or \"enabled-on-global-iface,subflow\" depending on \"/proc/sys/net/mptcp/enabled\". NetworkManager does not change the MPTCP limits nor enable MPTCP via \"/proc/sys/net/mptcp/enabled\". That is a host configuration which the admin can change via sysctl and ip-mptcp. Strict reverse path filtering (rp_filter) breaks many MPTCP use cases, so when MPTCP handling for IPv4 addresses on the interface is enabled, NetworkManager would loosen the strict reverse path filtering (1) to the loose setting (2).") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MUD_URL N_("If configured, set to a Manufacturer Usage Description (MUD) URL that points to manufacturer-recommended network policies for IoT devices. It is transmitted as a DHCPv4 or DHCPv6 option. The value must be a valid URL starting with \"https://\". The special value \"none\" is allowed to indicate that no MUD URL is used. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the ultimate default is \"none\".") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MULTI_CONNECT N_("Specifies whether the profile can be active multiple times at a particular moment. The value is of type NMConnectionMultiConnect.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_PERMISSIONS N_("An array of strings defining what access a given user has to this connection. If this is NULL or empty, all users are allowed to access this connection; otherwise users are allowed if and only if they are in this list. When this is not empty, the connection can be active only when one of the specified users is logged into an active session. Each entry is of the form \"[type]:[id]:[reserved]\"; for example, \"user:dcbw:blah\". At this time only the \"user\" [type] is allowed. Any other values are ignored and reserved for future use. [id] is the username that this permission refers to, which may not contain the \":\" character. Any [reserved] information present must be ignored and is reserved for future use. All of [type], [id], and [reserved] must be valid UTF-8.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_READ_ONLY N_("FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_SECONDARIES N_("List of connection UUIDs that should be activated when the base connection itself is activated. Currently, only VPN connections are supported.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_SLAVE_TYPE N_("Setting name of the device type of this slave's master connection (eg, \"bond\"), or NULL if this connection is not a slave.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. The '$' character is treated special to perform dynamic substitutions at runtime. Currently, supported are \"${CONNECTION}\", \"${DEVICE}\", \"${MAC}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that \"${DEVICE}\" corresponds to the interface name of the device and \"${MAC}\" is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}-${BOOT}-${DEVICE}\" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to \"${CONNECTION}\" and uses a unique, fixed ID for the connection.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_TIMESTAMP N_("The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved).") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_TYPE N_("Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, \"802-3-ethernet\" or \"802-11-wireless\" or \"bluetooth\", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, \"vpn\" or \"bridge\", etc).") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_UUID N_("A universally unique identifier for the connection, for example generated with libuuid. It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network. For example, it should not be changed when the \"id\" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or \"type\" property changes. The UUID must be in the format \"2815492f-7e56-435e-b2e9-246bd7cdc664\" (ie, contains only hexadecimal characters and \"-\").") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_WAIT_ACTIVATION_DELAY N_("Time in milliseconds to wait for connection to be considered activated. The wait will start after the pre-up dispatcher event. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT N_("Timeout in milliseconds to wait for device at startup. During boot, devices may take a while to be detected by the driver. This property will cause to delay NetworkManager-wait-online.service and nm-online to give the device a chance to appear. This works by waiting for the given timeout until a compatible device for the profile is available and managed. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time.") +#define DESCRIBE_DOC_NM_SETTING_CONNECTION_ZONE N_("The trust level of a the connection. Free form case-insensitive string (for example \"Home\", \"Work\", \"Public\"). NULL or unspecified zone means the connection will be placed in the default zone as defined by the firewall. When updating this property on a currently activated connection, the change takes effect immediately.") #define DESCRIBE_DOC_NM_SETTING_6LOWPAN_PARENT N_("If given, specifies the parent interface name or parent connection UUID from which this 6LowPAN interface should be created.") -#define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_CHANNEL N_("Channel on which the mesh network to join is located.") -#define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS N_("Anycast DHCP MAC address used when requesting an IP address via DHCP. The specific anycast address used determines which DHCP server class answers the request. This is currently only implemented by dhclient DHCP plugin.") -#define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_SSID N_("SSID of the mesh network to join.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_AP_ISOLATION N_("Configures AP isolation, which prevents communication between wireless devices connected to this AP. This property can be set to a value different from NM_TERNARY_DEFAULT (-1) only when the interface is configured in AP mode. If set to NM_TERNARY_TRUE (1), devices are not able to communicate with each other. This increases security because it protects devices against attacks from other clients in the network. At the same time, it prevents devices to access resources on the same wireless networks as file shares, printers, etc. If set to NM_TERNARY_FALSE (0), devices can talk to each other. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_FALSE (0).") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_BAND N_("802.11 frequency band of the network. One of \"a\" for 5GHz 802.11a or \"bg\" for 2.4GHz 802.11. This will lock associations to the Wi-Fi network to the specific band, i.e. if \"a\" is specified, the device will not associate with the same network in the 2.4GHz band even if the network's settings are compatible. This setting depends on specific driver capability and may not work with all drivers.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_BSSID N_("If specified, directs the device to only associate with the given access point. This capability is highly driver dependent and not supported by all devices. Note: this property does not control the BSSID used when creating an Ad-Hoc network and is unlikely to in the future.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_CHANNEL N_("Wireless channel to use for the Wi-Fi connection. The device will only join (or create for Ad-Hoc networks) a Wi-Fi network on the specified channel. Because channel numbers overlap between bands, this property also requires the \"band\" property to be set.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS N_("If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. Beside explicitly specifying a MAC address, the special values \"preserve\", \"permanent\", \"random\" and \"stable\" are supported. \"preserve\" means not to touch the MAC address on activation. \"permanent\" means to use the permanent hardware address of the device. \"random\" creates a random MAC address on each connect. \"stable\" creates a hashed MAC address based on connection.stable-id and a machine dependent key. If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to \"preserve\" (older versions of NetworkManager may use a different default value). On D-Bus, this field is expressed as \"assigned-mac-address\" or the deprecated \"cloned-mac-address\".") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK N_("With \"cloned-mac-address\" setting \"random\" or \"stable\", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting \"FE:FF:FF:00:00:00\" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the \"random\" or \"stable\" algorithm. If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of \"FE:FF:FF:00:00:00 68:F7:28:00:00:00\" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of \"02:00:00:00:00:00 00:00:00:00:00:00\" will create a fully scrambled globally-administered, burned-in MAC address. If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, \"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00\" will create a fully scrambled MAC address, randomly locally or globally administered.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_HIDDEN N_("If TRUE, indicates that the network is a non-broadcasting network that hides its SSID. This works both in infrastructure and AP mode. In infrastructure mode, various workarounds are used for a more reliable discovery of hidden networks, such as probe-scanning the SSID. However, these workarounds expose inherent insecurities with hidden SSID networks, and thus hidden SSID networks should be used with caution. In AP mode, the created network does not broadcast its SSID. Note that marking the network as hidden may be a privacy issue for you (in infrastructure mode) or client stations (in AP mode), as the explicit probe-scans are distinctly recognizable on the air.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS N_("If specified, this connection will only apply to the Wi-Fi device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST N_("A list of permanent MAC addresses of Wi-Fi devices to which this connection should never apply. Each MAC address should be given in the standard hex-digits-and-colons notation (eg \"00:11:22:33:44:55\").") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION N_("One of NM_SETTING_MAC_RANDOMIZATION_DEFAULT (0) (never randomize unless the user has set a global default to randomize and the supplicant supports randomization), NM_SETTING_MAC_RANDOMIZATION_NEVER (1) (never randomize the MAC address), or NM_SETTING_MAC_RANDOMIZATION_ALWAYS (2) (always randomize the MAC address). This property is deprecated for 'cloned-mac-address'. Deprecated: 1") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MODE N_("Wi-Fi network mode; one of \"infrastructure\", \"mesh\", \"adhoc\" or \"ap\". If blank, infrastructure is assumed.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_POWERSAVE N_("One of NM_SETTING_WIRELESS_POWERSAVE_DISABLE (2) (disable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_ENABLE (3) (enable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_IGNORE (1) (don't touch currently configure setting) or NM_SETTING_WIRELESS_POWERSAVE_DEFAULT (0) (use the globally configured value). All other values are reserved.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_RATE N_("If non-zero, directs the device to only use the specified bitrate for communication with the access point. Units are in Kb/s, ie 5500 = 5.5 Mbit/s. This property is highly driver dependent and not all devices support setting a static bitrate.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SEEN_BSSIDS N_("A list of BSSIDs (each BSSID formatted as a MAC address like \"00:11:22:33:44:55\") that have been detected as part of the Wi-Fi network. NetworkManager internally tracks previously seen BSSIDs. The property is only meant for reading and reflects the BSSID list of NetworkManager. The changes you make to this property will not be preserved.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SSID N_("SSID of the Wi-Fi network. Must be specified.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_TX_POWER N_("If non-zero, directs the device to use the specified transmit power. Units are dBm. This property is highly driver dependent and not all devices support setting a static transmit power.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_WAKE_ON_WLAN N_("The NMSettingWirelessWakeOnWLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY (0x2), NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT (0x4), NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC (0x8), NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE (0x10), NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST (0x20), NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE (0x40), NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE (0x80), NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP (0x100) or the special values NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager).") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_AUTH_ALG N_("When WEP is used (ie, key-mgmt = \"none\" or \"ieee8021x\") indicate the 802.11 authentication algorithm required by the AP here. One of \"open\" for Open System, \"shared\" for Shared Key, or \"leap\" for Cisco LEAP. When using Cisco LEAP (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\") the \"leap-username\" and \"leap-password\" properties must be specified.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_FILS N_("Indicates whether Fast Initial Link Setup (802.11ai) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE (1) (disable FILS), NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL (2) (enable FILS if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED (3) (enable FILS and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) and no global default is set, FILS will be optionally enabled.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_GROUP N_("A list of group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of \"wep40\", \"wep104\", \"tkip\", or \"ccmp\".") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_KEY_MGMT N_("Key management used for the connection. One of \"none\" (WEP or no password protection), \"ieee8021x\" (Dynamic WEP), \"owe\" (Opportunistic Wireless Encryption), \"wpa-psk\" (WPA2 + WPA3 personal), \"sae\" (WPA3 personal only), \"wpa-eap\" (WPA2 + WPA3 enterprise) or \"wpa-eap-suite-b-192\" (WPA3 enterprise only). This property must be set for any Wi-Fi connection that uses security.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD N_("The login password for legacy LEAP connections (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\").") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS N_("Flags indicating how to handle the \"leap-password\" property.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME N_("The login username for legacy LEAP connections (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\").") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PAIRWISE N_("A list of pairwise encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of \"tkip\" or \"ccmp\".") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PMF N_("Indicates whether Protected Management Frames (802.11w) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE (1) (disable PMF), NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL (2) (enable PMF if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED (3) (enable PMF and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) and no global default is set, PMF will be optionally enabled.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PROTO N_("List of strings specifying the allowed WPA protocol versions to use. Each element may be one \"wpa\" (allow WPA) or \"rsn\" (allow WPA2/RSN). If not specified, both WPA and RSN connections are allowed.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PSK N_("Pre-Shared-Key for WPA networks. For WPA-PSK, it's either an ASCII passphrase of 8 to 63 characters that is (as specified in the 802.11i standard) hashed to derive the actual key, or the key in form of 64 hexadecimal character. The WPA3-Personal networks use a passphrase of any length for SAE authentication.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS N_("Flags indicating how to handle the \"psk\" property.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS N_("Flags indicating how to handle the \"wep-key0\", \"wep-key1\", \"wep-key2\", and \"wep-key3\" properties.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE N_("Controls the interpretation of WEP keys. Allowed values are NM_WEP_KEY_TYPE_KEY (1), in which case the key is either a 10- or 26-character hexadecimal string, or a 5- or 13-character ASCII password; or NM_WEP_KEY_TYPE_PASSPHRASE (2), in which case the passphrase is provided as a string and will be hashed using the de-facto MD5 method to derive the actual WEP key.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY0 N_("Index 0 WEP key. This is the WEP key used in most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY1 N_("Index 1 WEP key. This WEP index is not used by most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY2 N_("Index 2 WEP key. This WEP index is not used by most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY3 N_("Index 3 WEP key. This WEP index is not used by most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX N_("When static WEP is used (ie, key-mgmt = \"none\") and a non-default WEP key index is used by the AP, put that WEP key index here. Valid values are 0 (default key) through 3. Note that some consumer access points (like the Linksys WRT54G) number the keys 1 - 4.") -#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WPS_METHOD N_("Flags indicating which mode of WPS is to be used if any. There's little point in changing the default setting as NetworkManager will automatically determine whether it's feasible to start WPS enrollment from the Access Point capabilities. WPS can be disabled by setting this property to a value of 1.") #define DESCRIBE_DOC_NM_SETTING_802_1X_ALTSUBJECT_MATCHES N_("List of strings to be matched against the altSubjectName of the certificate presented by the authentication server. If the list is empty, no verification of the server certificate's altSubjectName is performed.") #define DESCRIBE_DOC_NM_SETTING_802_1X_ANONYMOUS_IDENTITY N_("Anonymous identity string for EAP authentication methods. Used as the unencrypted identity with EAP types that support different tunneled identity like EAP-TTLS.") #define DESCRIBE_DOC_NM_SETTING_802_1X_AUTH_TIMEOUT N_("A timeout for the authentication. Zero means the global default; if the global default is not set, the authentication timeout is 25 seconds.") @@ -89,21 +76,6 @@ #define DESCRIBE_DOC_NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS N_("Flags indicating how to handle the \"private-key-password\" property.") #define DESCRIBE_DOC_NM_SETTING_802_1X_SUBJECT_MATCH N_("Substring to be matched against the subject of the certificate presented by the authentication server. When unset, no verification of the authentication server certificate's subject is performed. This property provides little security, if any, and its use is deprecated in favor of NMSetting8021x:domain-suffix-match.") #define DESCRIBE_DOC_NM_SETTING_802_1X_SYSTEM_CA_CERTS N_("When TRUE, overrides the \"ca-path\" and \"phase2-ca-path\" properties using the system CA directory specified at configure time with the --system-ca-path switch. The certificates in this directory are added to the verification chain in addition to any certificates specified by the \"ca-cert\" and \"phase2-ca-cert\" properties. If the path provided with --system-ca-path is rather a file name (bundle of trusted CA certificates), it overrides \"ca-cert\" and \"phase2-ca-cert\" properties instead (sets ca_cert/ca_cert2 options for wpa_supplicant).") -#define DESCRIBE_DOC_NM_SETTING_WIRED_ACCEPT_ALL_MAC_ADDRESSES N_("When TRUE, setup the interface to accept packets for all MAC addresses. This is enabling the kernel interface flag IFF_PROMISC. When FALSE, the interface will only accept the packets with the interface destination mac address or broadcast.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_AUTO_NEGOTIATE N_("When TRUE, enforce auto-negotiation of speed and duplex mode. If \"speed\" and \"duplex\" properties are both specified, only that single mode will be advertised and accepted during the link auto-negotiation process: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. When FALSE, \"speed\" and \"duplex\" properties should be both set or link configuration will be skipped.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_CLONED_MAC_ADDRESS N_("If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. Beside explicitly specifying a MAC address, the special values \"preserve\", \"permanent\", \"random\" and \"stable\" are supported. \"preserve\" means not to touch the MAC address on activation. \"permanent\" means to use the permanent hardware address if the device has one (otherwise this is treated as \"preserve\"). \"random\" creates a random MAC address on each connect. \"stable\" creates a hashed MAC address based on connection.stable-id and a machine dependent key. If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to \"preserve\" (older versions of NetworkManager may use a different default value). On D-Bus, this field is expressed as \"assigned-mac-address\" or the deprecated \"cloned-mac-address\".") -#define DESCRIBE_DOC_NM_SETTING_WIRED_DUPLEX N_("When a value is set, either \"half\" or \"full\", configures the device to use the specified duplex mode. If \"auto-negotiate\" is \"yes\" the specified duplex mode will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. If the value is unset (the default), the link configuration will be either skipped (if \"auto-negotiate\" is \"no\", the default) or will be auto-negotiated (if \"auto-negotiate\" is \"yes\") and the local device will advertise all the supported duplex modes. Must be set together with the \"speed\" property if specified. Before specifying a duplex mode be sure your device supports it.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK N_("With \"cloned-mac-address\" setting \"random\" or \"stable\", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting \"FE:FF:FF:00:00:00\" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the \"random\" or \"stable\" algorithm. If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of \"FE:FF:FF:00:00:00 68:F7:28:00:00:00\" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of \"02:00:00:00:00:00 00:00:00:00:00:00\" will create a fully scrambled globally-administered, burned-in MAC address. If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, \"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00\" will create a fully scrambled MAC address, randomly locally or globally administered.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_MAC_ADDRESS N_("If specified, this connection will only apply to the Ethernet device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).") -#define DESCRIBE_DOC_NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST N_("If specified, this connection will never apply to the Ethernet device whose permanent MAC address matches an address in the list. Each MAC address is in the standard hex-digits-and-colons notation (00:11:22:33:44:55).") -#define DESCRIBE_DOC_NM_SETTING_WIRED_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_PORT N_("Specific port type to use if the device supports multiple attachment methods. One of \"tp\" (Twisted Pair), \"aui\" (Attachment Unit Interface), \"bnc\" (Thin Ethernet) or \"mii\" (Media Independent Interface). If the device supports only one port type, this setting is ignored.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_S390_NETTYPE N_("s390 network device type; one of \"qeth\", \"lcs\", or \"ctc\", representing the different types of virtual network devices available on s390 systems.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_S390_OPTIONS N_("Dictionary of key/value pairs of s390-specific device options. Both keys and values must be strings. Allowed keys include \"portno\", \"layer2\", \"portname\", \"protocol\", among others. Key names must contain only alphanumeric characters (ie, [a-zA-Z0-9]). Currently, NetworkManager itself does nothing with this information. However, s390utils ships a udev rule which parses this information and applies it to the interface.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_S390_SUBCHANNELS N_("Identifies specific subchannels that this network device uses for communication with z/VM or s390 host. Like the \"mac-address\" property for non-z/VM devices, this property can be used to ensure this connection only applies to the network device that uses these subchannels. The list should contain exactly 3 strings, and each string may only be composed of hexadecimal characters and the period (.) character.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_SPEED N_("When a value greater than 0 is set, configures the device to use the specified speed. If \"auto-negotiate\" is \"yes\" the specified speed will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabit speeds, as in this case link negotiation is mandatory. If the value is unset (0, the default), the link configuration will be either skipped (if \"auto-negotiate\" is \"no\", the default) or will be auto-negotiated (if \"auto-negotiate\" is \"yes\") and the local device will advertise all the supported speeds. In Mbit/s, ie 100 == 100Mbit/s. Must be set together with the \"duplex\" property when non-zero. Before specifying a speed value be sure your device supports it.") -#define DESCRIBE_DOC_NM_SETTING_WIRED_WAKE_ON_LAN N_("The NMSettingWiredWakeOnLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRED_WAKE_ON_LAN_PHY (0x2), NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST (0x4), NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST (0x8), NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST (0x10), NM_SETTING_WIRED_WAKE_ON_LAN_ARP (0x20), NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC (0x40) or the special values NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager).") -#define DESCRIBE_DOC_NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD N_("If specified, the password used with magic-packet-based Wake-on-LAN, represented as an Ethernet MAC address. If NULL, no password will be required.") #define DESCRIBE_DOC_NM_SETTING_ADSL_ENCAPSULATION N_("Encapsulation of ADSL connection. Can be \"vcmux\" or \"llc\".") #define DESCRIBE_DOC_NM_SETTING_ADSL_PASSWORD N_("Password used to authenticate with the ADSL service.") #define DESCRIBE_DOC_NM_SETTING_ADSL_PASSWORD_FLAGS N_("Flags indicating how to handle the \"password\" property.") @@ -114,7 +86,6 @@ #define DESCRIBE_DOC_NM_SETTING_BLUETOOTH_BDADDR N_("The Bluetooth address of the device.") #define DESCRIBE_DOC_NM_SETTING_BLUETOOTH_TYPE N_("Either \"dun\" for Dial-Up Networking connections or \"panu\" for Personal Area Networking connections to devices supporting the NAP profile.") #define DESCRIBE_DOC_NM_SETTING_BOND_OPTIONS N_("Dictionary of key/value pairs of bonding options. Both keys and values must be strings. Option names must contain only alphanumeric characters (ie, [a-zA-Z0-9]).") -#define DESCRIBE_DOC_NM_SETTING_BOND_PORT_QUEUE_ID N_("The queue ID of this bond port. The maximum value of queue ID is the number of TX queues currently active in device.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_AGEING_TIME N_("The Ethernet MAC address aging time, in seconds.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_FORWARD_DELAY N_("The Spanning Tree Protocol (STP) forwarding delay, in seconds.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_GROUP_ADDRESS N_("If specified, The MAC address of the multicast group this bridge uses for STP. The address must be a link-local address in standard Ethernet MAC address format, ie an address of the form 01:80:C2:00:00:0X, with X in [0, 4..F]. If not specified the default value is 01:80:C2:00:00:00.") @@ -151,32 +122,6 @@ #define DESCRIBE_DOC_NM_SETTING_CDMA_PASSWORD N_("The password used to authenticate with the network, if required. Many providers do not require a password, or accept any password. But if a password is required, it is specified here.") #define DESCRIBE_DOC_NM_SETTING_CDMA_PASSWORD_FLAGS N_("Flags indicating how to handle the \"password\" property.") #define DESCRIBE_DOC_NM_SETTING_CDMA_USERNAME N_("The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTH_RETRIES N_("The number of retries for the authentication. Zero means to try indefinitely; -1 means to use a global default. If the global default is not set, the authentication retries for 3 times before failing the connection. Currently, this only applies to 802-1x authentication.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT N_("Whether or not the connection should be automatically connected by NetworkManager when the resources for the connection are available. TRUE to automatically activate the connection, FALSE to require manual intervention to activate the connection. Autoconnect happens when the circumstances are suitable. That means for example that the device is currently managed and not active. Autoconnect thus never replaces or competes with an already active profile. Note that autoconnect is not implemented for VPN profiles. See \"secondaries\" as an alternative to automatically connect VPN profiles. If multiple profiles are ready to autoconnect on the same device, the one with the better \"connection.autoconnect-priority\" is chosen. If the priorities are equal, then the most recently connected profile is activated. If the profiles were not connected earlier or their \"connection.timestamp\" is identical, the choice is undefined. Depending on \"connection.multi-connect\", a profile can (auto)connect only once at a time or multiple times.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY N_("The autoconnect priority in range -999 to 999. If the connection is set to autoconnect, connections with higher priority will be preferred. The higher number means higher priority. Defaults to 0. Note that this property only matters if there are more than one candidate profile to select for autoconnect. In case of equal priority, the profile used most recently is chosen.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES N_("The number of times a connection should be tried when autoactivating before giving up. Zero means forever, -1 means the global default (4 times if not overridden). Setting this to 1 means to try activation only once before blocking autoconnect. Note that after a timeout, NetworkManager will try to autoconnect again.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES N_("Whether or not slaves of this connection should be automatically brought up when NetworkManager activates this connection. This only has a real effect for master connections. The properties \"autoconnect\", \"autoconnect-priority\" and \"autoconnect-retries\" are unrelated to this setting. The permitted values are: 0: leave slave connections untouched, 1: activate all the slave connections with this connection, -1: default. If -1 (default) is set, global connection.autoconnect-slaves is read to determine the real value. If it is default as well, this fallbacks to 0.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_DNS_OVER_TLS N_("Whether DNSOverTls (dns-over-tls) is enabled for the connection. DNSOverTls is a technology which uses TLS to encrypt dns traffic. The permitted values are: \"yes\" (2) use DNSOverTls and disabled fallback, \"opportunistic\" (1) use DNSOverTls but allow fallback to unencrypted resolution, \"no\" (0) don't ever use DNSOverTls. If unspecified \"default\" depends on the plugin used. Systemd-resolved uses global setting. This feature requires a plugin which supports DNSOverTls. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT N_("If greater than zero, delay success of IP addressing until either the timeout is reached, or an IP gateway replies to a ping.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_ID N_("A human readable unique identifier for the connection, like \"Work Wi-Fi\" or \"T-Mobile 3G\".") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_INTERFACE_NAME N_("The name of the network interface this connection is bound to. If not set, then the connection can be attached to any interface of the appropriate type (subject to restrictions imposed by other settings). For software devices this specifies the name of the created device. For connection types where interface names cannot easily be made persistent (e.g. mobile broadband or USB Ethernet), this property should not be used. Setting this property restricts the interfaces a connection can be used with, and if interface names change or are reordered the connection may be applied to the wrong interface.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_LLDP N_("Whether LLDP is enabled for the connection.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_LLMNR N_("Whether Link-Local Multicast Name Resolution (LLMNR) is enabled for the connection. LLMNR is a protocol based on the Domain Name System (DNS) packet format that allows both IPv4 and IPv6 hosts to perform name resolution for hosts on the same local link. The permitted values are: \"yes\" (2) register hostname and resolving for the connection, \"no\" (0) disable LLMNR for the interface, \"resolve\" (1) do not register hostname but allow resolving of LLMNR host names If unspecified, \"default\" ultimately depends on the DNS plugin (which for systemd-resolved currently means \"yes\"). This feature requires a plugin which supports LLMNR. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MASTER N_("Interface name of the master device or UUID of the master connection.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MDNS N_("Whether mDNS is enabled for the connection. The permitted values are: \"yes\" (2) register hostname and resolving for the connection, \"no\" (0) disable mDNS for the interface, \"resolve\" (1) do not register hostname but allow resolving of mDNS host names and \"default\" (-1) to allow lookup of a global default in NetworkManager.conf. If unspecified, \"default\" ultimately depends on the DNS plugin (which for systemd-resolved currently means \"no\"). This feature requires a plugin which supports mDNS. Otherwise, the setting has no effect. One such plugin is dns-systemd-resolved.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_METERED N_("Whether the connection is metered. When updating this property on a currently activated connection, the change takes effect immediately.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MUD_URL N_("If configured, set to a Manufacturer Usage Description (MUD) URL that points to manufacturer-recommended network policies for IoT devices. It is transmitted as a DHCPv4 or DHCPv6 option. The value must be a valid URL starting with \"https://\". The special value \"none\" is allowed to indicate that no MUD URL is used. If the per-profile value is unspecified (the default), a global connection default gets consulted. If still unspecified, the ultimate default is \"none\".") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_MULTI_CONNECT N_("Specifies whether the profile can be active multiple times at a particular moment. The value is of type NMConnectionMultiConnect.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_PERMISSIONS N_("An array of strings defining what access a given user has to this connection. If this is NULL or empty, all users are allowed to access this connection; otherwise users are allowed if and only if they are in this list. When this is not empty, the connection can be active only when one of the specified users is logged into an active session. Each entry is of the form \"[type]:[id]:[reserved]\"; for example, \"user:dcbw:blah\". At this time only the \"user\" [type] is allowed. Any other values are ignored and reserved for future use. [id] is the username that this permission refers to, which may not contain the \":\" character. Any [reserved] information present must be ignored and is reserved for future use. All of [type], [id], and [reserved] must be valid UTF-8.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_READ_ONLY N_("FALSE if the connection can be modified using the provided settings service's D-Bus interface with the right privileges, or TRUE if the connection is read-only and cannot be modified.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_SECONDARIES N_("List of connection UUIDs that should be activated when the base connection itself is activated. Currently, only VPN connections are supported.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_SLAVE_TYPE N_("Setting name of the device type of this slave's master connection (eg, \"bond\"), or NULL if this connection is not a slave.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_STABLE_ID N_("This represents the identity of the connection used for various purposes. It allows to configure multiple profiles to share the identity. Also, the stable-id can contain placeholders that are substituted dynamically and deterministically depending on the context. The stable-id is used for generating IPv6 stable private addresses with ipv6.addr-gen-mode=stable-privacy. It is also used to seed the generated cloned MAC address for ethernet.cloned-mac-address=stable and wifi.cloned-mac-address=stable. It is also used as DHCP client identifier with ipv4.dhcp-client-id=stable and to derive the DHCP DUID with ipv6.dhcp-duid=stable-[llt,ll,uuid]. Note that depending on the context where it is used, other parameters are also seeded into the generation algorithm. For example, a per-host key is commonly also included, so that different systems end up generating different IDs. Or with ipv6.addr-gen-mode=stable-privacy, also the device's name is included, so that different interfaces yield different addresses. The per-host key is the identity of your machine and stored in /var/lib/NetworkManager/secret_key. See NetworkManager(8) manual about the secret-key and the host identity. The '$' character is treated special to perform dynamic substitutions at runtime. Currently, supported are \"${CONNECTION}\", \"${DEVICE}\", \"${MAC}\", \"${BOOT}\", \"${RANDOM}\". These effectively create unique IDs per-connection, per-device, per-boot, or every time. Note that \"${DEVICE}\" corresponds to the interface name of the device and \"${MAC}\" is the permanent MAC address of the device. Any unrecognized patterns following '$' are treated verbatim, however are reserved for future use. You are thus advised to avoid '$' or escape it as \"$$\". For example, set it to \"${CONNECTION}-${BOOT}-${DEVICE}\" to create a unique id for this connection that changes with every reboot and differs depending on the interface where the profile activates. If the value is unset, a global connection default is consulted. If the value is still unset, the default is similar to \"${CONNECTION}\" and uses a unique, fixed ID for the connection.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_TIMESTAMP N_("The time, in seconds since the Unix Epoch, that the connection was last _successfully_ fully activated. NetworkManager updates the connection timestamp periodically when the connection is active to ensure that an active connection has the latest timestamp. The property is only meant for reading (changes to this property will not be preserved).") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_TYPE N_("Base type of the connection. For hardware-dependent connections, should contain the setting name of the hardware-type specific setting (ie, \"802-3-ethernet\" or \"802-11-wireless\" or \"bluetooth\", etc), and for non-hardware dependent connections like VPN or otherwise, should contain the setting name of that setting type (ie, \"vpn\" or \"bridge\", etc).") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_UUID N_("A universally unique identifier for the connection, for example generated with libuuid. It should be assigned when the connection is created, and never changed as long as the connection still applies to the same network. For example, it should not be changed when the \"id\" property or NMSettingIP4Config changes, but might need to be re-created when the Wi-Fi SSID, mobile broadband network provider, or \"type\" property changes. The UUID must be in the format \"2815492f-7e56-435e-b2e9-246bd7cdc664\" (ie, contains only hexadecimal characters and \"-\").") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT N_("Timeout in milliseconds to wait for device at startup. During boot, devices may take a while to be detected by the driver. This property will cause to delay NetworkManager-wait-online.service and nm-online to give the device a chance to appear. This works by waiting for the given timeout until a compatible device for the profile is available and managed. The value 0 means no wait time. The default value is -1, which currently has the same meaning as no wait time.") -#define DESCRIBE_DOC_NM_SETTING_CONNECTION_ZONE N_("The trust level of a the connection. Free form case-insensitive string (for example \"Home\", \"Work\", \"Public\"). NULL or unspecified zone means the connection will be placed in the default zone as defined by the firewall. When updating this property on a currently activated connection, the change takes effect immediately.") #define DESCRIBE_DOC_NM_SETTING_DCB_APP_FCOE_FLAGS N_("Specifies the NMSettingDcbFlags for the DCB FCoE application. Flags may be any combination of NM_SETTING_DCB_FLAG_ENABLE (0x1), NM_SETTING_DCB_FLAG_ADVERTISE (0x2), and NM_SETTING_DCB_FLAG_WILLING (0x4).") #define DESCRIBE_DOC_NM_SETTING_DCB_APP_FCOE_MODE N_("The FCoE controller mode; either \"fabric\" or \"vn2vn\". Since 1.34, NULL is the default and means \"fabric\". Before 1.34, NULL was rejected as invalid and the default was \"fabric\".") #define DESCRIBE_DOC_NM_SETTING_DCB_APP_FCOE_PRIORITY N_("The highest User Priority (0 - 7) which FCoE frames should use, or -1 for default priority. Only used when the \"app-fcoe-flags\" property includes the NM_SETTING_DCB_FLAG_ENABLE (0x1) flag.") @@ -206,28 +151,11 @@ #define DESCRIBE_DOC_NM_SETTING_GSM_SIM_ID N_("The SIM card unique identifier (as given by the WWAN management service) which this connection applies to. If given, the connection will apply to any device also allowed by \"device-id\" which contains a SIM card matching the given identifier.") #define DESCRIBE_DOC_NM_SETTING_GSM_SIM_OPERATOR_ID N_("A MCC/MNC string like \"310260\" or \"21601\" identifying the specific mobile network operator which this connection applies to. If given, the connection will apply to any device also allowed by \"device-id\" and \"sim-id\" which contains a SIM card provisioned by the given operator.") #define DESCRIBE_DOC_NM_SETTING_GSM_USERNAME N_("The username used to authenticate with the network, if required. Many providers do not require a username, or accept any username. But if a username is required, it is specified here.") -#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DHCP N_("Whether the system hostname can be determined from DHCP on this connection. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).") -#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP N_("Whether the system hostname can be determined from reverse DNS lookup of addresses on this device. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).") -#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT N_("If set to NM_TERNARY_TRUE (1), NetworkManager attempts to get the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this device only when the device has the default route for the given address family (IPv4/IPv6). If set to NM_TERNARY_FALSE (0), the hostname can be set from this device even if it doesn't have the default route. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_FALSE (0).") -#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_PRIORITY N_("The relative priority of this connection to determine the system hostname. A lower numerical value is better (higher priority). A connection with higher priority is considered before connections with lower priority. If the value is zero, it can be overridden by a global value from NetworkManager configuration. If the property doesn't have a value in the global configuration, the value is assumed to be 100. Negative values have the special effect of excluding other connections with a greater numerical priority value; so in presence of at least one negative priority, only connections with the lowest priority value will be used to determine the hostname.") #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_MAC_ADDRESS N_("If specified, this connection will only apply to the IPoIB device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).") #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames.") #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_P_KEY N_("The InfiniBand P_Key to use for this device. A value of -1 means to use the default P_Key (aka \"the P_Key at index 0\"). Otherwise, it is a 16-bit unsigned integer, whose high bit is set if it is a \"full membership\" P_Key.") #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_PARENT N_("The interface name of the parent device of this device. Normally NULL, but if the \"p_key\" property is set, then you must specify the base device by setting either this property or \"mac-address\".") #define DESCRIBE_DOC_NM_SETTING_INFINIBAND_TRANSPORT_MODE N_("The IP-over-InfiniBand transport mode. Either \"datagram\" or \"connected\".") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT N_("How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLAGS N_("Tunnel flags. Currently, the following values are supported: NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS (0x2), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL (0x4), NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV (0x8), NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY (0x10), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK (0x20). They are valid only for IPv6 tunnels.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLOW_LABEL N_("The flow label to assign to tunnel packets. This property applies only to IPv6 tunnels.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_INPUT_KEY N_("The key used for tunnel input packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_LOCAL N_("The local endpoint of the tunnel; the value can be empty, otherwise it must contain an IPv4 or IPv6 address.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MODE N_("The tunneling mode, for example NM_IP_TUNNEL_MODE_IPIP (1) or NM_IP_TUNNEL_MODE_GRE (2).") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_OUTPUT_KEY N_("The key used for tunnel output packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_PARENT N_("If given, specifies the parent interface name or parent connection UUID the new device will be bound to so that tunneled packets will only be routed via that interface.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY N_("Whether to enable Path MTU Discovery on this tunnel.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_REMOTE N_("The remote endpoint of the tunnel; the value must contain an IPv4 or IPv6 address.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TOS N_("The type of service (IPv4) or traffic class (IPv6) field to be set on tunneled packets.") -#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TTL N_("The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ADDRESSES N_("A list of IPv4 addresses and their prefix length. Multiple addresses can be separated by comma. For example \"192.168.1.5/24, 10.1.0.5/24\". The addresses are listed in decreasing priority, meaning the first address will be the primary address.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID N_("A string sent to the DHCP server to identify the local machine which the DHCP server may use to customize the DHCP lease and options. When the property is a hex string ('aa:bb:cc') it is interpreted as a binary client ID, in which case the first byte is assumed to be the 'type' field as per RFC 2132 section 9.14 and the remaining bytes may be an hardware address (e.g. '01:xx:xx:xx:xx:xx:xx' where 1 is the Ethernet ARP type and the rest is a MAC address). If the property is not a hex string it is considered as a non-hardware-address client ID and the 'type' field is set to 0. The special values \"mac\" and \"perm-mac\" are supported, which use the current or permanent MAC address of the device to generate a client identifier with type ethernet (01). Currently, these options only work for ethernet type of links. The special value \"ipv6-duid\" uses the DUID from \"ipv6.dhcp-duid\" property as an RFC4361-compliant client identifier. As IAID it uses \"ipv4.dhcp-iaid\" and falls back to \"ipv6.dhcp-iaid\" if unset. The special value \"duid\" generates a RFC4361-compliant client identifier based on \"ipv4.dhcp-iaid\" and uses a DUID generated by hashing /etc/machine-id. The special value \"stable\" is supported to generate a type 0 client identifier based on the stable-id (see connection.stable-id) and a per-host key. If you set the stable-id, you may want to include the \"${DEVICE}\" or \"${MAC}\" specifier to get a per-device key. If unset, a globally configured default is used. If still unset, the default depends on the DHCP plugin.") @@ -242,10 +170,11 @@ #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS N_("Array of IP addresses of DNS servers.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are \"attempts\", \"debug\", \"edns0\", \"inet6\", \"ip6-bytestring\", \"ip6-dotint\", \"ndots\", \"no-check-names\", \"no-ip6-dotint\", \"no-reload\", \"no-tld-query\", \"rotate\", \"single-request\", \"single-request-reopen\", \"timeout\", \"trust-ad\", \"use-vc\". The \"trust-ad\" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have \"trust-ad\" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then \"edns0\" and \"trust-ad\" are automatically added.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the \"rotate\" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured.") -#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting.") +#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH N_("List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting \"ignore-auto-dns\". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15).") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set. The gateway's main purpose is to control the next hop of the standard default route on the device. Hence, the gateway property conflicts with \"never-default\" and will be automatically dropped if the IP configuration is set to never-default. As an alternative to set the gateway, configure a static default route with /0 as prefix length.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.") +#define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_LINK_LOCAL N_("Enable and disable the IPv4 link-local configuration independently of the ipv4.method configuration. This allows a link-local address (169.254.x.y/16) to be obtained in addition to other addresses, such as those manually configured or obtained from a DHCP server. When set to \"auto\", the value is dependent on \"ipv4.method\". When set to \"default\", it honors the global connection default, before falling back to \"auto\". Note that if \"ipv4.method\" is \"disabled\", then link local addressing is always disabled too. The default is \"default\". Since 1.40") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_MAY_FAIL N_("If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out. Note that at least one IP configuration must succeed or overall network configuration will still fail. For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_METHOD N_("IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support \"disabled\", \"auto\", \"manual\", and \"link-local\". See the subclass-specific documentation for other values. In general, for the \"auto\" method, properties such as \"dns\" and \"routes\" specify information that is added on to the information returned from automatic configuration. The \"ignore-auto-routes\" and \"ignore-auto-dns\" properties modify this behavior. For methods that imply no upstream network, such as \"shared\" or \"link-local\", these properties must be empty. For IPv4 method \"shared\", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_NEVER_DEFAULT N_("If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager.") @@ -254,7 +183,7 @@ #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTE_TABLE N_("Enable policy routing (source routing) and set the routing table used when adding routes. This affects all routes, including device-routes, IPv4LL, DHCP, SLAAC, default-routes and static routes. But note that static routes can individually overwrite the setting by explicitly specifying a non-zero routing table. If the table setting is left at zero, it is eligible to be overwritten via global configuration. If the property is zero even after applying the global configuration value, policy routing is disabled for the address family of this connection. Policy routing disabled means that NetworkManager will add all routes to the main table (except static routes that explicitly configure a different table). Additionally, NetworkManager will not delete any extraneous routes from tables except the main table. This is to preserve backward compatibility for users who manage routing tables outside of NetworkManager.") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTES N_("A list of IPv4 destination addresses, prefix length, optional IPv4 next hop addresses, optional route metric, optional attribute. The valid syntax is: \"ip[/prefix] [next-hop] [metric] [attribute=val]...[,ip[/prefix]...]\". For example \"192.0.2.0/24 10.1.1.1 77, 198.51.100.0/24\".") #define DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTING_RULES N_("A comma separated list of routing rules for policy routing.") -#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE N_("Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. On D-Bus, the absence of an addr-gen-mode setting equals enabling stable-privacy. For keyfile plugin, the absence of the setting on disk means EUI64 so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by \"ip6-privacy\" property and it does not affect the temporary addresses configured with this option.") +#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE N_("Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0), NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64 (2) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT (3). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. The special values \"default\" and \"default-or-eui64\" will fallback to the global connection default in as documented in NetworkManager.conf(5) manual. If the global default is not specified, the fallback value is \"stable-privacy\" or \"eui64\", respectively. For libnm, the property defaults to \"default\" since 1.40. Previously it defaulted to \"stable-privacy\". On D-Bus, the absence of an addr-gen-mode setting equals \"default\". For keyfile plugin, the absence of the setting on disk means \"default-or-eui64\" so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by \"ip6-privacy\" property and it does not affect the temporary addresses configured with this option.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ADDRESSES N_("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 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).") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DAD_TIMEOUT N_("Timeout in milliseconds used to check for the presence of duplicate IP addresses on the network. If an address conflict is detected, the activation will fail. A zero value means that no duplicate address detection is performed, -1 means the default value (either configuration ipvx.dad-timeout override or zero). A value greater than zero is a timeout in milliseconds. The property is currently implemented only for IPv4.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DHCP_DUID N_("A string containing the DHCPv6 Unique Identifier (DUID) used by the dhcp client to identify itself to DHCPv6 servers (RFC 3315). The DUID is carried in the Client Identifier option. If the property is a hex string ('aa:bb:cc') it is interpreted as a binary DUID and filled as an opaque value in the Client Identifier option. The special value \"lease\" will retrieve the DUID previously used from the lease file belonging to the connection. If no DUID is found and \"dhclient\" is the configured dhcp client, the DUID is searched in the system-wide dhclient lease file. If still no DUID is found, or another dhcp client is used, a global and permanent DUID-UUID (RFC 6355) will be generated based on the machine-id. The special values \"llt\" and \"ll\" will generate a DUID of type LLT or LL (see RFC 3315) based on the current MAC address of the device. In order to try providing a stable DUID-LLT, the time field will contain a constant timestamp that is used globally (for all profiles) and persisted to disk. The special values \"stable-llt\", \"stable-ll\" and \"stable-uuid\" will generate a DUID of the corresponding type, derived from the connection's stable-id and a per-host unique key. You may want to include the \"${DEVICE}\" or \"${MAC}\" specifier in the stable-id, in case this profile gets activated on multiple devices. So, the link-layer address of \"stable-ll\" and \"stable-llt\" will be a generated address derived from the stable id. The DUID-LLT time value in the \"stable-llt\" option will be picked among a static timespan of three years (the upper bound of the interval is the same constant timestamp used in \"llt\"). When the property is unset, the global value provided for \"ipv6.dhcp-duid\" is used. If no global value is provided, the default \"lease\" value is assumed.") @@ -267,13 +196,14 @@ #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS N_("Array of IP addresses of DNS servers.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS N_("Array of DNS options as described in man 5 resolv.conf. NULL means that the options are unset and left at the default. In this case NetworkManager will use default options. This is distinct from an empty list of properties. The currently supported options are \"attempts\", \"debug\", \"edns0\", \"inet6\", \"ip6-bytestring\", \"ip6-dotint\", \"ndots\", \"no-check-names\", \"no-ip6-dotint\", \"no-reload\", \"no-tld-query\", \"rotate\", \"single-request\", \"single-request-reopen\", \"timeout\", \"trust-ad\", \"use-vc\". The \"trust-ad\" setting is only honored if the profile contributes name servers to resolv.conf, and if all contributing profiles have \"trust-ad\" enabled. When using a caching DNS plugin (dnsmasq or systemd-resolved in NetworkManager.conf) then \"edns0\" and \"trust-ad\" are automatically added.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY N_("DNS servers priority. The relative priority for DNS servers specified by this setting. A lower numerical value is better (higher priority). Negative values have the special effect of excluding other configurations with a greater numerical priority value; so in presence of at least one negative priority, only DNS servers from connections with the lowest priority value will be used. To avoid all DNS leaks, set the priority of the profile that should be used to the most negative value of all active connections profiles. Zero selects a globally configured default value. If the latter is missing or zero too, it defaults to 50 for VPNs (including WireGuard) and 100 for other connections. Note that the priority is to order DNS settings for multiple active connections. It does not disambiguate multiple DNS servers within the same connection profile. When multiple devices have configurations with the same priority, VPNs will be considered first, then devices with the best (lowest metric) default route and then all other devices. When using dns=default, servers with higher priority will be on top of resolv.conf. To prioritize a given server over another one within the same connection, just specify them in the desired order. Note that commonly the resolver tries name servers in /etc/resolv.conf in the order listed, proceeding with the next server in the list on failure. See for example the \"rotate\" option of the dns-options setting. If there are any negative DNS priorities, then only name servers from the devices with that lowest priority will be considered. When using a DNS resolver that supports Conditional Forwarding or Split DNS (with dns=dnsmasq or dns=systemd-resolved settings), each connection is used to query domains in its search list. The search domains determine which name servers to ask, and the DNS priority is used to prioritize name servers based on the domain. Queries for domains not present in any search list are routed through connections having the '~.' special wildcard domain, which is added automatically to connections with the default route (or can be added manually). When multiple connections specify the same domain, the one with the best priority (lowest numerical value) wins. If a sub domain is configured on another interface it will be accepted regardless the priority, unless parent domain on the other interface has a negative priority, which causes the sub domain to be shadowed. With Split DNS one can avoid undesired DNS leaks by properly configuring DNS priorities and the search domains, so that only name servers of the desired interface are configured.") -#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("Array of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting.") +#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH N_("List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting \"ignore-auto-dns\". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15).") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY N_("The gateway associated with this configuration. This is only meaningful if \"addresses\" is also set. The gateway's main purpose is to control the next hop of the standard default route on the device. Hence, the gateway property conflicts with \"never-default\" and will be automatically dropped if the IP configuration is set to never-default. As an alternative to set the gateway, configure a static default route with /0 as prefix length.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured name servers and search domains are ignored and only name servers and search domains specified in the \"dns\" and \"dns-search\" properties, if any, are used.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES N_("When \"method\" is set to \"auto\" and this property to TRUE, automatically configured routes are ignored and only routes specified in the \"routes\" property, if any, are used.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_IP6_PRIVACY N_("Configure IPv6 Privacy Extensions for SLAAC, described in RFC4941. If enabled, it makes the kernel generate a temporary IPv6 address in addition to the public one generated from MAC address via modified EUI-64. This enhances privacy, but could cause problems in some applications, on the other hand. The permitted values are: -1: unknown, 0: disabled, 1: enabled (prefer public address), 2: enabled (prefer temporary addresses). Having a per-connection setting set to \"-1\" (unknown) means fallback to global configuration \"ipv6.ip6-privacy\". If also global configuration is unspecified or set to \"-1\", fallback to read \"/proc/sys/net/ipv6/conf/default/use_tempaddr\". Note that this setting is distinct from the Stable Privacy addresses that can be enabled with the \"addr-gen-mode\" property's \"stable-privacy\" setting as another way of avoiding host tracking with IPv6 addresses.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_MAY_FAIL N_("If TRUE, allow overall network configuration to proceed even if the configuration specified by this property times out. Note that at least one IP configuration must succeed or overall network configuration will still fail. For example, in IPv6-only networks, setting this property to TRUE on the NMSettingIP4Config allows the overall network configuration to succeed if IPv4 configuration fails but IPv6 configuration completes successfully.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_METHOD N_("IP configuration method. NMSettingIP4Config and NMSettingIP6Config both support \"disabled\", \"auto\", \"manual\", and \"link-local\". See the subclass-specific documentation for other values. In general, for the \"auto\" method, properties such as \"dns\" and \"routes\" specify information that is added on to the information returned from automatic configuration. The \"ignore-auto-routes\" and \"ignore-auto-dns\" properties modify this behavior. For methods that imply no upstream network, such as \"shared\" or \"link-local\", these properties must be empty. For IPv4 method \"shared\", the IP subnet can be configured by adding one manual IPv4 address or otherwise 10.42.x.0/24 is chosen. Note that the shared method must be configured on the interface which shares the internet to a subnet, not on the uplink which is shared.") +#define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_MTU N_("Maximum transmission unit size, in bytes. If zero (the default), the MTU is set automatically from router advertisements or is left equal to the link-layer MTU. If greater than the link-layer MTU, or greater than zero but less than the minimum IPv6 MTU of 1280, this value has no effect.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_NEVER_DEFAULT N_("If TRUE, this connection will never be the default connection for this IP type, meaning it will never be assigned the default route by NetworkManager.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_RA_TIMEOUT N_("A timeout for waiting Router Advertisements in seconds. If zero (the default), a globally configured default is used. If still unspecified, the timeout depends on the sysctl settings of the device. Set to 2147483647 (MAXINT32) for infinity.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_REQUIRED_TIMEOUT N_("The minimum time interval in milliseconds for which dynamic IP configuration should be tried before the connection succeeds. This property is useful for example if both IPv4 and IPv6 are enabled and are allowed to fail. Normally the connection succeeds as soon as one of the two address families completes; by setting a required timeout for e.g. IPv4, one can ensure that even if IP6 succeeds earlier than IPv4, NetworkManager waits some time for IPv4 before the connection becomes active. Note that if \"may-fail\" is FALSE for the same address family, this property has no effect as NetworkManager needs to wait for the full DHCP timeout. A zero value means that no required timeout is present, -1 means the default value (either configuration ipvx.required-timeout override or zero).") @@ -282,6 +212,19 @@ #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTES N_("Array of IP routes.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTING_RULES N_("A comma separated list of routing rules for policy routing.") #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_TOKEN N_("Configure the token for draft-chown-6man-tokenised-ipv6-identifiers-02 IPv6 tokenized interface identifiers. Useful with eui64 addr-gen-mode.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT N_("How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLAGS N_("Tunnel flags. Currently, the following values are supported: NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS (0x2), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL (0x4), NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV (0x8), NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY (0x10), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK (0x20). They are valid only for IPv6 tunnels.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLOW_LABEL N_("The flow label to assign to tunnel packets. This property applies only to IPv6 tunnels.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_INPUT_KEY N_("The key used for tunnel input packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_LOCAL N_("The local endpoint of the tunnel; the value can be empty, otherwise it must contain an IPv4 or IPv6 address.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MODE N_("The tunneling mode, for example NM_IP_TUNNEL_MODE_IPIP (1) or NM_IP_TUNNEL_MODE_GRE (2).") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_OUTPUT_KEY N_("The key used for tunnel output packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_PARENT N_("If given, specifies the parent interface name or parent connection UUID the new device will be bound to so that tunneled packets will only be routed via that interface.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY N_("Whether to enable Path MTU Discovery on this tunnel.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_REMOTE N_("The remote endpoint of the tunnel; the value must contain an IPv4 or IPv6 address.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TOS N_("The type of service (IPv4) or traffic class (IPv6) field to be set on tunneled packets.") +#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_TTL N_("The TTL to assign to tunneled packets. 0 is a special value meaning that packets inherit the TTL value.") #define DESCRIBE_DOC_NM_SETTING_MACSEC_ENCRYPT N_("Whether the transmitted traffic must be encrypted.") #define DESCRIBE_DOC_NM_SETTING_MACSEC_MKA_CAK N_("The pre-shared CAK (Connectivity Association Key) for MACsec Key Agreement.") #define DESCRIBE_DOC_NM_SETTING_MACSEC_MKA_CAK_FLAGS N_("Flags indicating how to handle the \"mka-cak\" property.") @@ -299,6 +242,9 @@ #define DESCRIBE_DOC_NM_SETTING_MATCH_INTERFACE_NAME N_("A list of interface names to match. Each element is a shell wildcard pattern. An element can be prefixed with a pipe symbol (|) or an ampersand (&). The former means that the element is optional and the latter means that it is mandatory. If there are any optional elements, than the match evaluates to true if at least one of the optional element matches (logical OR). If there are any mandatory elements, then they all must match (logical AND). By default, an element is optional. This means that an element \"foo\" behaves the same as \"|foo\". An element can also be inverted with exclamation mark (!) between the pipe symbol (or the ampersand) and before the pattern. Note that \"!foo\" is a shortcut for the mandatory match \"&!foo\". Finally, a backslash can be used at the beginning of the element (after the optional special characters) to escape the start of the pattern. For example, \"&\\!a\" is an mandatory match for literally \"!a\".") #define DESCRIBE_DOC_NM_SETTING_MATCH_KERNEL_COMMAND_LINE N_("A list of kernel command line arguments to match. This may be used to check whether a specific kernel command line option is set (or unset, if prefixed with the exclamation mark). The argument must either be a single word, or an assignment (i.e. two words, joined by \"=\"). In the former case the kernel command line is searched for the word appearing as is, or as left hand side of an assignment. In the latter case, the exact assignment is looked for with right and left hand side matching. Wildcard patterns are not supported. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the match.") #define DESCRIBE_DOC_NM_SETTING_MATCH_PATH N_("A list of paths to match against the ID_PATH udev property of devices. ID_PATH represents the topological persistent path of a device. It typically contains a subsystem string (pci, usb, platform, etc.) and a subsystem-specific identifier. For PCI devices the path has the form \"pci-$domain:$bus:$device.$function\", where each variable is an hexadecimal value; for example \"pci-0000:0a:00.0\". The path of a device can be obtained with \"udevadm info /sys/class/net/$dev | grep ID_PATH=\" or by looking at the \"path\" property exported by NetworkManager (\"nmcli -f general.path device show $dev\"). Each element of the list is a shell wildcard pattern. See NMSettingMatch:interface-name for how special characters '|', '&', '!' and '\\' are used for optional and mandatory matches and inverting the pattern.") +#define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_CHANNEL N_("Channel on which the mesh network to join is located.") +#define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS N_("Anycast DHCP MAC address used when requesting an IP address via DHCP. The specific anycast address used determines which DHCP server class answers the request. This is currently only implemented by dhclient DHCP plugin.") +#define DESCRIBE_DOC_NM_SETTING_OLPC_MESH_SSID N_("SSID of the mesh network to join.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_DATAPATH_TYPE N_("The data path type. One of \"system\", \"netdev\" or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_FAIL_MODE N_("The bridge failure mode. One of \"secure\", \"standalone\" or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE N_("Enable or disable multicast snooping.") @@ -306,7 +252,6 @@ #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_STP_ENABLE N_("Enable or disable STP.") #define DESCRIBE_DOC_NM_SETTING_OVS_DPDK_DEVARGS N_("Open vSwitch DPDK device arguments.") #define DESCRIBE_DOC_NM_SETTING_OVS_DPDK_N_RXQ N_("Open vSwitch DPDK number of rx queues. Defaults to zero which means to leave the parameter in OVS unspecified and effectively configures one queue.") -#define DESCRIBE_DOC_NM_SETTING_OVS_EXTERNAL_IDS_DATA N_("A dictionary of key/value pairs with exernal-ids for OVS.") #define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_TYPE N_("The interface type. Either \"internal\", \"system\", \"patch\", \"dpdk\", or empty.") #define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_PEER N_("Specifies the name of the interface for the other side of the patch. The patch on the other side must also set this interface as peer.") #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_DOWNDELAY N_("The time port must be inactive in order to be considered down.") @@ -382,7 +327,6 @@ #define DESCRIBE_DOC_NM_SETTING_TUN_PI N_("If TRUE the interface will prepend a 4 byte header describing the physical interface to the packets.") #define DESCRIBE_DOC_NM_SETTING_TUN_VNET_HDR N_("If TRUE the IFF_VNET_HDR the tunnel packets will include a virtio network header.") #define DESCRIBE_DOC_NM_SETTING_USER_DATA N_("A dictionary of key/value pairs with user data. This data is ignored by NetworkManager and can be used at the users discretion. The keys only support a strict ascii format, but the values can be arbitrary UTF8 strings up to a certain length.") -#define DESCRIBE_DOC_NM_SETTING_VETH_PEER N_("This property specifies the peer interface name of the veth. This property is mandatory.") #define DESCRIBE_DOC_NM_SETTING_VLAN_EGRESS_PRIORITY_MAP N_("For outgoing packets, a list of mappings from Linux SKB priorities to 802.1p priorities. The mapping is given in the format \"from:to\" where both \"from\" and \"to\" are unsigned integers, ie \"7:3\".") #define DESCRIBE_DOC_NM_SETTING_VLAN_FLAGS N_("One or more flags which control the behavior and features of the VLAN interface. Flags include NM_VLAN_FLAG_REORDER_HEADERS (0x1) (reordering of output packet headers), NM_VLAN_FLAG_GVRP (0x2) (use of the GVRP protocol), and NM_VLAN_FLAG_LOOSE_BINDING (0x4) (loose binding of the interface to its master device's operating state). NM_VLAN_FLAG_MVRP (0x8) (use of the MVRP protocol). The default value of this property is NM_VLAN_FLAG_REORDER_HEADERS, but it used to be 0. To preserve backward compatibility, the default-value in the D-Bus API continues to be 0 and a missing property on D-Bus is still considered as 0.") #define DESCRIBE_DOC_NM_SETTING_VLAN_ID N_("The VLAN identifier that the interface created by this connection should be assigned. The valid range is from 0 to 4094, without the reserved id 4095.") @@ -416,16 +360,76 @@ #define DESCRIBE_DOC_NM_SETTING_WIFI_P2P_WPS_METHOD N_("Flags indicating which mode of WPS is to be used. There's little point in changing the default setting as NetworkManager will automatically determine the best method to use.") #define DESCRIBE_DOC_NM_SETTING_WIMAX_MAC_ADDRESS N_("If specified, this connection will only apply to the WiMAX device whose MAC address matches. This property does not change the MAC address of the device (known as MAC spoofing). Deprecated: 1") #define DESCRIBE_DOC_NM_SETTING_WIMAX_NETWORK_NAME N_("Network Service Provider (NSP) name of the WiMAX network this connection should use. Deprecated: 1") +#define DESCRIBE_DOC_NM_SETTING_WIRED_ACCEPT_ALL_MAC_ADDRESSES N_("When TRUE, setup the interface to accept packets for all MAC addresses. This is enabling the kernel interface flag IFF_PROMISC. When FALSE, the interface will only accept the packets with the interface destination mac address or broadcast.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_AUTO_NEGOTIATE N_("When TRUE, enforce auto-negotiation of speed and duplex mode. If \"speed\" and \"duplex\" properties are both specified, only that single mode will be advertised and accepted during the link auto-negotiation process: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. When FALSE, \"speed\" and \"duplex\" properties should be both set or link configuration will be skipped.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_CLONED_MAC_ADDRESS N_("If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. Beside explicitly specifying a MAC address, the special values \"preserve\", \"permanent\", \"random\" and \"stable\" are supported. \"preserve\" means not to touch the MAC address on activation. \"permanent\" means to use the permanent hardware address if the device has one (otherwise this is treated as \"preserve\"). \"random\" creates a random MAC address on each connect. \"stable\" creates a hashed MAC address based on connection.stable-id and a machine dependent key. If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to \"preserve\" (older versions of NetworkManager may use a different default value). On D-Bus, this field is expressed as \"assigned-mac-address\" or the deprecated \"cloned-mac-address\".") +#define DESCRIBE_DOC_NM_SETTING_WIRED_DUPLEX N_("When a value is set, either \"half\" or \"full\", configures the device to use the specified duplex mode. If \"auto-negotiate\" is \"yes\" the specified duplex mode will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabits modes, as in these cases link negotiation is mandatory. If the value is unset (the default), the link configuration will be either skipped (if \"auto-negotiate\" is \"no\", the default) or will be auto-negotiated (if \"auto-negotiate\" is \"yes\") and the local device will advertise all the supported duplex modes. Must be set together with the \"speed\" property if specified. Before specifying a duplex mode be sure your device supports it.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_GENERATE_MAC_ADDRESS_MASK N_("With \"cloned-mac-address\" setting \"random\" or \"stable\", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting \"FE:FF:FF:00:00:00\" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the \"random\" or \"stable\" algorithm. If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of \"FE:FF:FF:00:00:00 68:F7:28:00:00:00\" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of \"02:00:00:00:00:00 00:00:00:00:00:00\" will create a fully scrambled globally-administered, burned-in MAC address. If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, \"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00\" will create a fully scrambled MAC address, randomly locally or globally administered.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_MAC_ADDRESS N_("If specified, this connection will only apply to the Ethernet device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).") +#define DESCRIBE_DOC_NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST N_("If specified, this connection will never apply to the Ethernet device whose permanent MAC address matches an address in the list. Each MAC address is in the standard hex-digits-and-colons notation (00:11:22:33:44:55).") +#define DESCRIBE_DOC_NM_SETTING_WIRED_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_PORT N_("Specific port type to use if the device supports multiple attachment methods. One of \"tp\" (Twisted Pair), \"aui\" (Attachment Unit Interface), \"bnc\" (Thin Ethernet) or \"mii\" (Media Independent Interface). If the device supports only one port type, this setting is ignored.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_S390_NETTYPE N_("s390 network device type; one of \"qeth\", \"lcs\", or \"ctc\", representing the different types of virtual network devices available on s390 systems.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_S390_OPTIONS N_("Dictionary of key/value pairs of s390-specific device options. Both keys and values must be strings. Allowed keys include \"portno\", \"layer2\", \"portname\", \"protocol\", among others. Key names must contain only alphanumeric characters (ie, [a-zA-Z0-9]). Currently, NetworkManager itself does nothing with this information. However, s390utils ships a udev rule which parses this information and applies it to the interface.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_S390_SUBCHANNELS N_("Identifies specific subchannels that this network device uses for communication with z/VM or s390 host. Like the \"mac-address\" property for non-z/VM devices, this property can be used to ensure this connection only applies to the network device that uses these subchannels. The list should contain exactly 3 strings, and each string may only be composed of hexadecimal characters and the period (.) character.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_SPEED N_("When a value greater than 0 is set, configures the device to use the specified speed. If \"auto-negotiate\" is \"yes\" the specified speed will be the only one advertised during link negotiation: this works only for BASE-T 802.3 specifications and is useful for enforcing gigabit speeds, as in this case link negotiation is mandatory. If the value is unset (0, the default), the link configuration will be either skipped (if \"auto-negotiate\" is \"no\", the default) or will be auto-negotiated (if \"auto-negotiate\" is \"yes\") and the local device will advertise all the supported speeds. In Mbit/s, ie 100 == 100Mbit/s. Must be set together with the \"duplex\" property when non-zero. Before specifying a speed value be sure your device supports it.") +#define DESCRIBE_DOC_NM_SETTING_WIRED_WAKE_ON_LAN N_("The NMSettingWiredWakeOnLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRED_WAKE_ON_LAN_PHY (0x2), NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST (0x4), NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST (0x8), NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST (0x10), NM_SETTING_WIRED_WAKE_ON_LAN_ARP (0x20), NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC (0x40) or the special values NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager).") +#define DESCRIBE_DOC_NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD N_("If specified, the password used with magic-packet-based Wake-on-LAN, represented as an Ethernet MAC address. If NULL, no password will be required.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_FWMARK N_("The use of fwmark is optional and is by default off. Setting it to 0 disables it. Otherwise, it is a 32-bit fwmark for outgoing packets. Note that \"ip4-auto-default-route\" or \"ip6-auto-default-route\" enabled, implies to automatically choose a fwmark.") -#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_IP4_AUTO_DEFAULT_ROUTE N_("Whether to enable special handling of the IPv4 default route. If enabled, the IPv4 default route from wireguard.peer-routes will be placed to a dedicated routing-table and two policy routing rules will be added. The fwmark number is also used as routing-table for the default-route, and if fwmark is zero, an unused fwmark/table is chosen automatically. This corresponds to what wg-quick does with Table=auto and what WireGuard calls \"Improved Rule-based Routing\". Note that for this automatism to work, you usually don't want to set ipv4.gateway, because that will result in a conflicting default route. Leaving this at the default will enable this option automatically if ipv4.never-default is not set and there are any peers that use a default-route as allowed-ips.") +#define DESCRIBE_DOC_NM_SETTING_WIREGUARD_IP4_AUTO_DEFAULT_ROUTE N_("Whether to enable special handling of the IPv4 default route. If enabled, the IPv4 default route from wireguard.peer-routes will be placed to a dedicated routing-table and two policy routing rules will be added. The fwmark number is also used as routing-table for the default-route, and if fwmark is zero, an unused fwmark/table is chosen automatically. This corresponds to what wg-quick does with Table=auto and what WireGuard calls \"Improved Rule-based Routing\". Note that for this automatism to work, you usually don't want to set ipv4.gateway, because that will result in a conflicting default route. Leaving this at the default will enable this option automatically if ipv4.never-default is not set and there are any peers that use a default-route as allowed-ips. Since this automatism only makes sense if you also have a peer with an /0 allowed-ips, it is usually not necessary to enable this explicitly. However, you can disable it if you want to configure your own routing and rules.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_IP6_AUTO_DEFAULT_ROUTE N_("Like ip4-auto-default-route, but for the IPv6 default route.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_LISTEN_PORT N_("The listen-port. If listen-port is not specified, the port will be chosen randomly when the interface comes up.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments. If zero a default MTU is used. Note that contrary to wg-quick's MTU setting, this does not take into account the current routes at the time of activation.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PEER_ROUTES N_("Whether to automatically add routes for the AllowedIPs ranges of the peers. If TRUE (the default), NetworkManager will automatically add routes in the routing tables according to ipv4.route-table and ipv6.route-table. Usually you want this automatism enabled. If FALSE, no such routes are added automatically. In this case, the user may want to configure static routes in ipv4.routes and ipv6.routes, respectively. Note that if the peer's AllowedIPs is \"0.0.0.0/0\" or \"::/0\" and the profile's ipv4.never-default or ipv6.never-default setting is enabled, the peer route for this peer won't be added automatically.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PRIVATE_KEY N_("The 256 bit private-key in base64 encoding.") #define DESCRIBE_DOC_NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS N_("Flags indicating how to handle the \"private-key\" property.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_AP_ISOLATION N_("Configures AP isolation, which prevents communication between wireless devices connected to this AP. This property can be set to a value different from NM_TERNARY_DEFAULT (-1) only when the interface is configured in AP mode. If set to NM_TERNARY_TRUE (1), devices are not able to communicate with each other. This increases security because it protects devices against attacks from other clients in the network. At the same time, it prevents devices to access resources on the same wireless networks as file shares, printers, etc. If set to NM_TERNARY_FALSE (0), devices can talk to each other. When set to NM_TERNARY_DEFAULT (-1), the global default is used; in case the global default is unspecified it is assumed to be NM_TERNARY_FALSE (0).") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_BAND N_("802.11 frequency band of the network. One of \"a\" for 5GHz 802.11a or \"bg\" for 2.4GHz 802.11. This will lock associations to the Wi-Fi network to the specific band, i.e. if \"a\" is specified, the device will not associate with the same network in the 2.4GHz band even if the network's settings are compatible. This setting depends on specific driver capability and may not work with all drivers.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_BSSID N_("If specified, directs the device to only associate with the given access point. This capability is highly driver dependent and not supported by all devices. Note: this property does not control the BSSID used when creating an Ad-Hoc network and is unlikely to in the future. Locking a client profile to a certain BSSID will prevent roaming and also disable background scanning. That can be useful, if there is only one access point for the SSID.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_CHANNEL N_("Wireless channel to use for the Wi-Fi connection. The device will only join (or create for Ad-Hoc networks) a Wi-Fi network on the specified channel. Because channel numbers overlap between bands, this property also requires the \"band\" property to be set.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS N_("If specified, request that the device use this MAC address instead. This is known as MAC cloning or spoofing. Beside explicitly specifying a MAC address, the special values \"preserve\", \"permanent\", \"random\" and \"stable\" are supported. \"preserve\" means not to touch the MAC address on activation. \"permanent\" means to use the permanent hardware address of the device. \"random\" creates a random MAC address on each connect. \"stable\" creates a hashed MAC address based on connection.stable-id and a machine dependent key. If unspecified, the value can be overwritten via global defaults, see manual of NetworkManager.conf. If still unspecified, it defaults to \"preserve\" (older versions of NetworkManager may use a different default value). On D-Bus, this field is expressed as \"assigned-mac-address\" or the deprecated \"cloned-mac-address\".") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK N_("With \"cloned-mac-address\" setting \"random\" or \"stable\", by default all bits of the MAC address are scrambled and a locally-administered, unicast MAC address is created. This property allows to specify that certain bits are fixed. Note that the least significant bit of the first MAC address will always be unset to create a unicast MAC address. If the property is NULL, it is eligible to be overwritten by a default connection setting. If the value is still NULL or an empty string, the default is to create a locally-administered, unicast MAC address. If the value contains one MAC address, this address is used as mask. The set bits of the mask are to be filled with the current MAC address of the device, while the unset bits are subject to randomization. Setting \"FE:FF:FF:00:00:00\" means to preserve the OUI of the current MAC address and only randomize the lower 3 bytes using the \"random\" or \"stable\" algorithm. If the value contains one additional MAC address after the mask, this address is used instead of the current MAC address to fill the bits that shall not be randomized. For example, a value of \"FE:FF:FF:00:00:00 68:F7:28:00:00:00\" will set the OUI of the MAC address to 68:F7:28, while the lower bits are randomized. A value of \"02:00:00:00:00:00 00:00:00:00:00:00\" will create a fully scrambled globally-administered, burned-in MAC address. If the value contains more than one additional MAC addresses, one of them is chosen randomly. For example, \"02:00:00:00:00:00 00:00:00:00:00:00 02:00:00:00:00:00\" will create a fully scrambled MAC address, randomly locally or globally administered.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_HIDDEN N_("If TRUE, indicates that the network is a non-broadcasting network that hides its SSID. This works both in infrastructure and AP mode. In infrastructure mode, various workarounds are used for a more reliable discovery of hidden networks, such as probe-scanning the SSID. However, these workarounds expose inherent insecurities with hidden SSID networks, and thus hidden SSID networks should be used with caution. In AP mode, the created network does not broadcast its SSID. Note that marking the network as hidden may be a privacy issue for you (in infrastructure mode) or client stations (in AP mode), as the explicit probe-scans are distinctly recognizable on the air.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS N_("If specified, this connection will only apply to the Wi-Fi device whose permanent MAC address matches. This property does not change the MAC address of the device (i.e. MAC spoofing).") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST N_("A list of permanent MAC addresses of Wi-Fi devices to which this connection should never apply. Each MAC address should be given in the standard hex-digits-and-colons notation (eg \"00:11:22:33:44:55\").") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION N_("One of NM_SETTING_MAC_RANDOMIZATION_DEFAULT (0) (never randomize unless the user has set a global default to randomize and the supplicant supports randomization), NM_SETTING_MAC_RANDOMIZATION_NEVER (1) (never randomize the MAC address), or NM_SETTING_MAC_RANDOMIZATION_ALWAYS (2) (always randomize the MAC address). This property is deprecated for 'cloned-mac-address'. Deprecated: 1") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MODE N_("Wi-Fi network mode; one of \"infrastructure\", \"mesh\", \"adhoc\" or \"ap\". If blank, infrastructure is assumed.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple Ethernet frames.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_POWERSAVE N_("One of NM_SETTING_WIRELESS_POWERSAVE_DISABLE (2) (disable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_ENABLE (3) (enable Wi-Fi power saving), NM_SETTING_WIRELESS_POWERSAVE_IGNORE (1) (don't touch currently configure setting) or NM_SETTING_WIRELESS_POWERSAVE_DEFAULT (0) (use the globally configured value). All other values are reserved.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_RATE N_("If non-zero, directs the device to only use the specified bitrate for communication with the access point. Units are in Kb/s, ie 5500 = 5.5 Mbit/s. This property is highly driver dependent and not all devices support setting a static bitrate.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SEEN_BSSIDS N_("A list of BSSIDs (each BSSID formatted as a MAC address like \"00:11:22:33:44:55\") that have been detected as part of the Wi-Fi network. NetworkManager internally tracks previously seen BSSIDs. The property is only meant for reading and reflects the BSSID list of NetworkManager. The changes you make to this property will not be preserved.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SSID N_("SSID of the Wi-Fi network. Must be specified.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_TX_POWER N_("If non-zero, directs the device to use the specified transmit power. Units are dBm. This property is highly driver dependent and not all devices support setting a static transmit power.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_WAKE_ON_WLAN N_("The NMSettingWirelessWakeOnWLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY (0x2), NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT (0x4), NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC (0x8), NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE (0x10), NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST (0x20), NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE (0x40), NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE (0x80), NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP (0x100) or the special values NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager).") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_AUTH_ALG N_("When WEP is used (ie, key-mgmt = \"none\" or \"ieee8021x\") indicate the 802.11 authentication algorithm required by the AP here. One of \"open\" for Open System, \"shared\" for Shared Key, or \"leap\" for Cisco LEAP. When using Cisco LEAP (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\") the \"leap-username\" and \"leap-password\" properties must be specified.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_FILS N_("Indicates whether Fast Initial Link Setup (802.11ai) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE (1) (disable FILS), NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL (2) (enable FILS if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED (3) (enable FILS and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) and no global default is set, FILS will be optionally enabled.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_GROUP N_("A list of group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of \"wep40\", \"wep104\", \"tkip\", or \"ccmp\".") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_KEY_MGMT N_("Key management used for the connection. One of \"none\" (WEP or no password protection), \"ieee8021x\" (Dynamic WEP), \"owe\" (Opportunistic Wireless Encryption), \"wpa-psk\" (WPA2 + WPA3 personal), \"sae\" (WPA3 personal only), \"wpa-eap\" (WPA2 + WPA3 enterprise) or \"wpa-eap-suite-b-192\" (WPA3 enterprise only). This property must be set for any Wi-Fi connection that uses security.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD N_("The login password for legacy LEAP connections (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\").") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS N_("Flags indicating how to handle the \"leap-password\" property.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME N_("The login username for legacy LEAP connections (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\").") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PAIRWISE N_("A list of pairwise encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of \"tkip\" or \"ccmp\".") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PMF N_("Indicates whether Protected Management Frames (802.11w) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE (1) (disable PMF), NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL (2) (enable PMF if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED (3) (enable PMF and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT (0) and no global default is set, PMF will be optionally enabled.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PROTO N_("List of strings specifying the allowed WPA protocol versions to use. Each element may be one \"wpa\" (allow WPA) or \"rsn\" (allow WPA2/RSN). If not specified, both WPA and RSN connections are allowed.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PSK N_("Pre-Shared-Key for WPA networks. For WPA-PSK, it's either an ASCII passphrase of 8 to 63 characters that is (as specified in the 802.11i standard) hashed to derive the actual key, or the key in form of 64 hexadecimal character. The WPA3-Personal networks use a passphrase of any length for SAE authentication.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS N_("Flags indicating how to handle the \"psk\" property.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS N_("Flags indicating how to handle the \"wep-key0\", \"wep-key1\", \"wep-key2\", and \"wep-key3\" properties.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE N_("Controls the interpretation of WEP keys. Allowed values are NM_WEP_KEY_TYPE_KEY (1), in which case the key is either a 10- or 26-character hexadecimal string, or a 5- or 13-character ASCII password; or NM_WEP_KEY_TYPE_PASSPHRASE (2), in which case the passphrase is provided as a string and will be hashed using the de-facto MD5 method to derive the actual WEP key.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY0 N_("Index 0 WEP key. This is the WEP key used in most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY1 N_("Index 1 WEP key. This WEP index is not used by most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY2 N_("Index 2 WEP key. This WEP index is not used by most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_KEY3 N_("Index 3 WEP key. This WEP index is not used by most networks. See the \"wep-key-type\" property for a description of how this key is interpreted.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX N_("When static WEP is used (ie, key-mgmt = \"none\") and a non-default WEP key index is used by the AP, put that WEP key index here. Valid values are 0 (default key) through 3. Note that some consumer access points (like the Linksys WRT54G) number the keys 1 - 4.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_WPS_METHOD N_("Flags indicating which mode of WPS is to be used if any. There's little point in changing the default setting as NetworkManager will automatically determine whether it's feasible to start WPS enrollment from the Access Point capabilities. WPS can be disabled by setting this property to a value of 1.") #define DESCRIBE_DOC_NM_SETTING_WPAN_CHANNEL N_("IEEE 802.15.4 channel. A positive integer or -1, meaning \"do not set, use whatever the device is already set to\".") #define DESCRIBE_DOC_NM_SETTING_WPAN_MAC_ADDRESS N_("If specified, this connection will only apply to the IEEE 802.15.4 (WPAN) MAC layer device whose permanent MAC address matches.") #define DESCRIBE_DOC_NM_SETTING_WPAN_PAGE N_("IEEE 802.15.4 channel page. A positive integer or -1, meaning \"do not set, use whatever the device is already set to\".") #define DESCRIBE_DOC_NM_SETTING_WPAN_PAN_ID N_("IEEE 802.15.4 Personal Area Network (PAN) identifier.") #define DESCRIBE_DOC_NM_SETTING_WPAN_SHORT_ADDRESS N_("Short IEEE 802.15.4 address to be used within a restricted environment.") +#define DESCRIBE_DOC_NM_SETTING_BOND_PORT_QUEUE_ID N_("The queue ID of this bond port. The maximum value of queue ID is the number of TX queues currently active in device.") +#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DHCP N_("Whether the system hostname can be determined from DHCP on this connection. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).") +#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP N_("Whether the system hostname can be determined from reverse DNS lookup of addresses on this device. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_TRUE (1).") +#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT N_("If set to NM_TERNARY_TRUE (1), NetworkManager attempts to get the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this device only when the device has the default route for the given address family (IPv4/IPv6). If set to NM_TERNARY_FALSE (0), the hostname can be set from this device even if it doesn't have the default route. When set to NM_TERNARY_DEFAULT (-1), the value from global configuration is used. If the property doesn't have a value in the global configuration, NetworkManager assumes the value to be NM_TERNARY_FALSE (0).") +#define DESCRIBE_DOC_NM_SETTING_HOSTNAME_PRIORITY N_("The relative priority of this connection to determine the system hostname. A lower numerical value is better (higher priority). A connection with higher priority is considered before connections with lower priority. If the value is zero, it can be overridden by a global value from NetworkManager configuration. If the property doesn't have a value in the global configuration, the value is assumed to be 100. Negative values have the special effect of excluding other connections with a greater numerical priority value; so in presence of at least one negative priority, only connections with the lowest priority value will be used to determine the hostname.") +#define DESCRIBE_DOC_NM_SETTING_OVS_EXTERNAL_IDS_DATA N_("A dictionary of key/value pairs with exernal-ids for OVS.") +#define DESCRIBE_DOC_NM_SETTING_VETH_PEER N_("This property specifies the peer interface name of the veth. This property is mandatory.") diff --git a/src/libnmc-setting/settings-docs.xsl b/src/libnmc-setting/settings-docs.xsl deleted file mode 100644 index 0d08a0c8..00000000 --- a/src/libnmc-setting/settings-docs.xsl +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - /* Generated file. Do not edit. */ - - - - - - - - - - - - - - - - - - - - #define DESCRIBE_DOC_NM_SETTING__ N_("") - - - - { "", setting_, }, - - - - - - \" - - - - - - - - diff --git a/src/libnmc-setting/tests/test-libnmc-setting.c b/src/libnmc-setting/tests/test-libnmc-setting.c index d34bf028..518e698c 100644 --- a/src/libnmc-setting/tests/test-libnmc-setting.c +++ b/src/libnmc-setting/tests/test-libnmc-setting.c @@ -169,7 +169,7 @@ test_client_import_wireguard_test0(void) gs_free_error GError *error = NULL; connection = - nm_vpn_wireguard_import(NM_BUILD_SRCDIR "/src/libnmc-setting/tests/wg-test0.conf", &error); + nm_conn_wireguard_import(NM_BUILD_SRCDIR "/src/libnmc-setting/tests/wg-test0.conf", &error); g_assert_no_error(error); @@ -231,7 +231,7 @@ test_client_import_wireguard_test1(void) { gs_free_error GError *error = NULL; - nm_vpn_wireguard_import(NM_BUILD_SRCDIR "/src/libnmc-setting/tests/wg-test1.conf", &error); + nm_conn_wireguard_import(NM_BUILD_SRCDIR "/src/libnmc-setting/tests/wg-test1.conf", &error); g_assert_error(error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); g_assert(g_str_has_prefix(error->message, "invalid secret 'PrivateKey'")); g_assert(g_str_has_suffix(error->message, "wg-test1.conf:2")); @@ -242,7 +242,7 @@ test_client_import_wireguard_test2(void) { gs_free_error GError *error = NULL; - nm_vpn_wireguard_import(NM_BUILD_SRCDIR "/src/libnmc-setting/tests/wg-test2.conf", &error); + nm_conn_wireguard_import(NM_BUILD_SRCDIR "/src/libnmc-setting/tests/wg-test2.conf", &error); g_assert_error(error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); g_assert(g_str_has_prefix(error->message, "unrecognized line at")); @@ -254,7 +254,7 @@ test_client_import_wireguard_test3(void) { gs_free_error GError *error = NULL; - nm_vpn_wireguard_import(NM_BUILD_SRCDIR "/src/libnmc-setting/tests/wg-test3.conf", &error); + nm_conn_wireguard_import(NM_BUILD_SRCDIR "/src/libnmc-setting/tests/wg-test3.conf", &error); g_assert_error(error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT); g_assert(g_str_has_prefix(error->message, "invalid value for 'ListenPort'")); g_assert(g_str_has_suffix(error->message, "wg-test3.conf:3")); @@ -265,7 +265,7 @@ test_client_import_wireguard_missing(void) { gs_free_error GError *error = NULL; - nm_vpn_wireguard_import(NM_BUILD_SRCDIR "/src/libnmc-setting/tests/wg-missing.conf", &error); + nm_conn_wireguard_import(NM_BUILD_SRCDIR "/src/libnmc-setting/tests/wg-missing.conf", &error); g_assert_error(error, G_FILE_ERROR, G_FILE_ERROR_NOENT); } diff --git a/src/linux-headers/mptcp.h b/src/linux-headers/mptcp.h new file mode 100644 index 00000000..ca502f1e --- /dev/null +++ b/src/linux-headers/mptcp.h @@ -0,0 +1,232 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +#ifndef _MPTCP_H +#define _MPTCP_H + +#include +#include +#include /* for sockaddr_in */ +#include /* for sockaddr_in6 */ +#include /* for sockaddr_storage and sa_family */ + +#include /* for struct sockaddr */ + +#define MPTCP_SUBFLOW_FLAG_MCAP_REM _BITUL(0) +#define MPTCP_SUBFLOW_FLAG_MCAP_LOC _BITUL(1) +#define MPTCP_SUBFLOW_FLAG_JOIN_REM _BITUL(2) +#define MPTCP_SUBFLOW_FLAG_JOIN_LOC _BITUL(3) +#define MPTCP_SUBFLOW_FLAG_BKUP_REM _BITUL(4) +#define MPTCP_SUBFLOW_FLAG_BKUP_LOC _BITUL(5) +#define MPTCP_SUBFLOW_FLAG_FULLY_ESTABLISHED _BITUL(6) +#define MPTCP_SUBFLOW_FLAG_CONNECTED _BITUL(7) +#define MPTCP_SUBFLOW_FLAG_MAPVALID _BITUL(8) + +enum { + MPTCP_SUBFLOW_ATTR_UNSPEC, + MPTCP_SUBFLOW_ATTR_TOKEN_REM, + MPTCP_SUBFLOW_ATTR_TOKEN_LOC, + MPTCP_SUBFLOW_ATTR_RELWRITE_SEQ, + MPTCP_SUBFLOW_ATTR_MAP_SEQ, + MPTCP_SUBFLOW_ATTR_MAP_SFSEQ, + MPTCP_SUBFLOW_ATTR_SSN_OFFSET, + MPTCP_SUBFLOW_ATTR_MAP_DATALEN, + MPTCP_SUBFLOW_ATTR_FLAGS, + MPTCP_SUBFLOW_ATTR_ID_REM, + MPTCP_SUBFLOW_ATTR_ID_LOC, + MPTCP_SUBFLOW_ATTR_PAD, + __MPTCP_SUBFLOW_ATTR_MAX +}; + +#define MPTCP_SUBFLOW_ATTR_MAX (__MPTCP_SUBFLOW_ATTR_MAX - 1) + +/* netlink interface */ +#define MPTCP_PM_NAME "mptcp_pm" +#define MPTCP_PM_CMD_GRP_NAME "mptcp_pm_cmds" +#define MPTCP_PM_EV_GRP_NAME "mptcp_pm_events" +#define MPTCP_PM_VER 0x1 + +/* + * ATTR types defined for MPTCP + */ +enum { + MPTCP_PM_ATTR_UNSPEC, + + MPTCP_PM_ATTR_ADDR, /* nested address */ + MPTCP_PM_ATTR_RCV_ADD_ADDRS, /* u32 */ + MPTCP_PM_ATTR_SUBFLOWS, /* u32 */ + + __MPTCP_PM_ATTR_MAX +}; + +#define MPTCP_PM_ATTR_MAX (__MPTCP_PM_ATTR_MAX - 1) + +enum { + MPTCP_PM_ADDR_ATTR_UNSPEC, + + MPTCP_PM_ADDR_ATTR_FAMILY, /* u16 */ + MPTCP_PM_ADDR_ATTR_ID, /* u8 */ + MPTCP_PM_ADDR_ATTR_ADDR4, /* struct in_addr */ + MPTCP_PM_ADDR_ATTR_ADDR6, /* struct in6_addr */ + MPTCP_PM_ADDR_ATTR_PORT, /* u16 */ + MPTCP_PM_ADDR_ATTR_FLAGS, /* u32 */ + MPTCP_PM_ADDR_ATTR_IF_IDX, /* s32 */ + + __MPTCP_PM_ADDR_ATTR_MAX +}; + +#define MPTCP_PM_ADDR_ATTR_MAX (__MPTCP_PM_ADDR_ATTR_MAX - 1) + +#define MPTCP_PM_ADDR_FLAG_SIGNAL (1 << 0) +#define MPTCP_PM_ADDR_FLAG_SUBFLOW (1 << 1) +#define MPTCP_PM_ADDR_FLAG_BACKUP (1 << 2) +#define MPTCP_PM_ADDR_FLAG_FULLMESH (1 << 3) +#define MPTCP_PM_ADDR_FLAG_IMPLICIT (1 << 4) + +enum { + MPTCP_PM_CMD_UNSPEC, + + MPTCP_PM_CMD_ADD_ADDR, + MPTCP_PM_CMD_DEL_ADDR, + MPTCP_PM_CMD_GET_ADDR, + MPTCP_PM_CMD_FLUSH_ADDRS, + MPTCP_PM_CMD_SET_LIMITS, + MPTCP_PM_CMD_GET_LIMITS, + MPTCP_PM_CMD_SET_FLAGS, + + __MPTCP_PM_CMD_AFTER_LAST +}; + +#define MPTCP_INFO_FLAG_FALLBACK _BITUL(0) +#define MPTCP_INFO_FLAG_REMOTE_KEY_RECEIVED _BITUL(1) + +struct mptcp_info { + __u8 mptcpi_subflows; + __u8 mptcpi_add_addr_signal; + __u8 mptcpi_add_addr_accepted; + __u8 mptcpi_subflows_max; + __u8 mptcpi_add_addr_signal_max; + __u8 mptcpi_add_addr_accepted_max; + __u32 mptcpi_flags; + __u32 mptcpi_token; + __u64 mptcpi_write_seq; + __u64 mptcpi_snd_una; + __u64 mptcpi_rcv_nxt; + __u8 mptcpi_local_addr_used; + __u8 mptcpi_local_addr_max; + __u8 mptcpi_csum_enabled; +}; + +/* + * MPTCP_EVENT_CREATED: token, family, saddr4 | saddr6, daddr4 | daddr6, + * sport, dport + * A new MPTCP connection has been created. It is the good time to allocate + * memory and send ADD_ADDR if needed. Depending on the traffic-patterns + * it can take a long time until the MPTCP_EVENT_ESTABLISHED is sent. + * + * MPTCP_EVENT_ESTABLISHED: token, family, saddr4 | saddr6, daddr4 | daddr6, + * sport, dport + * A MPTCP connection is established (can start new subflows). + * + * MPTCP_EVENT_CLOSED: token + * A MPTCP connection has stopped. + * + * MPTCP_EVENT_ANNOUNCED: token, rem_id, family, daddr4 | daddr6 [, dport] + * A new address has been announced by the peer. + * + * MPTCP_EVENT_REMOVED: token, rem_id + * An address has been lost by the peer. + * + * MPTCP_EVENT_SUB_ESTABLISHED: token, family, loc_id, rem_id, + * saddr4 | saddr6, daddr4 | daddr6, sport, + * dport, backup, if_idx [, error] + * A new subflow has been established. 'error' should not be set. + * + * MPTCP_EVENT_SUB_CLOSED: token, family, loc_id, rem_id, saddr4 | saddr6, + * daddr4 | daddr6, sport, dport, backup, if_idx + * [, error] + * A subflow has been closed. An error (copy of sk_err) could be set if an + * error has been detected for this subflow. + * + * MPTCP_EVENT_SUB_PRIORITY: token, family, loc_id, rem_id, saddr4 | saddr6, + * daddr4 | daddr6, sport, dport, backup, if_idx + * [, error] + * The priority of a subflow has changed. 'error' should not be set. + */ +enum mptcp_event_type { + MPTCP_EVENT_UNSPEC = 0, + MPTCP_EVENT_CREATED = 1, + MPTCP_EVENT_ESTABLISHED = 2, + MPTCP_EVENT_CLOSED = 3, + + MPTCP_EVENT_ANNOUNCED = 6, + MPTCP_EVENT_REMOVED = 7, + + MPTCP_EVENT_SUB_ESTABLISHED = 10, + MPTCP_EVENT_SUB_CLOSED = 11, + + MPTCP_EVENT_SUB_PRIORITY = 13, +}; + +enum mptcp_event_attr { + MPTCP_ATTR_UNSPEC = 0, + + MPTCP_ATTR_TOKEN, /* u32 */ + MPTCP_ATTR_FAMILY, /* u16 */ + MPTCP_ATTR_LOC_ID, /* u8 */ + MPTCP_ATTR_REM_ID, /* u8 */ + MPTCP_ATTR_SADDR4, /* be32 */ + MPTCP_ATTR_SADDR6, /* struct in6_addr */ + MPTCP_ATTR_DADDR4, /* be32 */ + MPTCP_ATTR_DADDR6, /* struct in6_addr */ + MPTCP_ATTR_SPORT, /* be16 */ + MPTCP_ATTR_DPORT, /* be16 */ + MPTCP_ATTR_BACKUP, /* u8 */ + MPTCP_ATTR_ERROR, /* u8 */ + MPTCP_ATTR_FLAGS, /* u16 */ + MPTCP_ATTR_TIMEOUT, /* u32 */ + MPTCP_ATTR_IF_IDX, /* s32 */ + MPTCP_ATTR_RESET_REASON,/* u32 */ + MPTCP_ATTR_RESET_FLAGS, /* u32 */ + + __MPTCP_ATTR_AFTER_LAST +}; + +#define MPTCP_ATTR_MAX (__MPTCP_ATTR_AFTER_LAST - 1) + +/* MPTCP Reset reason codes, rfc8684 */ +#define MPTCP_RST_EUNSPEC 0 +#define MPTCP_RST_EMPTCP 1 +#define MPTCP_RST_ERESOURCE 2 +#define MPTCP_RST_EPROHIBIT 3 +#define MPTCP_RST_EWQ2BIG 4 +#define MPTCP_RST_EBADPERF 5 +#define MPTCP_RST_EMIDDLEBOX 6 + +struct mptcp_subflow_data { + __u32 size_subflow_data; /* size of this structure in userspace */ + __u32 num_subflows; /* must be 0, set by kernel */ + __u32 size_kernel; /* must be 0, set by kernel */ + __u32 size_user; /* size of one element in data[] */ +} __attribute__((aligned(8))); + +struct mptcp_subflow_addrs { + union { + __kernel_sa_family_t sa_family; + struct sockaddr sa_local; + struct sockaddr_in sin_local; + struct sockaddr_in6 sin6_local; + struct __kernel_sockaddr_storage ss_local; + }; + union { + struct sockaddr sa_remote; + struct sockaddr_in sin_remote; + struct sockaddr_in6 sin6_remote; + struct __kernel_sockaddr_storage ss_remote; + }; +}; + +/* MPTCP socket options */ +#define MPTCP_INFO 1 +#define MPTCP_TCPINFO 2 +#define MPTCP_SUBFLOW_ADDRS 3 + +#endif /* _MPTCP_H */ diff --git a/src/n-dhcp4/src/n-dhcp4-c-lease.c b/src/n-dhcp4/src/n-dhcp4-c-lease.c index bae2f674..be0d7886 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. */ @@ -351,32 +351,15 @@ _c_public_ int n_dhcp4_client_lease_query(NDhcp4ClientLease *lease, uint8_t opti * selected none of the others can be. * * Return: 0 on success, or a negative error code on failure. + * Returns -ENOTRECOVERABLE when called in an unexpected state. */ _c_public_ int n_dhcp4_client_lease_select(NDhcp4ClientLease *lease) { - NDhcp4ClientLease *l, *t_l; - NDhcp4ClientProbe *probe; - int r; - - /* XXX error handling, this must be an OFFER */ - if (!lease->probe) return -ENOTRECOVERABLE; if (lease->probe->current_lease) return -ENOTRECOVERABLE; - r = n_dhcp4_client_probe_transition_select(lease->probe, lease->message, n_dhcp4_gettime(CLOCK_BOOTTIME)); - if (r) - return r; - - /* - * Only one of the offered leases can be selected, so flush the list. - * All offered lease, including this one are now dead. - */ - probe = lease->probe; - c_list_for_each_entry_safe(l, t_l, &probe->lease_list, probe_link) - n_dhcp4_client_lease_unlink(l); - - return 0; + return n_dhcp4_client_probe_transition_select(lease->probe, lease->message, n_dhcp4_gettime(CLOCK_BOOTTIME)); } /** @@ -390,24 +373,15 @@ _c_public_ int n_dhcp4_client_lease_select(NDhcp4ClientLease *lease) { * can be accepted. * * Return: 0 on success, or a negative error code on failure. + * Returns -ENOTRECOVERABLE when called in an unexpected state. */ _c_public_ int n_dhcp4_client_lease_accept(NDhcp4ClientLease *lease) { - int r; - - /* XXX error handling, this must be an ACK */ - if (!lease->probe) return -ENOTRECOVERABLE; if (lease->probe->current_lease != lease) return -ENOTRECOVERABLE; - r = n_dhcp4_client_probe_transition_accept(lease->probe, lease->message); - if (r) - return r; - - n_dhcp4_client_lease_unlink(lease); - - return 0; + return n_dhcp4_client_probe_transition_accept(lease->probe, lease->message); } /** @@ -421,23 +395,13 @@ _c_public_ int n_dhcp4_client_lease_accept(NDhcp4ClientLease *lease) { * decline. * * Return: 0 on success, or a negative error code on failure. + * Returns -ENOTRECOVERABLE when called in an unexpected state. */ _c_public_ int n_dhcp4_client_lease_decline(NDhcp4ClientLease *lease, const char *error) { - int r; - - /* XXX: error handling, this must be an ACK */ - if (!lease->probe) return -ENOTRECOVERABLE; if (lease->probe->current_lease != lease) return -ENOTRECOVERABLE; - r = n_dhcp4_client_probe_transition_decline(lease->probe, lease->message, error, n_dhcp4_gettime(CLOCK_BOOTTIME)); - if (r) - return r; - - lease->probe->current_lease = n_dhcp4_client_lease_unref(lease->probe->current_lease); - n_dhcp4_client_lease_unlink(lease); - - return 0; + return n_dhcp4_client_probe_transition_decline(lease->probe, lease->message, error, n_dhcp4_gettime(CLOCK_BOOTTIME)); } diff --git a/src/n-dhcp4/src/n-dhcp4-c-probe.c b/src/n-dhcp4/src/n-dhcp4-c-probe.c index 283c1693..284aa428 100644 --- a/src/n-dhcp4/src/n-dhcp4-c-probe.c +++ b/src/n-dhcp4/src/n-dhcp4-c-probe.c @@ -1024,6 +1024,7 @@ static int n_dhcp4_client_probe_transition_nak(NDhcp4ClientProbe *probe) { int n_dhcp4_client_probe_transition_select(NDhcp4ClientProbe *probe, NDhcp4Incoming *offer, uint64_t ns_now) { _c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL; + NDhcp4ClientLease *l, *t_l; int r; switch (probe->state) { @@ -1042,11 +1043,16 @@ int n_dhcp4_client_probe_transition_select(NDhcp4ClientProbe *probe, NDhcp4Incom else request = NULL; /* consumed */ - /* XXX: ignore other offers */ - probe->state = N_DHCP4_CLIENT_PROBE_STATE_REQUESTING; - break; + /* + * Only one of the offered leases can be selected, so flush the list. + * All offered lease, including this one are now dead. + */ + c_list_for_each_entry_safe(l, t_l, &probe->lease_list, probe_link) + n_dhcp4_client_lease_unlink(l); + + return 0; case N_DHCP4_CLIENT_PROBE_STATE_INIT: case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT: case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING: @@ -1057,11 +1063,9 @@ int n_dhcp4_client_probe_transition_select(NDhcp4ClientProbe *probe, NDhcp4Incom case N_DHCP4_CLIENT_PROBE_STATE_REBINDING: case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED: default: - /* ignore */ - break; + /* user called in invalid state. Return error. */ + return -ENOTRECOVERABLE; } - - return 0; } /** @@ -1085,10 +1089,11 @@ int n_dhcp4_client_probe_transition_accept(NDhcp4ClientProbe *probe, NDhcp4Incom return r; probe->state = N_DHCP4_CLIENT_PROBE_STATE_BOUND; - + probe->ns_decline_restart_delay = 0; + n_dhcp4_client_lease_unlink(probe->current_lease); n_dhcp4_client_arm_timer(probe->client); - break; + return 0; case N_DHCP4_CLIENT_PROBE_STATE_INIT: case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT: @@ -1100,11 +1105,9 @@ int n_dhcp4_client_probe_transition_accept(NDhcp4ClientProbe *probe, NDhcp4Incom case N_DHCP4_CLIENT_PROBE_STATE_REBINDING: case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED: default: - /* ignore */ - break; + /* user called in invalid state. Return error. */ + return -ENOTRECOVERABLE; } - - return 0; } /** @@ -1126,9 +1129,22 @@ int n_dhcp4_client_probe_transition_decline(NDhcp4ClientProbe *probe, NDhcp4Inco else request = NULL; /* consumed */ - /* XXX: what state to transition to? */ + n_dhcp4_client_lease_unlink(probe->current_lease); + probe->current_lease = n_dhcp4_client_lease_unref(probe->current_lease); + + probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT; - break; + /* RFC2131, 3.1, 5.) The client SHOULD wait a minimum of ten seconds before restarting + * the configuration process to avoid excessive network traffic in case of looping. + * + * Let's go beyond that, and use an exponential backoff. */ + probe->ns_decline_restart_delay = C_CLAMP(probe->ns_decline_restart_delay * 2u, + UINT64_C(10) * UINT64_C(1000000000), + UINT64_C(300) * UINT64_C(1000000000)); + probe->ns_deferred = n_dhcp4_gettime(CLOCK_BOOTTIME) + probe->ns_decline_restart_delay; + + n_dhcp4_client_arm_timer(probe->client); + return 0; case N_DHCP4_CLIENT_PROBE_STATE_INIT: case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT: @@ -1140,11 +1156,9 @@ int n_dhcp4_client_probe_transition_decline(NDhcp4ClientProbe *probe, NDhcp4Inco case N_DHCP4_CLIENT_PROBE_STATE_REBINDING: case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED: default: - /* ignore */ - break; + /* user called in invalid state. Return error. */ + return -ENOTRECOVERABLE; } - - return 0; } /** diff --git a/src/n-dhcp4/src/n-dhcp4-client.c b/src/n-dhcp4/src/n-dhcp4-client.c index 1dedbf30..3b4a70c8 100644 --- a/src/n-dhcp4/src/n-dhcp4-client.c +++ b/src/n-dhcp4/src/n-dhcp4-client.c @@ -214,8 +214,8 @@ _c_public_ void n_dhcp4_client_config_set_mac(NDhcp4ClientConfig *config, const _c_public_ void n_dhcp4_client_config_set_broadcast_mac(NDhcp4ClientConfig *config, const uint8_t *mac, size_t n_mac) { config->n_broadcast_mac = n_mac; - if (n_mac > sizeof(config->mac)) - n_mac = sizeof(config->mac); + if (n_mac > sizeof(config->broadcast_mac)) + n_mac = sizeof(config->broadcast_mac); memcpy(config->broadcast_mac, mac, n_mac); } diff --git a/src/n-dhcp4/src/n-dhcp4-private.h b/src/n-dhcp4/src/n-dhcp4-private.h index 858c3d3a..6b366884 100644 --- a/src/n-dhcp4/src/n-dhcp4-private.h +++ b/src/n-dhcp4/src/n-dhcp4-private.h @@ -378,6 +378,7 @@ struct NDhcp4ClientProbe { uint64_t ns_deferred; /* timeout for deferred action */ uint64_t ns_reinit; uint64_t ns_nak_restart_delay; /* restart delay after a nak */ + uint64_t ns_decline_restart_delay; /* restart delay after a decline */ NDhcp4ClientLease *current_lease; /* current lease */ NDhcp4CConnection connection; /* client connection wrapper */ diff --git a/src/nm-cloud-setup/nmcs-provider-aliyun.c b/src/nm-cloud-setup/nmcs-provider-aliyun.c index 1a5e5459..34ab5ecc 100644 --- a/src/nm-cloud-setup/nmcs-provider-aliyun.c +++ b/src/nm-cloud-setup/nmcs-provider-aliyun.c @@ -203,7 +203,7 @@ _get_config_fetch_done_cb(NMHttpClient *http_client, g_bytes_get_data(response, NULL), NULL, &netmask_bin)) { - config_iface_data->cidr_prefix = nm_utils_ip4_netmask_to_prefix(netmask_bin); + config_iface_data->cidr_prefix = _nm_utils_ip4_netmask_to_prefix(netmask_bin); }; break; diff --git a/src/nm-daemon-helper/nm-daemon-helper.c b/src/nm-daemon-helper/nm-daemon-helper.c index 21a71e3c..a101bf9b 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 #include #include @@ -10,8 +12,6 @@ #include #endif -#include "libnm-std-aux/nm-std-aux.h" - enum { RETURN_SUCCESS = 0, RETURN_INVALID_CMD = 1, diff --git a/src/nm-dispatcher/nm-dispatcher.c b/src/nm-dispatcher/nm-dispatcher.c index aeecaa9b..4cf662c4 100644 --- a/src/nm-dispatcher/nm-dispatcher.c +++ b/src/nm-dispatcher/nm-dispatcher.c @@ -1138,25 +1138,25 @@ _initial_setup(int *p_argc, char ***p_argv, GError **error) GOptionContext *opt_ctx; gboolean arg_debug = FALSE; GOptionEntry entries[] = {{ - "debug", - 0, - 0, - G_OPTION_ARG_NONE, - &arg_debug, - "Output to console rather than syslog", - NULL, + "debug", + 0, + 0, + G_OPTION_ARG_NONE, + &arg_debug, + "Output to console rather than syslog", + NULL, }, - { - "persist", - 0, - 0, - G_OPTION_ARG_NONE, - &gl.persist, - "Don't quit after a short timeout", - NULL, + { + "persist", + 0, + 0, + G_OPTION_ARG_NONE, + &gl.persist, + "Don't quit after a short timeout", + NULL, }, - { - NULL, + { + NULL, }}; gboolean success; diff --git a/src/nm-initrd-generator/nm-initrd-generator.c b/src/nm-initrd-generator/nm-initrd-generator.c index 981cb14b..09f8baf2 100644 --- a/src/nm-initrd-generator/nm-initrd-generator.c +++ b/src/nm-initrd-generator/nm-initrd-generator.c @@ -25,6 +25,18 @@ /*****************************************************************************/ +static void +add_keyfile_comment(GKeyFile *keyfile, char *reason) +{ + gs_free char *comment = NULL; + + comment = g_strdup_printf(" Created by nm-initrd-generator%s%s%s", + reason ? " (" : "", + reason ? reason : "", + reason ? ")" : ""); + g_key_file_set_comment(keyfile, NULL, NULL, comment, NULL); +} + static void output_conn(gpointer key, gpointer value, gpointer user_data) { @@ -48,9 +60,12 @@ output_conn(gpointer key, gpointer value, gpointer user_data) goto err_out; file = nm_keyfile_write(connection, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error); - if (file == NULL) + if (!file) goto err_out; + if (connections_dir) + add_keyfile_comment(file, NULL); + data = g_key_file_to_data(file, &len, &error); if (!data) goto err_out; @@ -88,55 +103,57 @@ main(int argc, char *argv[]) gboolean dump_to_stdout = FALSE; gs_strfreev char **remaining = NULL; GOptionEntry option_entries[] = { - {"connections-dir", - 'c', - 0, - G_OPTION_ARG_FILENAME, - &connections_dir, - "Output connection directory", - NM_KEYFILE_PATH_NAME_RUN}, - {"persistent-connections-dir", - 'p', - 0, - G_OPTION_ARG_FILENAME, - &etc_connections_dir, - "Persistent connection directory", - NM_KEYFILE_PATH_NAME_ETC_DEFAULT}, - {"initrd-data-dir", - 'i', - 0, - G_OPTION_ARG_FILENAME, - &initrd_dir, - "Output initrd data directory", - DEFAULT_INITRD_DATA_DIR}, - {"sysfs-dir", - 'd', - 0, - G_OPTION_ARG_FILENAME, - &sysfs_dir, - "The sysfs mount point", - DEFAULT_SYSFS_DIR}, - {"run-config-dir", - 'r', - 0, - G_OPTION_ARG_FILENAME, - &run_config_dir, - "Output config directory", - DEFAULT_RUN_CONFIG_DIR}, - {"stdout", - 's', - 0, - G_OPTION_ARG_NONE, - &dump_to_stdout, - "Dump connections to standard output", - NULL}, - {G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &remaining, NULL, NULL}, - {NULL}}; + {"connections-dir", + 'c', + 0, + G_OPTION_ARG_FILENAME, + &connections_dir, + "Output connection directory", + NM_KEYFILE_PATH_NAME_RUN}, + {"persistent-connections-dir", + 'p', + 0, + G_OPTION_ARG_FILENAME, + &etc_connections_dir, + "Persistent connection directory", + NM_KEYFILE_PATH_NAME_ETC_DEFAULT}, + {"initrd-data-dir", + 'i', + 0, + G_OPTION_ARG_FILENAME, + &initrd_dir, + "Output initrd data directory", + DEFAULT_INITRD_DATA_DIR}, + {"sysfs-dir", + 'd', + 0, + G_OPTION_ARG_FILENAME, + &sysfs_dir, + "The sysfs mount point", + DEFAULT_SYSFS_DIR}, + {"run-config-dir", + 'r', + 0, + G_OPTION_ARG_FILENAME, + &run_config_dir, + "Output config directory", + DEFAULT_RUN_CONFIG_DIR}, + {"stdout", + 's', + 0, + G_OPTION_ARG_NONE, + &dump_to_stdout, + "Dump connections to standard output", + NULL}, + {G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &remaining, NULL, NULL}, + {NULL}}; nm_auto_free_option_context GOptionContext *option_context = NULL; gs_free_error GError *error = NULL; gs_free char *hostname = NULL; int errsv; gint64 carrier_timeout_sec = 0; + gs_unref_array GArray *confs = NULL; + guint i; option_context = g_option_context_new( "-- [ip=...] [rd.route=...] [bridge=...] [bond=...] [team=...] [vlan=...] " @@ -178,15 +195,57 @@ main(int argc, char *argv[]) &hostname, &carrier_timeout_sec); + confs = g_array_new(FALSE, FALSE, sizeof(NMUtilsNamedValue)); + g_array_set_clear_func(confs, (GDestroyNotify) nm_utils_named_value_clear_with_g_free); + + { + nm_auto_unref_keyfile GKeyFile *keyfile = NULL; + NMUtilsNamedValue v; + + keyfile = g_key_file_new(); + g_key_file_set_list_separator(keyfile, NM_CONFIG_KEYFILE_LIST_SEPARATOR); + + g_key_file_set_value(keyfile, + NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE "-15-carrier-timeout", + NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE, + "*"); + g_key_file_set_int64(keyfile, + NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE "-15-carrier-timeout", + NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT, + (carrier_timeout_sec != 0 ? carrier_timeout_sec : 10) * 1000); + if (carrier_timeout_sec == 0) { + g_key_file_set_value(keyfile, + NM_CONFIG_KEYFILE_GROUP_CONFIG, + NM_CONFIG_KEYFILE_KEY_CONFIG_ENABLE, + "env:initrd"); + } + + if (!dump_to_stdout) { + add_keyfile_comment(keyfile, + carrier_timeout_sec == 0 ? "default initrd carrier timeout" + : "from \"rd.net.timeout.carrier\""); + } + + v = (NMUtilsNamedValue){ + .name = g_strdup_printf("%s/15-carrier-timeout.conf", run_config_dir), + .value_str = g_key_file_to_data(keyfile, NULL, NULL), + }; + g_array_append_val(confs, v); + } + if (dump_to_stdout) { nm_clear_g_free(&connections_dir); nm_clear_g_free(&initrd_dir); nm_clear_g_free(&run_config_dir); if (hostname) g_print("\n*** Hostname '%s' ***\n", hostname); - if (carrier_timeout_sec != 0) - g_print("\n*** Carrier Wait Timeout %" G_GINT64_FORMAT " sec ***\n", - carrier_timeout_sec); + + for (i = 0; i < confs->len; i++) { + NMUtilsNamedValue *v = &g_array_index(confs, NMUtilsNamedValue, i); + gs_free char *name = g_path_get_basename(v->name); + + g_print("\n*** Configuration '%s' ***\n\n%s\n", name, v->value_str); + } } else { if (g_mkdir_with_parents(connections_dir, 0755) != 0) { errsv = errno; @@ -216,25 +275,12 @@ main(int argc, char *argv[]) return 1; } } - if (carrier_timeout_sec != 0) { - nm_auto_unref_keyfile GKeyFile *keyfile = NULL; - gs_free char *filename = NULL; - keyfile = g_key_file_new(); - g_key_file_set_list_separator(keyfile, NM_CONFIG_KEYFILE_LIST_SEPARATOR); - filename = g_strdup_printf("%s/15-carrier-timeout.conf", run_config_dir); + for (i = 0; i < confs->len; i++) { + NMUtilsNamedValue *v = &g_array_index(confs, NMUtilsNamedValue, i); - g_key_file_set_value(keyfile, - NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE "-15-carrier-timeout", - NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE, - "*"); - g_key_file_set_int64(keyfile, - NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE "-15-carrier-timeout", - NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT, - carrier_timeout_sec * 1000); - - if (!g_key_file_save_to_file(keyfile, filename, &error)) { - _LOGW(LOGD_CORE, "%s: %s", filename, error->message); + if (!g_file_set_contents(v->name, v->value_str, strlen(v->value_str), &error)) { + _LOGW(LOGD_CORE, "%s: %s", v->name, error->message); return 1; } } diff --git a/src/nm-initrd-generator/nmi-cmdline-reader.c b/src/nm-initrd-generator/nmi-cmdline-reader.c index 412c7510..34b19e45 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" /*****************************************************************************/ @@ -134,7 +133,7 @@ reader_create_connection(Reader *reader, NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, - (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, + (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64, NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, reader->ignore_auto_dns, NM_SETTING_IP_CONFIG_DHCP_TIMEOUT, @@ -535,8 +534,8 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument) int client_ip_prefix = -1; gboolean clear_ip4_required_timeout = TRUE; const char *dns[2] = { - NULL, - NULL, + NULL, + NULL, }; int dns_addr_family[2] = { AF_UNSPEC, @@ -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) { @@ -634,7 +633,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument) NMIPAddr addr; if (is_ipv4 && nm_utils_parse_inaddr_bin(AF_INET, netmask, NULL, &addr)) - client_ip_prefix = nm_utils_ip4_netmask_to_prefix(addr.addr4); + client_ip_prefix = _nm_utils_ip4_netmask_to_prefix(addr.addr4); else client_ip_prefix = _nm_utils_ascii_str_to_int64(netmask, 10, 0, is_ipv4 ? 32 : 128, -1); diff --git a/src/nm-initrd-generator/nmi-dt-reader.c b/src/nm-initrd-generator/nmi-dt-reader.c index 8bd591a8..554f5c4d 100644 --- a/src/nm-initrd-generator/nmi-dt-reader.c +++ b/src/nm-initrd-generator/nmi-dt-reader.c @@ -258,7 +258,7 @@ nmi_dt_reader_parse(const char *sysfs_dir) g_object_set(s_ip6, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, - (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, + (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64, NULL); if (!bootp && dt_get_property(base, "chosen", "bootp-response", NULL, NULL)) @@ -288,7 +288,7 @@ nmi_dt_reader_parse(const char *sysfs_dir) guint32 netmask_v4; nm_ip_address_get_address_binary(netmask, &netmask_v4); - prefix = nm_utils_ip4_netmask_to_prefix(netmask_v4); + prefix = _nm_utils_ip4_netmask_to_prefix(netmask_v4); } if (prefix == -1) diff --git a/src/nm-initrd-generator/nmi-ibft-reader.c b/src/nm-initrd-generator/nmi-ibft-reader.c index 196bb141..5e4b1bb3 100644 --- a/src/nm-initrd-generator/nmi-ibft-reader.c +++ b/src/nm-initrd-generator/nmi-ibft-reader.c @@ -164,7 +164,7 @@ ip_setting_add_from_block(GHashTable *nic, NMConnection *connection, GError **er g_object_set(s_ip6, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, - (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, + (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64, NULL); } diff --git a/src/nm-online/nm-online.c b/src/nm-online/nm-online.c index ee4477db..0807270e 100644 --- a/src/nm-online/nm-online.c +++ b/src/nm-online/nm-online.c @@ -233,30 +233,30 @@ main(int argc, char *argv[]) GOptionContext *opt_ctx = NULL; gboolean success; GOptionEntry options[] = { - {"quiet", 'q', 0, G_OPTION_ARG_NONE, &data.quiet, N_("Don't print anything"), NULL}, - {"wait-for-startup", - 's', - 0, - G_OPTION_ARG_NONE, - &data.wait_startup, - N_("Wait for NetworkManager startup instead of a connection"), - NULL}, - {"timeout", - 't', - 0, - G_OPTION_ARG_INT, - &t_secs, - N_("Time to wait for a connection, in seconds (without the option, default value is 30). " + {"quiet", 'q', 0, G_OPTION_ARG_NONE, &data.quiet, N_("Don't print anything"), NULL}, + {"wait-for-startup", + 's', + 0, + G_OPTION_ARG_NONE, + &data.wait_startup, + N_("Wait for NetworkManager startup instead of a connection"), + NULL}, + {"timeout", + 't', + 0, + G_OPTION_ARG_INT, + &t_secs, + N_("Time to wait for a connection, in seconds (without the option, default value is 30). " "Maximum value is 2073600 seconds."), - ""}, - {"exit", - 'x', - 0, - G_OPTION_ARG_NONE, - &data.exit_no_nm, - N_("Exit immediately if NetworkManager is not running or connecting"), - NULL}, - {NULL}, + ""}, + {"exit", + 'x', + 0, + G_OPTION_ARG_NONE, + &data.exit_no_nm, + N_("Exit immediately if NetworkManager is not running or connecting"), + NULL}, + {NULL}, }; /* Set locale to be able to use environment variables */ diff --git a/src/nm-priv-helper/nm-priv-helper.c b/src/nm-priv-helper/nm-priv-helper.c index ec064bca..e29113b1 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 f42f76e4..ff4c15c3 100644 --- a/src/nmcli/common.c +++ b/src/nmcli/common.c @@ -16,6 +16,8 @@ #include #include #endif +#include + #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); @@ -536,8 +539,6 @@ nmc_find_active_connection(const GPtrArray *active_cons, NMActiveConnection *candidate = g_ptr_array_index(active_cons, i); const char *v, *v_num; - con = nm_active_connection_get_connection(candidate); - /* When filter_type is NULL, compare connection ID (filter_val) * against all types. Otherwise, only compare against the specific * type. If 'path' or 'apath' filter types are specified, comparison @@ -559,6 +560,8 @@ nmc_find_active_connection(const GPtrArray *active_cons, goto found; } + con = nm_active_connection_get_connection(candidate); + if (NM_IN_STRSET(filter_type, NULL, "path")) { v = con ? nm_connection_get_path(NM_CONNECTION(con)) : NULL; v_num = nm_utils_dbus_path_get_last_component(v); @@ -569,7 +572,7 @@ nmc_find_active_connection(const GPtrArray *active_cons, } if (NM_IN_STRSET(filter_type, NULL, "filename")) { - v = nm_remote_connection_get_filename(con); + v = con ? nm_remote_connection_get_filename(con) : NULL; if (complete && (filter_type || *filter_val)) nmc_complete_strings(filter_val, v); if (nm_streq0(filter_val, v)) @@ -926,7 +929,8 @@ read_again: } } else if (!rl_string) { /* Ctrl-D, exit */ - nmc_exit(); + if (g_main_loop_is_running(loop)) + nmc_exit(); } /* Return NULL, not empty string */ @@ -1010,7 +1014,7 @@ nmc_readline_echo(const NmcConfig *nmc_config, gboolean echo_on, const char *pro #if HAVE_READLINE_HISTORY nm_auto_free HISTORY_STATE *saved_history = NULL; HISTORY_STATE passwd_history = { - 0, + 0, }; #else int start, curpos; @@ -1273,12 +1277,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 d093823b..8c6ebd98 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 #endif #include +#include #include "libnm-glib-aux/nm-dbus-aux.h" #include "libnmc-base/nm-client-utils.h" @@ -51,6 +52,7 @@ typedef struct _OptionInfo { NMConnection *connection, const struct _OptionInfo *option, const char *value, + gboolean allow_reset, GError **error); CompEntryFunc generator_func; } OptionInfo; @@ -137,6 +139,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 +1069,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 +1430,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 +2069,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 +2088,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 +2236,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 +2381,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 ' */ if (!nmc->mode_specified) @@ -2315,7 +2437,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 +2574,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 +3398,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 +4048,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); } @@ -4052,11 +4174,14 @@ enable_options(const char *setting_name, const char *property, const char *const for (i = 0; i < nm_meta_property_typ_data_bond.nested_len; i++) { const NMMetaNestedPropertyInfo *bi = &nm_meta_property_typ_data_bond.nested[i]; - if (bi->base.inf_flags & NM_META_PROPERTY_INF_FLAG_DONT_ASK && bi->base.property_alias - && g_strv_contains(opts, bi->base.property_alias)) - _dynamic_options_set((const NMMetaAbstractInfo *) bi, - PROPERTY_INF_FLAG_ENABLED, - PROPERTY_INF_FLAG_ENABLED); + if (opts) { + if (!bi->base.property_alias || !g_strv_contains(opts, bi->base.property_alias)) + continue; + } + + _dynamic_options_set((const NMMetaAbstractInfo *) bi, + PROPERTY_INF_FLAG_ENABLED | PROPERTY_INF_FLAG_DISABLED, + PROPERTY_INF_FLAG_ENABLED); } return; } @@ -4064,11 +4189,14 @@ enable_options(const char *setting_name, const char *property, const char *const if (!property_info->is_cli_option) g_return_if_reached(); - if (property_info->inf_flags & NM_META_PROPERTY_INF_FLAG_DONT_ASK - && property_info->property_alias && g_strv_contains(opts, property_info->property_alias)) - _dynamic_options_set((const NMMetaAbstractInfo *) property_info, - PROPERTY_INF_FLAG_ENABLED, - PROPERTY_INF_FLAG_ENABLED); + if (opts) { + if (!property_info->property_alias || !g_strv_contains(opts, property_info->property_alias)) + return; + } + + _dynamic_options_set((const NMMetaAbstractInfo *) property_info, + PROPERTY_INF_FLAG_ENABLED | PROPERTY_INF_FLAG_DISABLED, + PROPERTY_INF_FLAG_ENABLED); } /* @@ -4254,7 +4382,7 @@ set_option(NmCli *nmc, NULL, NULL); if (option && option->check_and_set) { - return option->check_and_set(nmc, connection, option, value, error); + return option->check_and_set(nmc, connection, option, value, allow_reset, error); } else if (value || allow_reset) { return set_property(nmc->client, connection, @@ -4380,21 +4508,63 @@ gen_func_bond_lacp_rate(const char *text, int state) /*****************************************************************************/ +static gboolean +enable_type_settings_and_options(NmCli *nmc, NMConnection *con, GError **error) +{ + const NMMetaSettingValidPartItem *const *type_settings; + const NMMetaSettingValidPartItem *const *slv_settings; + NMSettingConnection *s_con; + + s_con = nm_connection_get_setting_connection(con); + g_return_val_if_fail(s_con, FALSE); + + if (nm_setting_connection_get_slave_type(s_con)) + enable_options(NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_MASTER, NULL); + + if (NM_IN_STRSET(nm_setting_connection_get_connection_type(s_con), + NM_SETTING_BLUETOOTH_SETTING_NAME, + NM_SETTING_BOND_SETTING_NAME, + NM_SETTING_BRIDGE_SETTING_NAME, + NM_SETTING_DUMMY_SETTING_NAME, + NM_SETTING_OVS_BRIDGE_SETTING_NAME, + NM_SETTING_OVS_PATCH_SETTING_NAME, + NM_SETTING_OVS_PORT_SETTING_NAME, + NM_SETTING_TEAM_SETTING_NAME, + NM_SETTING_VETH_SETTING_NAME, + NM_SETTING_VRF_SETTING_NAME, + NM_SETTING_WIREGUARD_SETTING_NAME)) { + enable_options(NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_INTERFACE_NAME, + NULL); + } + + if (!con_settings(con, &type_settings, &slv_settings, error)) + return FALSE; + + ensure_settings(con, slv_settings); + ensure_settings(con, type_settings); + + /* For some software connection types we generate the interface name for the user. */ + set_default_interface_name(nmc, s_con); + + return TRUE; +} + static gboolean set_connection_type(NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, + gboolean allow_reset, GError **error) { - const NMMetaSettingValidPartItem *const *type_settings; - const NMMetaSettingValidPartItem *const *slv_settings; - GError *local = NULL; - const char *master[] = {"master", NULL}; - const char *slave_type = NULL; + GError *local = NULL; + const char *slave_type = NULL; value = check_valid_name_toplevel(value, &slave_type, &local); if (!value) { + if (!allow_reset) + return TRUE; g_set_error(error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, @@ -4414,16 +4584,6 @@ set_connection_type(NmCli *nmc, error)) { return FALSE; } - enable_options(NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_MASTER, master); - } - - /* ifname is mandatory for all connection types except virtual ones (bond, team, bridge, vlan) */ - if (NM_IN_STRSET(value, - NM_SETTING_BOND_SETTING_NAME, - NM_SETTING_TEAM_SETTING_NAME, - NM_SETTING_BRIDGE_SETTING_NAME, - NM_SETTING_VLAN_SETTING_NAME)) { - disable_options(NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_INTERFACE_NAME); } if (!set_property(nmc->client, @@ -4435,13 +4595,7 @@ set_connection_type(NmCli *nmc, error)) return FALSE; - if (!con_settings(con, &type_settings, &slv_settings, error)) - return FALSE; - - ensure_settings(con, slv_settings); - ensure_settings(con, type_settings); - - return TRUE; + return enable_type_settings_and_options(nmc, con, error); } static gboolean @@ -4449,12 +4603,15 @@ set_connection_iface(NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, + gboolean allow_reset, GError **error) { if (value) { /* Special value of '*' means no specific interface name */ if (nm_streq(value, "*")) value = NULL; + } else if (!allow_reset) { + return TRUE; } return set_property(nmc->client, @@ -4471,6 +4628,7 @@ set_connection_master(NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, + gboolean allow_reset, GError **error) { const GPtrArray *connections; @@ -4481,6 +4639,8 @@ set_connection_master(NmCli *nmc, g_return_val_if_fail(s_con, FALSE); if (!value) { + if (!allow_reset) + return TRUE; g_set_error_literal(error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, @@ -4489,7 +4649,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, @@ -4516,10 +4676,10 @@ set_bond_option(NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, + gboolean allow_reset, GError **error) { NMSettingBond *s_bond; - gboolean success; gs_free char *name = NULL; char *p; @@ -4533,26 +4693,25 @@ set_bond_option(NmCli *nmc, } if (nm_str_is_empty(value)) { - nm_setting_bond_remove_option(s_bond, name); - success = TRUE; - } else - success = _nm_meta_setting_bond_add_option(NM_SETTING(s_bond), name, value, error); - - if (!success) - return FALSE; + if (allow_reset) { + nm_setting_bond_remove_option(s_bond, name); + return TRUE; + } + } else { + if (!_nm_meta_setting_bond_add_option(NM_SETTING(s_bond), name, value, error)) + return FALSE; + } - if (success) { - if (nm_streq(name, NM_SETTING_BOND_OPTION_MODE)) { - value = nmc_bond_validate_mode(value, error); - if (nm_streq(value, "active-backup")) { - enable_options(NM_SETTING_BOND_SETTING_NAME, - NM_SETTING_BOND_OPTIONS, - NM_MAKE_STRV("primary")); - } + if (nm_streq(name, NM_SETTING_BOND_OPTION_MODE)) { + value = nm_setting_bond_get_option_by_name(s_bond, name); + if (nm_streq(value, "active-backup")) { + enable_options(NM_SETTING_BOND_SETTING_NAME, + NM_SETTING_BOND_OPTIONS, + NM_MAKE_STRV("primary")); } } - return success; + return TRUE; } static gboolean @@ -4560,6 +4719,7 @@ set_bond_monitoring_mode(NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, + gboolean allow_reset, GError **error) { NMSettingBond *s_bond; @@ -4600,6 +4760,7 @@ set_bluetooth_type(NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, + gboolean allow_reset, GError **error) { NMSetting *setting; @@ -4648,6 +4809,7 @@ set_ip4_address(NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, + gboolean allow_reset, GError **error) { NMSettingIPConfig *s_ip4; @@ -4675,6 +4837,7 @@ set_ip6_address(NmCli *nmc, NMConnection *con, const OptionInfo *option, const char *value, + gboolean allow_reset, GError **error) { NMSettingIPConfig *s_ip6; @@ -5265,12 +5428,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 +5508,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) { @@ -5448,17 +5599,30 @@ ask_option(NmCli *nmc, NMConnection *connection, const NMMetaAbstractInfo *abstr GError *error = NULL; gs_free char *prompt = NULL; gboolean multi; + const char *setting_name, *property_name; const char *opt_prompt, *opt_def_hint; + gs_free char *def_hint = NULL; + gs_free char *property_val = NULL; NMMetaPropertyInfFlags inf_flags; + NMSetting *setting; _meta_abstract_get(abstract_info, NULL, - NULL, - NULL, + &setting_name, + &property_name, NULL, &inf_flags, &opt_prompt, &opt_def_hint); + + if (!opt_def_hint) { + setting = nm_connection_get_setting_by_name(connection, setting_name); + if (setting) + property_val = nmc_setting_get_property_parsable(setting, property_name, NULL); + if (property_val) + opt_def_hint = def_hint = g_strdup_printf("[%s]", property_val); + } + prompt = g_strjoin("", gettext(opt_prompt), opt_def_hint ? " " : "", opt_def_hint ?: "", ": ", NULL); @@ -5469,8 +5633,6 @@ ask_option(NmCli *nmc, NMConnection *connection, const NMMetaAbstractInfo *abstr again: value = nmc_readline(&nmc->nmc_config, "%s", prompt); - if (multi && !value) - return; if (!set_option(nmc, connection, abstract_info, value, FALSE, &error)) { g_printerr("%s\n", error->message); @@ -5490,7 +5652,9 @@ connection_get_base_meta_setting_type(NMConnection *connection) const NMMetaSettingInfoEditor *editor; connection_type = nm_connection_get_connection_type(connection); - nm_assert(connection_type); + if (!connection_type) + return NM_META_SETTING_TYPE_UNKNOWN; + base_setting = nm_connection_get_setting_by_name(connection, connection_type); nm_assert(base_setting); editor = nm_meta_setting_info_editor_find_by_setting(base_setting); @@ -5546,10 +5710,15 @@ questionnaire_mandatory(NmCli *nmc, NMConnection *connection) NMMetaSettingType s, base; /* First ask connection properties */ - questionnaire_mandatory_ask_setting(nmc, connection, NM_META_SETTING_TYPE_CONNECTION); + while (1) { + base = connection_get_base_meta_setting_type(connection); + if (base != NM_META_SETTING_TYPE_UNKNOWN) + break; + enable_options(NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_TYPE, NULL); + questionnaire_mandatory_ask_setting(nmc, connection, NM_META_SETTING_TYPE_CONNECTION); + } /* Ask properties of the base setting */ - base = connection_get_base_meta_setting_type(connection); questionnaire_mandatory_ask_setting(nmc, connection, base); /* Remaining settings */ @@ -5564,16 +5733,14 @@ want_provide_opt_args(const NmcConfig *nmc_config, const char *type, guint num) { gs_free char *answer = NULL; + /* Don't ask to ask. */ + if (num == 1) + return TRUE; + /* Ask for optional arguments. */ - g_print(ngettext("There is %d optional setting for %s.\n", - "There are %d optional settings for %s.\n", - num), - (int) num, - type); - answer = nmc_readline( - nmc_config, - ngettext("Do you want to provide it? %s", "Do you want to provide them? %s", num), - prompt_yes_no(TRUE, NULL)); + g_print(_("There are %d optional settings for %s.\n"), (int) num, type); + answer = + nmc_readline(nmc_config, _("Do you want to provide them? %s"), prompt_yes_no(TRUE, NULL)); nm_strstrip(answer); return !answer || matches(answer, WORD_YES); } @@ -5661,6 +5828,20 @@ again: return TRUE; } +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) { @@ -5722,6 +5903,12 @@ read_properties: if (nmc->complete) goto finish; + if (!enable_type_settings_and_options(nmc, connection, &error)) { + g_string_assign(nmc->return_text, error->message); + nmc->return_value = error->code; + goto finish; + } + /* Now ask user for the rest of the mandatory options. */ if (nmc->ask) questionnaire_mandatory(nmc, connection); @@ -5748,7 +5935,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)); @@ -5757,9 +5944,6 @@ read_properties: } } - /* For some software connection types we generate the interface name for the user. */ - set_default_interface_name(nmc, s_con); - /* Now see if there's something optional that needs to be asked for. * Keep asking until there's no more things to ask for. */ do { @@ -5813,11 +5997,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 +6019,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 +6353,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 +6370,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 +8516,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, @@ -8721,12 +8905,12 @@ do_connection_edit(const NMCCommand *cmd, NmCli *nmc, int argc, const char *cons gs_free_error GError *error = NULL; GError *err1 = NULL; nmc_arg_t exp_args[] = {{"type", TRUE, &type, FALSE}, - {"con-name", TRUE, &con_name, FALSE}, - {"id", TRUE, &con_id, FALSE}, - {"uuid", TRUE, &con_uuid, FALSE}, - {"path", TRUE, &con_path, FALSE}, - {"filename", TRUE, &con_filename, FALSE}, - {NULL}}; + {"con-name", TRUE, &con_name, FALSE}, + {"id", TRUE, &con_id, FALSE}, + {"uuid", TRUE, &con_uuid, FALSE}, + {"path", TRUE, &con_path, FALSE}, + {"filename", TRUE, &con_filename, FALSE}, + {NULL}}; next_arg(nmc, &argc, &argv, NULL); if (argc == 1 && nmc->complete) @@ -8750,7 +8934,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) { @@ -8931,11 +9115,24 @@ modify_connection_cb(GObject *connection, GAsyncResult *result, gpointer user_da quit(); } +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 +9148,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 +9458,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)) { @@ -9502,7 +9693,7 @@ do_connection_import(const NMCCommand *cmd, NmCli *nmc, int argc, const char *co } if (nm_streq(type, "wireguard")) - connection = nm_vpn_wireguard_import(filename, &error); + connection = nm_conn_wireguard_import(filename, &error); else { service_type = nm_vpn_plugin_info_list_find_service_type(nm_vpn_get_plugin_infos(), type); if (!service_type) { @@ -9768,7 +9959,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 +10006,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 +10032,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 +10096,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/devices.c b/src/nmcli/devices.c index be51731f..43bd3724 100644 --- a/src/nmcli/devices.c +++ b/src/nmcli/devices.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" @@ -1042,6 +1042,18 @@ usage_device_lldp(void) "used to list neighbors for a particular interface.\n\n")); } +static void +usage_device_checkpoint(void) +{ + g_printerr(_("Usage: nmcli device checkpoint { ARGUMENTS | help }\n" + "\n" + "ARGUMENTS := [--timeout ] -- COMMAND...\n" + "\n" + "Runs the command with a configuration checkpoint taken and asks for a\n" + "confirmation when finished. When the confirmation is not given, the\n" + "checkpoint is automatically restored after timeout.\n\n")); +} + static void quit(void) { @@ -1109,59 +1121,72 @@ nmc_complete_device(NMClient *client, const char *prefix, gboolean wifi_only) complete_device(devices, prefix, wifi_only); } -static GSList * -get_device_list(NmCli *nmc, int argc, const char *const *argv) +static void destroy_queue_element(gpointer data); + +static GPtrArray * +get_device_list(NmCli *nmc, int *argc, const char *const **argv) { - int arg_num = argc; + int arg_num; + const char *const *arg_ptr; + gs_strfreev char **arg_arr = NULL; - const char *const *arg_ptr = argv; NMDevice **devices; - GSList *queue = NULL; + GPtrArray *queue = NULL; NMDevice *device; int i; - if (argc == 0) { - if (nmc->ask) { - gs_free char *line = NULL; + if (*argc == 0 && nmc->ask) { + gs_free char *line = NULL; - line = nmc_readline(&nmc->nmc_config, PROMPT_INTERFACES); - nmc_string_to_arg_array(line, NULL, FALSE, &arg_arr, &arg_num); - arg_ptr = (const char *const *) arg_arr; - } - if (arg_num == 0) { - g_string_printf(nmc->return_text, _("Error: No interface specified.")); - nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; - goto error; - } + line = nmc_readline(&nmc->nmc_config, PROMPT_INTERFACES); + nmc_string_to_arg_array(line, NULL, FALSE, &arg_arr, &arg_num); + arg_ptr = (const char *const *) arg_arr; + + argc = &arg_num; + argv = &arg_ptr; + } + + if (*argc == 0) { + g_string_printf(nmc->return_text, _("Error: No interface specified.")); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + goto error; } devices = nmc_get_devices_sorted(nmc->client); - while (arg_num > 0) { - if (arg_num == 1 && nmc->complete) - complete_device(devices, *arg_ptr, FALSE); + while (*argc > 0) { + if (strcmp(**argv, "--") == 0) { + (*argc)--; + (*argv)++; + break; + } + + if (*argc == 1 && nmc->complete) + complete_device(devices, **argv, FALSE); device = NULL; for (i = 0; devices[i]; i++) { - if (!g_strcmp0(nm_device_get_iface(devices[i]), *arg_ptr)) { + if (!g_strcmp0(nm_device_get_iface(devices[i]), **argv)) { device = devices[i]; break; } } if (device) { - if (!g_slist_find(queue, device)) - queue = g_slist_prepend(queue, device); + if (!queue) + queue = g_ptr_array_new_with_free_func(destroy_queue_element); + if (!g_ptr_array_find(queue, device, NULL)) + g_ptr_array_add(queue, g_object_ref(device)); else - g_printerr(_("Warning: argument '%s' is duplicated.\n"), *arg_ptr); + g_printerr(_("Warning: argument '%s' is duplicated.\n"), **argv); } else { if (!nmc->complete) - g_printerr(_("Error: Device '%s' not found.\n"), *arg_ptr); + g_printerr(_("Error: Device '%s' not found.\n"), **argv); g_string_printf(nmc->return_text, _("Error: not all devices found.")); nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; } /* Take next argument */ - next_arg(nmc->ask ? NULL : nmc, &arg_num, &arg_ptr, NULL); + next_arg(nmc->ask ? NULL : nmc, argc, argv, NULL); } g_free(devices); @@ -2305,7 +2330,7 @@ do_device_connect(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const typedef struct { NmCli *nmc; - GSList *queue; + GPtrArray *queue; guint timeout_id; gboolean cmd_disconnect; GCancellable *cancellable; @@ -2329,7 +2354,7 @@ device_removed_cb(NMClient *client, NMDevice *device, DeviceCbInfo *info) /* Success: device has been removed. * It can also happen when disconnecting a software device. */ - if (!g_slist_find(info->queue, device)) + if (!g_ptr_array_find(info->queue, device, NULL)) return; if (info->cmd_disconnect) @@ -2342,7 +2367,7 @@ device_removed_cb(NMClient *client, NMDevice *device, DeviceCbInfo *info) static void disconnect_state_cb(NMDevice *device, GParamSpec *pspec, DeviceCbInfo *info) { - if (!g_slist_find(info->queue, device)) + if (!g_ptr_array_find(info->queue, device, NULL)) return; if (nm_device_get_state(device) <= NM_DEVICE_STATE_DISCONNECTED) { @@ -2368,22 +2393,16 @@ static void device_cb_info_finish(DeviceCbInfo *info, NMDevice *device) { if (device) { - GSList *elem = g_slist_find(info->queue, device); - if (!elem) + if (!g_ptr_array_remove(info->queue, device)) + return; + if (info->queue->len) return; - info->queue = g_slist_delete_link(info->queue, elem); - destroy_queue_element(device); - } else { - g_slist_free_full(info->queue, destroy_queue_element); - info->queue = NULL; } - if (info->queue) - return; - if (info->timeout_id) g_source_remove(info->timeout_id); + g_ptr_array_free(info->queue, TRUE); g_signal_handlers_disconnect_by_func(info->nmc->client, device_removed_cb, info); nm_clear_g_cancellable(&info->cancellable); @@ -2448,9 +2467,11 @@ do_device_reapply(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const nmc->nowait_flag = (nmc->timeout == 0); nmc->should_wait++; - info = g_slice_new0(DeviceCbInfo); - info->nmc = nmc; - info->queue = g_slist_prepend(info->queue, g_object_ref(device)); + info = g_slice_new0(DeviceCbInfo); + info->nmc = nmc; + + info->queue = g_ptr_array_new_with_free_func(destroy_queue_element); + g_ptr_array_add(info->queue, g_object_ref(device)); /* Now reapply the connection to the device */ nm_device_reapply_async(device, NULL, 0, 0, NULL, reapply_device_cb, info); @@ -2615,23 +2636,29 @@ disconnect_device_cb(GObject *object, GAsyncResult *result, gpointer user_data) static void do_devices_disconnect(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) { - NMDevice *device; - DeviceCbInfo *info = NULL; - GSList *queue, *iter; + NMDevice *device; + DeviceCbInfo *info = NULL; + gs_unref_ptrarray GPtrArray *queue = NULL; + guint i; /* Set default timeout for disconnect operation. */ if (nmc->timeout == -1) nmc->timeout = 10; next_arg(nmc, &argc, &argv, NULL); - queue = get_device_list(nmc, argc, argv); + queue = get_device_list(nmc, &argc, &argv); + if (argc) { + g_string_printf(nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; + } if (!queue) return; if (nmc->complete) - goto out; - queue = g_slist_reverse(queue); + return; info = g_slice_new0(DeviceCbInfo); + info->queue = g_steal_pointer(&queue); info->nmc = nmc; info->cmd_disconnect = TRUE; info->cancellable = g_cancellable_new(); @@ -2643,18 +2670,12 @@ do_devices_disconnect(const NMCCommand *cmd, NmCli *nmc, int argc, const char *c nmc->nowait_flag = (nmc->timeout == 0); nmc->should_wait++; - for (iter = queue; iter; iter = g_slist_next(iter)) { - device = iter->data; + for (i = 0; i < info->queue->len; i++) { + device = info->queue->pdata[i]; - info->queue = g_slist_prepend(info->queue, g_object_ref(device)); g_signal_connect(device, "notify::" NM_DEVICE_STATE, G_CALLBACK(disconnect_state_cb), info); - - /* Now disconnect the device */ nm_device_disconnect_async(device, info->cancellable, disconnect_device_cb, info); } - -out: - g_slist_free(queue); } static void @@ -2683,41 +2704,38 @@ delete_device_cb(GObject *object, GAsyncResult *result, gpointer user_data) static void do_devices_delete(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) { - NMDevice *device; - DeviceCbInfo *info = NULL; - GSList *queue, *iter; + DeviceCbInfo *info = NULL; + gs_unref_ptrarray GPtrArray *queue = NULL; + guint i; /* Set default timeout for delete operation. */ if (nmc->timeout == -1) nmc->timeout = 10; next_arg(nmc, &argc, &argv, NULL); - queue = get_device_list(nmc, argc, argv); + queue = get_device_list(nmc, &argc, &argv); + if (argc) { + g_string_printf(nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; + } if (!queue) return; if (nmc->complete) - goto out; - queue = g_slist_reverse(queue); + return; - info = g_slice_new0(DeviceCbInfo); - info->nmc = nmc; + info = g_slice_new0(DeviceCbInfo); + info->queue = g_steal_pointer(&queue); + info->nmc = nmc; if (nmc->timeout > 0) info->timeout_id = g_timeout_add_seconds(nmc->timeout, device_op_timeout_cb, info); nmc->nowait_flag = (nmc->timeout == 0); nmc->should_wait++; - for (iter = queue; iter; iter = g_slist_next(iter)) { - device = iter->data; - - info->queue = g_slist_prepend(info->queue, g_object_ref(device)); - - /* Now delete the device */ - nm_device_delete_async(device, NULL, delete_device_cb, info); + for (i = 0; i < info->queue->len; i++) { + nm_device_delete_async(info->queue->pdata[i], NULL, delete_device_cb, info); } - -out: - g_slist_free(queue); } static void @@ -2886,31 +2904,33 @@ device_removed(NMClient *client, NMDevice *device, NmCli *nmc) static void do_devices_monitor(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) { + const GPtrArray *devices; + gs_unref_ptrarray GPtrArray *devices_free = NULL; + guint i; + if (nmc->complete) return; next_arg(nmc, &argc, &argv, NULL); - if (argc == 0) { + if (argc > 0) { + devices = devices_free = get_device_list(nmc, &argc, &argv); + if (argc) { + g_string_printf(nmc->return_text, _("Error: invalid extra argument '%s'."), *argv); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; + } + } else { /* No devices specified. Monitor all. */ - const GPtrArray *devices = nm_client_get_devices(nmc->client); - int i; - - for (i = 0; i < devices->len; i++) - device_watch(nmc, g_ptr_array_index(devices, i)); + devices = nm_client_get_devices(nmc->client); /* We'll watch the device additions too, never exit. */ nmc->should_wait++; g_signal_connect(nmc->client, NM_CLIENT_DEVICE_ADDED, G_CALLBACK(device_added), nmc); - } else { - GSList *queue = get_device_list(nmc, argc, argv); - GSList *iter; - - /* Monitor the specified devices. */ - for (iter = queue; iter; iter = g_slist_next(iter)) - device_watch(nmc, NM_DEVICE(iter->data)); - g_slist_free(queue); } + for (i = 0; i < devices->len; i++) + device_watch(nmc, g_ptr_array_index(devices, i)); + g_signal_connect(nmc->client, NM_CLIENT_DEVICE_REMOVED, G_CALLBACK(device_removed), nmc); } @@ -5002,6 +5022,214 @@ do_device_lldp(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *a nmc_do_cmd(nmc, device_lldp_cmds, *argv, argc, argv); } +/*****************************************************************************/ + +typedef struct { + NmCli *nmc; + NMCheckpoint *checkpoint; + char **argv; + guint removed_id; + guint child_id; + gboolean removed; +} CheckpointCbInfo; + +static void +free_checkpoint_info(CheckpointCbInfo *info) +{ + g_clear_object(&info->checkpoint); + g_strfreev(info->argv); + g_slice_free(CheckpointCbInfo, info); +} + +static void +checkpoints_changed_cb(GObject *object, GParamSpec *pspec, CheckpointCbInfo *info) +{ + const GPtrArray *checkpoints; + guint i; + + checkpoints = nm_client_get_checkpoints(info->nmc->client); + for (i = 0; i < checkpoints->len; i++) { + if (checkpoints->pdata[i] == info->checkpoint) { + /* Our checkpoint still exists. */ + return; + } + } + + g_string_printf(info->nmc->return_text, _("Checkpoint was removed.")); + info->nmc->return_value = NMC_RESULT_ERROR_TIMEOUT_EXPIRED; + + info->removed = TRUE; + + if (!info->child_id) { + /* The command is done, we're in the confirmation prompt. */ + g_print("%s\n", _("No")); + g_main_loop_quit(loop); + } +} + +static void +checkpoint_destroy_cb(GObject *object, GAsyncResult *result, void *user_data) +{ + NmCli *nmc = (NmCli *) user_data; + gs_free_error GError *error = NULL; + + if (!nm_client_checkpoint_destroy_finish(nmc->client, result, &error)) { + g_string_printf(nmc->return_text, + _("Error: Destroying a checkpoint failed: %s"), + error->message); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + } + + g_main_loop_quit(loop); +} + +static void +child_watch_cb(GPid pid, gint wait_status, gpointer user_data) +{ + CheckpointCbInfo *info = (CheckpointCbInfo *) user_data; + NmCli *nmc = info->nmc; + char *line; + + info->child_id = 0; + if (info->removed) { + g_main_loop_quit(loop); + goto out; + } + + while (g_main_loop_is_running(loop)) { + line = nmc_readline(&nmc->nmc_config, "Type \"%s\" to commit the changes: ", _("Yes")); + if (g_strcmp0(line, _("Yes")) == 0) { + g_signal_handler_disconnect(nmc->client, info->removed_id); + nm_client_checkpoint_destroy(nmc->client, + nm_object_get_path(NM_OBJECT(info->checkpoint)), + NULL, + checkpoint_destroy_cb, + nmc); + break; + } + } + nmc_cleanup_readline(); +out: + free_checkpoint_info(info); +} + +static void +checkpoint_create_cb(GObject *object, GAsyncResult *result, void *user_data) +{ + NMClient *client = NM_CLIENT(object); + CheckpointCbInfo *info = (CheckpointCbInfo *) user_data; + gs_free_error GError *error = NULL; + GPid pid; + + info->checkpoint = nm_client_checkpoint_create_finish(client, result, &error); + if (!info->checkpoint) { + g_string_printf(info->nmc->return_text, + _("Error: Creating a checkpoint failed: %s"), + error->message); + info->nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + g_main_loop_quit(loop); + goto err; + } + + if (!g_spawn_async(NULL, + info->argv, + NULL, + G_SPAWN_LEAVE_DESCRIPTORS_OPEN | G_SPAWN_SEARCH_PATH + | G_SPAWN_CHILD_INHERITS_STDIN | G_SPAWN_DO_NOT_REAP_CHILD, + NULL, + info, + &pid, + &error)) { + g_string_printf(info->nmc->return_text, _("Error: %s"), error->message); + info->nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + g_main_loop_quit(loop); + goto err; + } + + info->child_id = g_child_watch_add(pid, child_watch_cb, info); + info->removed_id = g_signal_connect(client, + "notify::" NM_CLIENT_CHECKPOINTS, + G_CALLBACK(checkpoints_changed_cb), + info); + + return; + +err: + free_checkpoint_info(info); +} + +static void +do_device_checkpoint(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) +{ + NMClient *client = nmc->client; + long unsigned int timeout = 15; + int option; + CheckpointCbInfo *info; + const GPtrArray *devices = NULL; + gs_unref_ptrarray GPtrArray *devices_free = NULL; + + while ((option = next_arg(nmc, &argc, &argv, "--timeout", NULL)) > 0) { + switch (option) { + case 1: /* --timeout */ + argc--; + argv++; + if (!argc) { + g_string_printf(nmc->return_text, _("Error: %s argument is missing."), *(argv - 1)); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; + } + if (!nmc_string_to_uint(*argv, TRUE, 0, G_MAXUINT32, &timeout)) { + g_string_printf(nmc->return_text, _("Error: '%s' is not a valid timeout."), *argv); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; + } + break; + default: + nm_assert_not_reached(); + break; + } + } + + if (argc) { + if (strcmp(*argv, "--") == 0) { + devices = nm_client_get_devices(client); + argc--; + argv++; + } else { + devices = devices_free = get_device_list(nmc, &argc, &argv); + if (!devices) { + g_string_printf(nmc->return_text, _("Error: not all devices found.")); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; + } + } + } + + if (argc == 0) { + g_string_printf(nmc->return_text, _("Error: Expected a command to run after '--'")); + nmc->return_value = NMC_RESULT_ERROR_USER_INPUT; + return; + } + + if (nmc->complete) + return; + + info = g_slice_new0(CheckpointCbInfo); + info->nmc = nmc; + info->argv = nm_strv_dup(argv, argc, TRUE); + + nmc->should_wait++; + nm_client_checkpoint_create(client, + devices, + (guint32) timeout, + NM_CHECKPOINT_CREATE_FLAG_NONE, + NULL, + checkpoint_create_cb, + info); +} + +/*****************************************************************************/ + static gboolean is_single_word(const char *line) { @@ -5048,6 +5276,7 @@ void nmc_command_func_device(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) { static const NMCCommand cmds[] = { + {"checkpoint", do_device_checkpoint, usage_device_checkpoint, TRUE, TRUE}, {"connect", do_device_connect, usage_device_connect, TRUE, TRUE}, {"disconnect", do_devices_disconnect, usage_device_disconnect, TRUE, TRUE}, {"delete", do_devices_delete, usage_device_delete, TRUE, TRUE}, diff --git a/src/nmcli/general.c b/src/nmcli/general.c index d5a6788f..d116ab2c 100644 --- a/src/nmcli/general.c +++ b/src/nmcli/general.c @@ -300,11 +300,12 @@ static void usage_general(void) { g_printerr(_("Usage: nmcli general { COMMAND | help }\n\n" - "COMMAND := { status | hostname | permissions | logging }\n\n" + "COMMAND := { status | hostname | permissions | logging | reload }\n\n" " status\n\n" " hostname []\n\n" " permissions\n\n" - " logging [level ] [domains ]\n\n")); + " logging [level ] [domains ]\n\n" + " reload []\n\n")); } static void diff --git a/src/nmcli/generate-docs-nm-settings-nmcli.xml b/src/nmcli/generate-docs-nm-settings-nmcli.xml index 525b36b6..85df9ce5 100644 --- a/src/nmcli/generate-docs-nm-settings-nmcli.xml +++ b/src/nmcli/generate-docs-nm-settings-nmcli.xml @@ -29,7 +29,7 @@ + description="If specified, directs the device to only associate with the given access point. This capability is highly driver dependent and not supported by all devices. Note: this property does not control the BSSID used when creating an Ad-Hoc network and is unlikely to in the future. Locking a client profile to a certain BSSID will prevent roaming and also disable background scanning. That can be useful, if there is only one access point for the SSID." /> + + + description="List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting "ignore-auto-dns". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15)." /> + @@ -705,7 +711,7 @@ + description="List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting "ignore-auto-dns". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15)." /> + description="Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0), NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64 (2) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT (3). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. The special values "default" and "default-or-eui64" will fallback to the global connection default in as documented in NetworkManager.conf(5) manual. If the global default is not specified, the fallback value is "stable-privacy" or "eui64", respectively. For libnm, the property defaults to "default" since 1.40. Previously it defaulted to "stable-privacy". On D-Bus, the absence of an addr-gen-mode setting equals "default". For keyfile plugin, the absence of the setting on disk means "default-or-eui64" so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by "ip6-privacy" property and it does not affect the temporary addresses configured with this option." /> + + description="Whether to enable special handling of the IPv4 default route. If enabled, the IPv4 default route from wireguard.peer-routes will be placed to a dedicated routing-table and two policy routing rules will be added. The fwmark number is also used as routing-table for the default-route, and if fwmark is zero, an unused fwmark/table is chosen automatically. This corresponds to what wg-quick does with Table=auto and what WireGuard calls "Improved Rule-based Routing". Note that for this automatism to work, you usually don't want to set ipv4.gateway, because that will result in a conflicting default route. Leaving this at the default will enable this option automatically if ipv4.never-default is not set and there are any peers that use a default-route as allowed-ips. Since this automatism only makes sense if you also have a peer with an /0 allowed-ips, it is usually not necessary to enable this explicitly. However, you can disable it if you want to configure your own routing and rules." /> diff --git a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in index 525b36b6..85df9ce5 100644 --- a/src/nmcli/generate-docs-nm-settings-nmcli.xml.in +++ b/src/nmcli/generate-docs-nm-settings-nmcli.xml.in @@ -29,7 +29,7 @@ + description="If specified, directs the device to only associate with the given access point. This capability is highly driver dependent and not supported by all devices. Note: this property does not control the BSSID used when creating an Ad-Hoc network and is unlikely to in the future. Locking a client profile to a certain BSSID will prevent roaming and also disable background scanning. That can be useful, if there is only one access point for the SSID." /> + + + description="List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting "ignore-auto-dns". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15)." /> + @@ -705,7 +711,7 @@ + description="List of DNS search domains. Domains starting with a tilde ('~') are considered 'routing' domains and are used only to decide the interface over which a query must be forwarded; they are not used to complete unqualified host names. When using a DNS plugin that supports Conditional Forwarding or Split DNS, then the search domains specify which name servers to query. This makes the behavior different from running with plain /etc/resolv.conf. For more information see also the dns-priority setting. When set on a profile that also enabled DHCP, the DNS search list received automatically (option 119 for DHCPv4 and option 24 for DHCPv6) gets merged with the manual list. This can be prevented by setting "ignore-auto-dns". Note that if no DNS searches are configured, the fallback will be derived from the domain from DHCP (option 15)." /> + description="Configure method for creating the address for use with RFC4862 IPv6 Stateless Address Autoconfiguration. The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64 (0), NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1). NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT_OR_EUI64 (2) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_DEFAULT (3). If the property is set to EUI64, the addresses will be generated using the interface tokens derived from hardware address. This makes the host part of the address to stay constant, making it possible to track host's presence when it changes networks. The address changes when the interface hardware is replaced. The value of stable-privacy enables use of cryptographically secure hash of a secret host-specific key along with the connection's stable-id and the network address as specified by RFC7217. This makes it impossible to use the address track host's presence, and makes the address stable when the network interface hardware is replaced. The special values "default" and "default-or-eui64" will fallback to the global connection default in as documented in NetworkManager.conf(5) manual. If the global default is not specified, the fallback value is "stable-privacy" or "eui64", respectively. For libnm, the property defaults to "default" since 1.40. Previously it defaulted to "stable-privacy". On D-Bus, the absence of an addr-gen-mode setting equals "default". For keyfile plugin, the absence of the setting on disk means "default-or-eui64" so that the property doesn't change on upgrade from older versions. Note that this setting is distinct from the Privacy Extensions as configured by "ip6-privacy" property and it does not affect the temporary addresses configured with this option." /> + + description="Whether to enable special handling of the IPv4 default route. If enabled, the IPv4 default route from wireguard.peer-routes will be placed to a dedicated routing-table and two policy routing rules will be added. The fwmark number is also used as routing-table for the default-route, and if fwmark is zero, an unused fwmark/table is chosen automatically. This corresponds to what wg-quick does with Table=auto and what WireGuard calls "Improved Rule-based Routing". Note that for this automatism to work, you usually don't want to set ipv4.gateway, because that will result in a conflicting default route. Leaving this at the default will enable this option automatically if ipv4.never-default is not set and there are any peers that use a default-route as allowed-ips. Since this automatism only makes sense if you also have a peer with an /0 allowed-ips, it is usually not necessary to enable this explicitly. However, you can disable it if you want to configure your own routing and rules." /> diff --git a/src/nmcli/meson.build b/src/nmcli/meson.build index fab7329e..a122e2af 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 96b8ec4a..bc37a7f0 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 157aae99..f9b4cc7d 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 @@ -52,7 +52,11 @@ typedef enum { NMC_RESULT_COMPLETE_FILE = 65, } NMCResultCode; -typedef enum { NMC_PRINT_TERSE = 0, NMC_PRINT_NORMAL = 1, NMC_PRINT_PRETTY = 2 } NMCPrintOutput; +typedef enum { + NMC_PRINT_TERSE = 0, + NMC_PRINT_NORMAL = 1, + NMC_PRINT_PRETTY = 2, +} NMCPrintOutput; static inline NMMetaAccessorGetType nmc_print_output_to_accessor_get_type(NMCPrintOutput print_output) @@ -65,12 +69,17 @@ nmc_print_output_to_accessor_get_type(NMCPrintOutput print_output) /* === Output fields === */ typedef enum { - NMC_OF_FLAG_FIELD_NAMES = 0x00000001, /* Print field names instead of values */ - NMC_OF_FLAG_SECTION_PREFIX = - 0x00000002, /* Use the first value as section prefix for the other field names - just in multiline */ - NMC_OF_FLAG_MAIN_HEADER_ADD = - 0x00000004, /* Print main header in addition to values/field names */ - NMC_OF_FLAG_MAIN_HEADER_ONLY = 0x00000008, /* Print main header only */ + /* Print field names instead of values */ + NMC_OF_FLAG_FIELD_NAMES = 0x00000001, + + /* Use the first value as section prefix for the other field names - just in multiline */ + NMC_OF_FLAG_SECTION_PREFIX = 0x00000002, + + /* Print main header in addition to values/field names */ + NMC_OF_FLAG_MAIN_HEADER_ADD = 0x00000004, + + /* Print main header only */ + NMC_OF_FLAG_MAIN_HEADER_ONLY = 0x00000008, } NmcOfFlags; typedef struct { @@ -84,23 +93,45 @@ 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 */ + + /* Width in screen columns */ + int width; + + /* Value of current field - char* or char** (NULL-terminated array) */ + void *value; + + /* Whether value is char** instead of char* */ + bool value_is_array : 1; + + /* Whether to free the value */ + bool free_value : 1; + + 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) */ + /* Output mode */ + NMCPrintOutput print_output; + + /* Whether to use colors for output: option '--color' */ + bool use_colors; + + /* Multiline output instead of default tabular */ + bool multiline_output : 1; + + /* Whether to escape ':' and '\' in terse tabular mode */ + bool escape_values : 1; + + /* Whether running the editor - nmcli con edit' */ + bool in_editor : 1; + + /* Whether to display secrets (both input and output): option '--show-secrets' */ + bool show_secrets : 1; + + /* Overview mode (hide default values) */ + bool overview : 1; + NmcColorPalette palette; } NmcConfig; @@ -109,40 +140,71 @@ typedef struct { } NmcPagerData; typedef struct _NmcOutputData { - GPtrArray * - output_data; /* GPtrArray of arrays of NmcOutputField structs - accumulates data for output */ + /* GPtrArray of arrays of NmcOutputField structs - accumulates data for output */ + GPtrArray *output_data; } NmcOutputData; /* NmCli - main structure */ typedef struct _NmCli { - NMClient *client; /* Pointer to NMClient of libnm */ + /* Pointer to NMClient of libnm */ + NMClient *client; + + /* Return code of nmcli */ + NMCResultCode return_value; - NMCResultCode return_value; /* Return code of nmcli */ - GString *return_text; /* Reason text */ + /* Reason text */ + GString *return_text; NmcPagerData pager_data; - int timeout; /* Operation timeout */ + /* Operation timeout */ + int timeout; - NMSecretAgentSimple *secret_agent; /* Secret agent */ - GHashTable *pwds_hash; /* Hash table with passwords in passwd-file */ - struct _NMPolkitListener *pk_listener; /* polkit agent listener */ + /* Secret agent */ + NMSecretAgentSimple *secret_agent; + + /* Hash table with passwords in passwd-file */ + GHashTable *pwds_hash; + + /* polkit agent listener */ + struct _NMPolkitListener *pk_listener; + + /* Semaphore indicating whether nmcli should not end or not yet */ + int should_wait; + + /* '--nowait' option; used for passing to callbacks */ + bool nowait_flag : 1; + + /* Whether tabular/multiline mode was specified via '--mode' option */ + bool mode_specified : 1; + + /* Communicate the connection data over stdin/stdout instead of talking to the daemon. */ + bool offline : 1; + + /* Ask for missing parameters: option '--ask' */ + bool ask : 1; + + /* Autocomplete the command line */ + bool complete : 1; + + /* Whether to display status line in connection editor */ + bool editor_status_line : 1; + + /* Whether to ask for confirmation on saving connections with 'autoconnect=yes' */ + bool editor_save_confirmation : 1; - 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 */ 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 *palette_buffer; /* Buffer with sequences for terminal-colors.d(5)-based coloring. */ + + /* Required fields in output: '--fields' option */ + char *required_fields; + + /* Buffer with sequences for terminal-colors.d(5)-based coloring. */ + char *palette_buffer; + + GPtrArray *offline_connections; } NmCli; extern const NmCli *const nm_cli_global_readline; @@ -176,8 +238,18 @@ 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; + + /* Ensure a client instance is there before calling the handler (unless --offline has been given). */ + bool needs_client : 1; + + /* Client instance exists *and* the service is actually present on the bus. */ + bool needs_nm_running : 1; + + /* Run the handler without a client even if the comand usually requires one if --offline option was used. */ + bool supports_offline : 1; + + /* With --online, read in a keyfile from standard input before dispatching the handler. */ + bool needs_offline_conn : 1; } 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 535cf8fd..f111e657 100644 --- a/src/nmtui/nmt-connect-connection-list.c +++ b/src/nmtui/nmt-connect-connection-list.c @@ -92,17 +92,18 @@ nmt_connect_device_free(NmtConnectDevice *nmtdev) } static const char *device_sort_order[] = {"NMDeviceEthernet", - "NMDeviceVeth", - "NMDeviceInfiniband", - "NMDeviceWifi", - NM_SETTING_VLAN_SETTING_NAME, - NM_SETTING_BOND_SETTING_NAME, - NM_SETTING_TEAM_SETTING_NAME, - NM_SETTING_BRIDGE_SETTING_NAME, - NM_SETTING_IP_TUNNEL_SETTING_NAME, - NM_SETTING_WIREGUARD_SETTING_NAME, - "NMDeviceModem", - "NMDeviceBt"}; + "NMDeviceVeth", + "NMDeviceInfiniband", + "NMDeviceWifi", + NM_SETTING_VLAN_SETTING_NAME, + NM_SETTING_BOND_SETTING_NAME, + NM_SETTING_TEAM_SETTING_NAME, + 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); static int diff --git a/src/tests/client/test-client.check-on-disk/test_002.expected b/src/tests/client/test-client.check-on-disk/test_002.expected index 3f3f45e1..8f7acd52 100644 --- a/src/tests/client/test-client.check-on-disk/test_002.expected +++ b/src/tests/client/test-client.check-on-disk/test_002.expected @@ -502,12 +502,12 @@ NAME UUID TYPE DEVICE con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet -- <<< -size: 1319 +size: 1416 location: src/tests/client/test-client.py:test_002()/23 cmd: $NMCLI c s con-1 lang: C returncode: 0 -stdout: 1191 bytes +stdout: 1288 bytes >>> connection.id: con-1 connection.uuid: 5fcfd6d7-1e63-3332-8826-a7eda103792d @@ -533,15 +533,17 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 <<< -size: 1331 +size: 1428 location: src/tests/client/test-client.py:test_002()/24 cmd: $NMCLI c s con-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 1193 bytes +stdout: 1290 bytes >>> connection.id: con-1 connection.uuid: 5fcfd6d7-1e63-3332-8826-a7eda103792d @@ -567,6 +569,8 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 <<< diff --git a/src/tests/client/test-client.check-on-disk/test_003.expected b/src/tests/client/test-client.check-on-disk/test_003.expected index 5ba040ef..f350e3c5 100644 --- a/src/tests/client/test-client.check-on-disk/test_003.expected +++ b/src/tests/client/test-client.check-on-disk/test_003.expected @@ -182,12 +182,12 @@ id path uuid <<< -size: 4697 +size: 4884 location: src/tests/client/test-client.py:test_003()/14 cmd: $NMCLI con s con-gsm1 lang: C returncode: 0 -stdout: 4564 bytes +stdout: 4751 bytes >>> connection.id: con-gsm1 connection.uuid: UUID-con-gsm1-REPLACED-REPLACED-REPL @@ -213,7 +213,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -239,6 +241,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -257,8 +260,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -291,12 +295,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 4727 +size: 4922 location: src/tests/client/test-client.py:test_003()/15 cmd: $NMCLI con s con-gsm1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4584 bytes +stdout: 4779 bytes >>> connection.id: con-gsm1 connection.uuid: UUID-con-gsm1-REPLACED-REPLACED-REPL @@ -322,7 +326,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -348,6 +354,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -366,8 +373,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -400,42 +408,42 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 486 +size: 493 location: src/tests/client/test-client.py:test_003()/16 cmd: $NMCLI -g all con s con-gsm1 lang: C returncode: 0 -stdout: 347 bytes +stdout: 354 bytes >>> -connection:con-gsm1:UUID-con-gsm1-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::: :0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-gsm1:UUID-con-gsm1-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::: :0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: serial:5:8:even:1:100 gsm:no::::0:xyz.con-gsm1:::0:no::::auto proxy:none:no:: <<< -size: 496 +size: 503 location: src/tests/client/test-client.py:test_003()/17 cmd: $NMCLI -g all con s con-gsm1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 347 bytes +stdout: 354 bytes >>> -connection:con-gsm1:UUID-con-gsm1-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::: :0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-gsm1:UUID-con-gsm1-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::: :0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: serial:5:8:even:1:100 gsm:no::::0:xyz.con-gsm1:::0:no::::auto proxy:none:no:: <<< -size: 4685 +size: 4872 location: src/tests/client/test-client.py:test_003()/18 cmd: $NMCLI con s con-gsm2 lang: C returncode: 0 -stdout: 4552 bytes +stdout: 4739 bytes >>> connection.id: con-gsm2 connection.uuid: UUID-con-gsm2-REPLACED-REPLACED-REPL @@ -461,7 +469,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -487,6 +497,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -505,8 +516,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -539,12 +551,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 4715 +size: 4910 location: src/tests/client/test-client.py:test_003()/19 cmd: $NMCLI con s con-gsm2 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4572 bytes +stdout: 4767 bytes >>> connection.id: con-gsm2 connection.uuid: UUID-con-gsm2-REPLACED-REPLACED-REPL @@ -570,7 +582,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -596,6 +610,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -614,8 +629,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -648,42 +664,42 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 474 +size: 481 location: src/tests/client/test-client.py:test_003()/20 cmd: $NMCLI -g all con s con-gsm2 lang: C returncode: 0 -stdout: 335 bytes +stdout: 342 bytes >>> -connection:con-gsm2:UUID-con-gsm2-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::: :0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-gsm2:UUID-con-gsm2-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::: :0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: serial:5:8:even:1:100 gsm:no::::0::::0:no::::auto proxy:none:no:: <<< -size: 484 +size: 491 location: src/tests/client/test-client.py:test_003()/21 cmd: $NMCLI -g all con s con-gsm2 lang: pl_PL.UTF-8 returncode: 0 -stdout: 335 bytes +stdout: 342 bytes >>> -connection:con-gsm2:UUID-con-gsm2-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::: :0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-gsm2:UUID-con-gsm2-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::: :0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: serial:5:8:even:1:100 gsm:no::::0::::0:no::::auto proxy:none:no:: <<< -size: 4685 +size: 4872 location: src/tests/client/test-client.py:test_003()/22 cmd: $NMCLI con s con-gsm3 lang: C returncode: 0 -stdout: 4552 bytes +stdout: 4739 bytes >>> connection.id: con-gsm3 connection.uuid: UUID-con-gsm3-REPLACED-REPLACED-REPL @@ -709,7 +725,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -735,6 +753,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -753,8 +772,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -787,12 +807,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 4715 +size: 4910 location: src/tests/client/test-client.py:test_003()/23 cmd: $NMCLI con s con-gsm3 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4572 bytes +stdout: 4767 bytes >>> connection.id: con-gsm3 connection.uuid: UUID-con-gsm3-REPLACED-REPLACED-REPL @@ -818,7 +838,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -844,6 +866,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -862,8 +885,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -896,31 +920,31 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 475 +size: 482 location: src/tests/client/test-client.py:test_003()/24 cmd: $NMCLI -g all con s con-gsm3 lang: C returncode: 0 -stdout: 336 bytes +stdout: 343 bytes >>> -connection:con-gsm3:UUID-con-gsm3-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::: :0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-gsm3:UUID-con-gsm3-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::: :0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: serial:5:8:even:1:100 gsm:no::::0: :::0:no::::auto proxy:none:no:: <<< -size: 485 +size: 492 location: src/tests/client/test-client.py:test_003()/25 cmd: $NMCLI -g all con s con-gsm3 lang: pl_PL.UTF-8 returncode: 0 -stdout: 336 bytes +stdout: 343 bytes >>> -connection:con-gsm3:UUID-con-gsm3-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::: :0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-gsm3:UUID-con-gsm3-REPLACED-REPLACED-REPL::gsm::no:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::: :0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: serial:5:8:even:1:100 gsm:no::::0: :::0:no::::auto proxy:none:no:: @@ -1066,12 +1090,12 @@ UUID NAME UUID-ethernet-REPLACED-REPLACED-REPL ethernet <<< -size: 4523 +size: 4710 location: src/tests/client/test-client.py:test_003()/37 cmd: $NMCLI -f ALL con s ethernet lang: C returncode: 0 -stdout: 4383 bytes +stdout: 4570 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -1097,7 +1121,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -1138,6 +1164,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -1156,8 +1183,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -1171,12 +1199,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 4551 +size: 4746 location: src/tests/client/test-client.py:test_003()/38 cmd: $NMCLI -f ALL con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 4401 bytes +stdout: 4596 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -1202,7 +1230,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -1243,6 +1273,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -1261,8 +1292,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -1296,12 +1328,12 @@ stdout: 51 bytes GENERAL.STATE: aktywowano <<< -size: 5225 +size: 5412 location: src/tests/client/test-client.py:test_003()/41 cmd: $NMCLI con s ethernet lang: C returncode: 0 -stdout: 5092 bytes +stdout: 5279 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -1327,7 +1359,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -1368,6 +1402,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -1386,8 +1421,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -1414,12 +1450,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 5257 +size: 5452 location: src/tests/client/test-client.py:test_003()/42 cmd: $NMCLI con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 5114 bytes +stdout: 5309 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -1445,7 +1481,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -1486,6 +1524,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -1504,8 +1543,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -2018,12 +2058,12 @@ UUID NAME UUID-ethernet-REPLACED-REPLACED-REPL ethernet <<< -size: 4523 +size: 4710 location: src/tests/client/test-client.py:test_003()/62 cmd: $NMCLI -f ALL con s ethernet lang: C returncode: 0 -stdout: 4383 bytes +stdout: 4570 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -2049,7 +2089,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -2090,6 +2132,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -2108,8 +2151,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -2123,12 +2167,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 4551 +size: 4746 location: src/tests/client/test-client.py:test_003()/63 cmd: $NMCLI -f ALL con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 4401 bytes +stdout: 4596 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -2154,7 +2198,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -2195,6 +2241,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -2213,8 +2260,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -2252,12 +2300,12 @@ GENERAL.STATE: aktywowano GENERAL.STATE: aktywowano <<< -size: 5935 +size: 6122 location: src/tests/client/test-client.py:test_003()/66 cmd: $NMCLI con s ethernet lang: C returncode: 0 -stdout: 5802 bytes +stdout: 5989 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -2283,7 +2331,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -2324,6 +2374,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -2342,8 +2393,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -2384,12 +2436,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 5971 +size: 6166 location: src/tests/client/test-client.py:test_003()/67 cmd: $NMCLI con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 5828 bytes +stdout: 6023 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -2415,7 +2467,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -2456,6 +2510,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -2474,8 +2529,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -2994,12 +3050,12 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 5938 +size: 6125 location: src/tests/client/test-client.py:test_003()/82 cmd: $NMCLI con s ethernet lang: C returncode: 0 -stdout: 5805 bytes +stdout: 5992 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -3025,7 +3081,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -3066,6 +3124,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -3084,8 +3143,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -3126,12 +3186,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 5975 +size: 6170 location: src/tests/client/test-client.py:test_003()/83 cmd: $NMCLI con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 5832 bytes +stdout: 6027 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -3157,7 +3217,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -3198,6 +3260,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -3216,8 +3279,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -3258,12 +3322,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 5268 +size: 5455 location: src/tests/client/test-client.py:test_003()/84 cmd: $NMCLI c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 5095 bytes +stdout: 5282 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -3289,7 +3353,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -3330,6 +3396,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -3348,8 +3415,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -3376,12 +3444,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 5301 +size: 5496 location: src/tests/client/test-client.py:test_003()/85 cmd: $NMCLI c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5118 bytes +stdout: 5313 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -3407,7 +3475,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -3448,6 +3518,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -3466,8 +3537,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -3704,12 +3776,12 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 5950 +size: 6137 location: src/tests/client/test-client.py:test_003()/92 cmd: $NMCLI --color yes con s ethernet lang: C returncode: 0 -stdout: 5805 bytes +stdout: 5992 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -3735,7 +3807,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -3776,6 +3850,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -3794,8 +3869,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -3836,12 +3912,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 5987 +size: 6182 location: src/tests/client/test-client.py:test_003()/93 cmd: $NMCLI --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 5832 bytes +stdout: 6027 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -3867,7 +3943,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -3908,6 +3986,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -3926,8 +4005,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -3968,12 +4048,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 5280 +size: 5467 location: src/tests/client/test-client.py:test_003()/94 cmd: $NMCLI --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 5095 bytes +stdout: 5282 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -3999,7 +4079,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -4040,6 +4122,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -4058,8 +4141,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -4086,12 +4170,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 5313 +size: 5508 location: src/tests/client/test-client.py:test_003()/95 cmd: $NMCLI --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5118 bytes +stdout: 5313 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -4117,7 +4201,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -4158,6 +4244,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -4176,8 +4263,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -4430,12 +4518,12 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 7191 +size: 7378 location: src/tests/client/test-client.py:test_003()/102 cmd: $NMCLI --pretty con s ethernet lang: C returncode: 0 -stdout: 7048 bytes +stdout: 7235 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -4464,7 +4552,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -4507,6 +4597,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -4526,8 +4617,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -4578,12 +4670,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 7249 +size: 7444 location: src/tests/client/test-client.py:test_003()/103 cmd: $NMCLI --pretty con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 7096 bytes +stdout: 7291 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -4612,7 +4704,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -4655,6 +4749,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -4674,8 +4769,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -4726,12 +4822,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 6209 +size: 6396 location: src/tests/client/test-client.py:test_003()/104 cmd: $NMCLI --pretty c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 6026 bytes +stdout: 6213 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -4760,7 +4856,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -4803,6 +4901,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -4822,8 +4921,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -4856,12 +4956,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 6255 +size: 6450 location: src/tests/client/test-client.py:test_003()/105 cmd: $NMCLI --pretty c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6062 bytes +stdout: 6257 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -4890,7 +4990,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -4933,6 +5035,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -4952,8 +5055,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -5236,12 +5340,12 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 7203 +size: 7390 location: src/tests/client/test-client.py:test_003()/112 cmd: $NMCLI --pretty --color yes con s ethernet lang: C returncode: 0 -stdout: 7048 bytes +stdout: 7235 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -5270,7 +5374,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -5313,6 +5419,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -5332,8 +5439,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -5384,12 +5492,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 7261 +size: 7456 location: src/tests/client/test-client.py:test_003()/113 cmd: $NMCLI --pretty --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 7096 bytes +stdout: 7291 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -5418,7 +5526,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -5461,6 +5571,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -5480,8 +5591,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -5532,12 +5644,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 6221 +size: 6408 location: src/tests/client/test-client.py:test_003()/114 cmd: $NMCLI --pretty --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 6026 bytes +stdout: 6213 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -5566,7 +5678,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -5609,6 +5723,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -5628,8 +5743,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -5662,12 +5778,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 6267 +size: 6462 location: src/tests/client/test-client.py:test_003()/115 cmd: $NMCLI --pretty --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6062 bytes +stdout: 6257 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -5696,7 +5812,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -5739,6 +5857,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -5758,8 +5877,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -6022,12 +6142,12 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL:gsm UUID-con-xx1-REPLACED-REPLACED-REPLA:802-3-ethernet <<< -size: 3193 +size: 3281 location: src/tests/client/test-client.py:test_003()/122 cmd: $NMCLI --terse con s ethernet lang: C returncode: 0 -stdout: 3051 bytes +stdout: 3139 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -6053,7 +6173,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -6094,6 +6216,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -6112,8 +6235,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -6154,12 +6278,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3203 +size: 3291 location: src/tests/client/test-client.py:test_003()/123 cmd: $NMCLI --terse con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 3051 bytes +stdout: 3139 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -6185,7 +6309,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -6226,6 +6352,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -6244,8 +6371,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -6286,12 +6414,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 2843 +size: 2931 location: src/tests/client/test-client.py:test_003()/124 cmd: $NMCLI --terse c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 2661 bytes +stdout: 2749 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -6317,7 +6445,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -6358,6 +6488,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -6376,8 +6507,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -6404,12 +6536,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 2853 +size: 2941 location: src/tests/client/test-client.py:test_003()/125 cmd: $NMCLI --terse c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2661 bytes +stdout: 2749 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -6435,7 +6567,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -6476,6 +6610,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -6494,8 +6629,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -6728,12 +6864,12 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL:gsm UUID-con-xx1-REPLACED-REPLACED-REPLA:802-3-ethernet <<< -size: 3205 +size: 3293 location: src/tests/client/test-client.py:test_003()/132 cmd: $NMCLI --terse --color yes con s ethernet lang: C returncode: 0 -stdout: 3051 bytes +stdout: 3139 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -6759,7 +6895,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -6800,6 +6938,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -6818,8 +6957,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -6860,12 +7000,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3215 +size: 3303 location: src/tests/client/test-client.py:test_003()/133 cmd: $NMCLI --terse --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 3051 bytes +stdout: 3139 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -6891,7 +7031,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -6932,6 +7074,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -6950,8 +7093,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -6992,12 +7136,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 2855 +size: 2943 location: src/tests/client/test-client.py:test_003()/134 cmd: $NMCLI --terse --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 2661 bytes +stdout: 2749 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -7023,7 +7167,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -7064,6 +7210,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -7082,8 +7229,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -7110,12 +7258,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 2865 +size: 2953 location: src/tests/client/test-client.py:test_003()/135 cmd: $NMCLI --terse --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2661 bytes +stdout: 2749 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -7141,7 +7289,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -7182,6 +7332,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -7200,8 +7351,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -7438,24 +7590,24 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 3993 +size: 4105 location: src/tests/client/test-client.py:test_003()/142 cmd: $NMCLI --mode tabular con s ethernet lang: C returncode: 0 -stdout: 3844 bytes +stdout: 3956 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- no -- -- -- -- auto -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name method browser-only pac-url pac-script proxy none no -- -- @@ -7469,24 +7621,24 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 4027 +size: 4155 location: src/tests/client/test-client.py:test_003()/143 cmd: $NMCLI --mode tabular con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 3868 bytes +stdout: 3996 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- nie -- -- -- -- automatyczne -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name method browser-only pac-url pac-script proxy none nie -- -- @@ -7500,24 +7652,24 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deza <<< -size: 3531 +size: 3643 location: src/tests/client/test-client.py:test_003()/144 cmd: $NMCLI --mode tabular c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 3342 bytes +stdout: 3454 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- no -- -- -- -- auto -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name method browser-only pac-url pac-script proxy none no -- -- @@ -7527,24 +7679,24 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 3563 +size: 3691 location: src/tests/client/test-client.py:test_003()/145 cmd: $NMCLI --mode tabular c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3364 bytes +stdout: 3492 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- nie -- -- -- -- automatyczne -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name method browser-only pac-url pac-script proxy none nie -- -- @@ -7690,24 +7842,24 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 4005 +size: 4117 location: src/tests/client/test-client.py:test_003()/152 cmd: $NMCLI --mode tabular --color yes con s ethernet lang: C returncode: 0 -stdout: 3844 bytes +stdout: 3956 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- no -- -- -- -- auto -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name method browser-only pac-url pac-script proxy none no -- -- @@ -7721,24 +7873,24 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 4039 +size: 4167 location: src/tests/client/test-client.py:test_003()/153 cmd: $NMCLI --mode tabular --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 3868 bytes +stdout: 3996 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- nie -- -- -- -- automatyczne -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name method browser-only pac-url pac-script proxy none nie -- -- @@ -7752,24 +7904,24 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deza <<< -size: 3543 +size: 3655 location: src/tests/client/test-client.py:test_003()/154 cmd: $NMCLI --mode tabular --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 3342 bytes +stdout: 3454 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- no -- -- -- -- auto -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name method browser-only pac-url pac-script proxy none no -- -- @@ -7779,24 +7931,24 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 3575 +size: 3703 location: src/tests/client/test-client.py:test_003()/155 cmd: $NMCLI --mode tabular --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3364 bytes +stdout: 3492 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses 802-3-ethernet -- 0 -- nie -- -- -- -- automatyczne -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name method browser-only pac-url pac-script proxy none nie -- -- @@ -7958,31 +8110,31 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 6461 +size: 6629 location: src/tests/client/test-client.py:test_003()/162 cmd: $NMCLI --mode tabular --pretty con s ethernet lang: C returncode: 0 -stdout: 6303 bytes +stdout: 6471 bytes >>> ========================================= Connection profile details (ethernet) ========================================= -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 802-3-ethernet -- 0 -- no -- -- -- -- auto -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name method browser-only pac-url pac-script -------------------------------------------------- @@ -8005,31 +8157,31 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 6567 +size: 6759 location: src/tests/client/test-client.py:test_003()/163 cmd: $NMCLI --mode tabular --pretty con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 6399 bytes +stdout: 6591 bytes >>> =========================================== Szczegóły profilu połączenia (ethernet) =========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 802-3-ethernet -- 0 -- nie -- -- -- -- automatyczne -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name method browser-only pac-url pac-script -------------------------------------------------- @@ -8052,31 +8204,31 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deza <<< -size: 5543 +size: 5711 location: src/tests/client/test-client.py:test_003()/164 cmd: $NMCLI --mode tabular --pretty c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 5345 bytes +stdout: 5513 bytes >>> ========================================= Connection profile details (ethernet) ========================================= -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 802-3-ethernet -- 0 -- no -- -- -- -- auto -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name method browser-only pac-url pac-script -------------------------------------------------- @@ -8091,31 +8243,31 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 5621 +size: 5813 location: src/tests/client/test-client.py:test_003()/165 cmd: $NMCLI --mode tabular --pretty c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5413 bytes +stdout: 5605 bytes >>> =========================================== Szczegóły profilu połączenia (ethernet) =========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 802-3-ethernet -- 0 -- nie -- -- -- -- automatyczne -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name method browser-only pac-url pac-script -------------------------------------------------- @@ -8306,31 +8458,31 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL gsm UUID-con-xx1-REPLACED-REPLACED-REPLA ethernet <<< -size: 6473 +size: 6641 location: src/tests/client/test-client.py:test_003()/172 cmd: $NMCLI --mode tabular --pretty --color yes con s ethernet lang: C returncode: 0 -stdout: 6303 bytes +stdout: 6471 bytes >>> ========================================= Connection profile details (ethernet) ========================================= -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 802-3-ethernet -- 0 -- no -- -- -- -- auto -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name method browser-only pac-url pac-script -------------------------------------------------- @@ -8353,31 +8505,31 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 6579 +size: 6771 location: src/tests/client/test-client.py:test_003()/173 cmd: $NMCLI --mode tabular --pretty --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 6399 bytes +stdout: 6591 bytes >>> =========================================== Szczegóły profilu połączenia (ethernet) =========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 802-3-ethernet -- 0 -- nie -- -- -- -- automatyczne -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name method browser-only pac-url pac-script -------------------------------------------------- @@ -8400,31 +8552,31 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deza <<< -size: 5555 +size: 5723 location: src/tests/client/test-client.py:test_003()/174 cmd: $NMCLI --mode tabular --pretty --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 5345 bytes +stdout: 5513 bytes >>> ========================================= Connection profile details (ethernet) ========================================= -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 802-3-ethernet -- 0 -- no -- -- -- -- auto -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name method browser-only pac-url pac-script -------------------------------------------------- @@ -8439,31 +8591,31 @@ GENERAL ethernet UUID-ethernet-REPLACED-REPLACED-REPL eth0 eth0 deac <<< -size: 5633 +size: 5825 location: src/tests/client/test-client.py:test_003()/175 cmd: $NMCLI --mode tabular --pretty --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5413 bytes +stdout: 5605 bytes >>> =========================================== Szczegóły profilu połączenia (ethernet) =========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection ethernet UUID-ethernet-REPLACED-REPLACED-REPL -- 802-3-ethernet -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 name port speed duplex auto-negotiate mac-address cloned-mac-address generate-mac-address-mask mac-address-blacklist mtu s390-subchannels s390-nettype s390-options wake-on-lan wake-on-lan-password accept-all-mac-addresses ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 802-3-ethernet -- 0 -- nie -- -- -- -- automatyczne -- -- -- default -- -1 (default) -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name method browser-only pac-url pac-script -------------------------------------------------- @@ -8634,66 +8786,66 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL:gsm UUID-con-xx1-REPLACED-REPLACED-REPLA:802-3-ethernet <<< -size: 868 +size: 875 location: src/tests/client/test-client.py:test_003()/182 cmd: $NMCLI --mode tabular --terse con s ethernet lang: C returncode: 0 -stdout: 712 bytes +stdout: 719 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: proxy:none:no:: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth1:eth1:activated:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/2:/org/freedesktop/NetworkManager/Settings/Connection/6:: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth0:eth0:deactivating:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/1:/org/freedesktop/NetworkManager/Settings/Connection/6:: <<< -size: 878 +size: 885 location: src/tests/client/test-client.py:test_003()/183 cmd: $NMCLI --mode tabular --terse con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 712 bytes +stdout: 719 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: proxy:none:no:: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth1:eth1:activated:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/2:/org/freedesktop/NetworkManager/Settings/Connection/6:: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth0:eth0:deactivating:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/1:/org/freedesktop/NetworkManager/Settings/Connection/6:: <<< -size: 716 +size: 723 location: src/tests/client/test-client.py:test_003()/184 cmd: $NMCLI --mode tabular --terse c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 520 bytes +stdout: 527 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: proxy:none:no:: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth0:eth0:deactivating:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/1:/org/freedesktop/NetworkManager/Settings/Connection/6:: <<< -size: 726 +size: 733 location: src/tests/client/test-client.py:test_003()/185 cmd: $NMCLI --mode tabular --terse c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 520 bytes +stdout: 527 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: proxy:none:no:: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth0:eth0:deactivating:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/1:/org/freedesktop/NetworkManager/Settings/Connection/6:: @@ -8796,66 +8948,66 @@ UUID-con-gsm3-REPLACED-REPLACED-REPL:gsm UUID-con-xx1-REPLACED-REPLACED-REPLA:802-3-ethernet <<< -size: 880 +size: 887 location: src/tests/client/test-client.py:test_003()/192 cmd: $NMCLI --mode tabular --terse --color yes con s ethernet lang: C returncode: 0 -stdout: 712 bytes +stdout: 719 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: proxy:none:no:: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth1:eth1:activated:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/2:/org/freedesktop/NetworkManager/Settings/Connection/6:: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth0:eth0:deactivating:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/1:/org/freedesktop/NetworkManager/Settings/Connection/6:: <<< -size: 890 +size: 897 location: src/tests/client/test-client.py:test_003()/193 cmd: $NMCLI --mode tabular --terse --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 712 bytes +stdout: 719 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: proxy:none:no:: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth1:eth1:activated:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/2:/org/freedesktop/NetworkManager/Settings/Connection/6:: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth0:eth0:deactivating:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/1:/org/freedesktop/NetworkManager/Settings/Connection/6:: <<< -size: 728 +size: 735 location: src/tests/client/test-client.py:test_003()/194 cmd: $NMCLI --mode tabular --terse --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 520 bytes +stdout: 527 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: proxy:none:no:: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth0:eth0:deactivating:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/1:/org/freedesktop/NetworkManager/Settings/Connection/6:: <<< -size: 738 +size: 745 location: src/tests/client/test-client.py:test_003()/195 cmd: $NMCLI --mode tabular --terse --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 520 bytes +stdout: 527 bytes >>> -connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 +connection:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL::802-3-ethernet::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 802-3-ethernet::0::no:::::auto::::default::-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: proxy:none:no:: GENERAL:ethernet:UUID-ethernet-REPLACED-REPLACED-REPL:eth0:eth0:deactivating:no:no::no:/org/freedesktop/NetworkManager/ActiveConnection/1:/org/freedesktop/NetworkManager/Settings/Connection/6:: @@ -9166,12 +9318,12 @@ UUID: UUID-con-xx1-REPLACED-REPLACED-REPLA TYPE: ethernet <<< -size: 5956 +size: 6143 location: src/tests/client/test-client.py:test_003()/202 cmd: $NMCLI --mode multiline con s ethernet lang: C returncode: 0 -stdout: 5805 bytes +stdout: 5992 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -9197,7 +9349,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -9238,6 +9392,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -9256,8 +9411,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -9298,12 +9454,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 5993 +size: 6188 location: src/tests/client/test-client.py:test_003()/203 cmd: $NMCLI --mode multiline con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 5832 bytes +stdout: 6027 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -9329,7 +9485,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -9370,6 +9528,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -9388,8 +9547,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -9430,12 +9590,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 5286 +size: 5473 location: src/tests/client/test-client.py:test_003()/204 cmd: $NMCLI --mode multiline c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 5095 bytes +stdout: 5282 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -9461,7 +9621,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -9502,6 +9664,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -9520,8 +9683,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -9548,12 +9712,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 5319 +size: 5514 location: src/tests/client/test-client.py:test_003()/205 cmd: $NMCLI --mode multiline c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5118 bytes +stdout: 5313 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -9579,7 +9743,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -9620,6 +9786,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -9638,8 +9805,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -10080,12 +10248,12 @@ UUID: UUID-con-xx1-REPLACED-REPLACED-REPLA TYPE: ethernet <<< -size: 5968 +size: 6155 location: src/tests/client/test-client.py:test_003()/212 cmd: $NMCLI --mode multiline --color yes con s ethernet lang: C returncode: 0 -stdout: 5805 bytes +stdout: 5992 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -10111,7 +10279,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -10152,6 +10322,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -10170,8 +10341,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -10212,12 +10384,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 6005 +size: 6200 location: src/tests/client/test-client.py:test_003()/213 cmd: $NMCLI --mode multiline --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 5832 bytes +stdout: 6027 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -10243,7 +10415,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -10284,6 +10458,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -10302,8 +10477,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -10344,12 +10520,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 5298 +size: 5485 location: src/tests/client/test-client.py:test_003()/214 cmd: $NMCLI --mode multiline --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 5095 bytes +stdout: 5282 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -10375,7 +10551,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -10416,6 +10594,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -10434,8 +10613,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -10462,12 +10642,12 @@ GENERAL.ZONE: -- GENERAL.MASTER-PATH: -- <<< -size: 5331 +size: 5526 location: src/tests/client/test-client.py:test_003()/215 cmd: $NMCLI --mode multiline --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5118 bytes +stdout: 5313 bytes >>> connection.id: ethernet connection.uuid: UUID-ethernet-REPLACED-REPLACED-REPL @@ -10493,7 +10673,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 802-3-ethernet.duplex: -- @@ -10534,6 +10716,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -10552,8 +10735,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -11032,12 +11216,12 @@ TYPE: ethernet ------------------------------------------------------------------------------- <<< -size: 7208 +size: 7395 location: src/tests/client/test-client.py:test_003()/222 cmd: $NMCLI --mode multiline --pretty con s ethernet lang: C returncode: 0 -stdout: 7048 bytes +stdout: 7235 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -11066,7 +11250,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -11109,6 +11295,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -11128,8 +11315,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -11180,12 +11368,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 7266 +size: 7461 location: src/tests/client/test-client.py:test_003()/223 cmd: $NMCLI --mode multiline --pretty con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 7096 bytes +stdout: 7291 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -11214,7 +11402,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -11257,6 +11447,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -11276,8 +11467,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -11328,12 +11520,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 6226 +size: 6413 location: src/tests/client/test-client.py:test_003()/224 cmd: $NMCLI --mode multiline --pretty c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 6026 bytes +stdout: 6213 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -11362,7 +11554,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -11405,6 +11599,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -11424,8 +11619,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -11458,12 +11654,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 6272 +size: 6467 location: src/tests/client/test-client.py:test_003()/225 cmd: $NMCLI --mode multiline --pretty c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6062 bytes +stdout: 6257 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -11492,7 +11688,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -11535,6 +11733,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -11554,8 +11753,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -12064,12 +12264,12 @@ TYPE: ethernet ------------------------------------------------------------------------------- <<< -size: 7220 +size: 7407 location: src/tests/client/test-client.py:test_003()/232 cmd: $NMCLI --mode multiline --pretty --color yes con s ethernet lang: C returncode: 0 -stdout: 7048 bytes +stdout: 7235 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -12098,7 +12298,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -12141,6 +12343,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -12160,8 +12363,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -12212,12 +12416,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 7278 +size: 7473 location: src/tests/client/test-client.py:test_003()/233 cmd: $NMCLI --mode multiline --pretty --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 7096 bytes +stdout: 7291 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -12246,7 +12450,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -12289,6 +12495,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -12308,8 +12515,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -12360,12 +12568,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 6238 +size: 6425 location: src/tests/client/test-client.py:test_003()/234 cmd: $NMCLI --mode multiline --pretty --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 6026 bytes +stdout: 6213 bytes >>> =============================================================================== Connection profile details (ethernet) @@ -12394,7 +12602,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -12437,6 +12647,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -12456,8 +12667,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -12490,12 +12702,12 @@ GENERAL.MASTER-PATH: -- ------------------------------------------------------------------------------- <<< -size: 6284 +size: 6479 location: src/tests/client/test-client.py:test_003()/235 cmd: $NMCLI --mode multiline --pretty --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6062 bytes +stdout: 6257 bytes >>> =============================================================================== Szczegóły profilu połączenia (ethernet) @@ -12524,7 +12736,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- 802-3-ethernet.port: -- 802-3-ethernet.speed: 0 @@ -12567,6 +12781,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -12586,8 +12801,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -13058,12 +13274,12 @@ UUID:UUID-con-xx1-REPLACED-REPLACED-REPLA TYPE:802-3-ethernet <<< -size: 3210 +size: 3298 location: src/tests/client/test-client.py:test_003()/242 cmd: $NMCLI --mode multiline --terse con s ethernet lang: C returncode: 0 -stdout: 3051 bytes +stdout: 3139 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -13089,7 +13305,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -13130,6 +13348,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -13148,8 +13367,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -13190,12 +13410,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3220 +size: 3308 location: src/tests/client/test-client.py:test_003()/243 cmd: $NMCLI --mode multiline --terse con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 3051 bytes +stdout: 3139 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -13221,7 +13441,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -13262,6 +13484,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -13280,8 +13503,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -13322,12 +13546,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 2860 +size: 2948 location: src/tests/client/test-client.py:test_003()/244 cmd: $NMCLI --mode multiline --terse c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 2661 bytes +stdout: 2749 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -13353,7 +13577,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -13394,6 +13620,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -13412,8 +13639,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -13440,12 +13668,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 2870 +size: 2958 location: src/tests/client/test-client.py:test_003()/245 cmd: $NMCLI --mode multiline --terse c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2661 bytes +stdout: 2749 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -13471,7 +13699,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -13512,6 +13742,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -13530,8 +13761,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -13972,12 +14204,12 @@ UUID:UUID-con-xx1-REPLACED-REPLACED-REPLA TYPE:802-3-ethernet <<< -size: 3222 +size: 3310 location: src/tests/client/test-client.py:test_003()/252 cmd: $NMCLI --mode multiline --terse --color yes con s ethernet lang: C returncode: 0 -stdout: 3051 bytes +stdout: 3139 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -14003,7 +14235,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -14044,6 +14278,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -14062,8 +14297,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -14104,12 +14340,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 3232 +size: 3320 location: src/tests/client/test-client.py:test_003()/253 cmd: $NMCLI --mode multiline --terse --color yes con s ethernet lang: pl_PL.UTF-8 returncode: 0 -stdout: 3051 bytes +stdout: 3139 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -14135,7 +14371,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -14176,6 +14414,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -14194,8 +14433,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -14236,12 +14476,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 2872 +size: 2960 location: src/tests/client/test-client.py:test_003()/254 cmd: $NMCLI --mode multiline --terse --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: C returncode: 0 -stdout: 2661 bytes +stdout: 2749 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -14267,7 +14507,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -14308,6 +14550,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -14326,8 +14569,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -14354,12 +14598,12 @@ GENERAL.ZONE: GENERAL.MASTER-PATH: <<< -size: 2882 +size: 2970 location: src/tests/client/test-client.py:test_003()/255 cmd: $NMCLI --mode multiline --terse --color yes c s /org/freedesktop/NetworkManager/ActiveConnection/1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2661 bytes +stdout: 2749 bytes >>> connection.id:ethernet connection.uuid:UUID-ethernet-REPLACED-REPLACED-REPL @@ -14385,7 +14629,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 802-3-ethernet.port: 802-3-ethernet.speed:0 802-3-ethernet.duplex: @@ -14426,6 +14672,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -14444,8 +14691,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 diff --git a/src/tests/client/test-client.check-on-disk/test_004.expected b/src/tests/client/test-client.check-on-disk/test_004.expected index ca8af006..379544a3 100644 --- a/src/tests/client/test-client.check-on-disk/test_004.expected +++ b/src/tests/client/test-client.check-on-disk/test_004.expected @@ -58,12 +58,12 @@ location: src/tests/client/test-client.py:test_004()/7 cmd: $NMCLI connection mod con-xx1 ipv4.addresses 192.168.77.5/24 ipv4.routes '2.3.4.5/32 192.168.77.1' ipv6.addresses 1:2:3:4::6/64 ipv6.routes 1:2:3:4:5:6::5/128 lang: C returncode: 0 -size: 4765 +size: 4952 location: src/tests/client/test-client.py:test_004()/8 cmd: $NMCLI con s con-xx1 lang: C returncode: 0 -stdout: 4634 bytes +stdout: 4821 bytes >>> connection.id: con-xx1 connection.uuid: UUID-con-xx1-REPLACED-REPLACED-REPLA @@ -89,7 +89,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-11-wireless.ssid: foobar 802-11-wireless.mode: infrastructure 802-11-wireless.band: a @@ -133,6 +135,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -151,8 +154,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -166,12 +170,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 4793 +size: 4988 location: src/tests/client/test-client.py:test_004()/9 cmd: $NMCLI con s con-xx1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4652 bytes +stdout: 4847 bytes >>> connection.id: con-xx1 connection.uuid: UUID-con-xx1-REPLACED-REPLACED-REPLA @@ -197,7 +201,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 802-11-wireless.ssid: foobar 802-11-wireless.mode: infrastructure 802-11-wireless.band: a @@ -241,6 +247,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -259,8 +266,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -310,12 +318,12 @@ con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP vpn -- con-xx1 UUID-con-xx1-REPLACED-REPLACED-REPLA wifi -- <<< -size: 4179 +size: 4366 location: src/tests/client/test-client.py:test_004()/13 cmd: $NMCLI con s con-vpn-1 lang: C returncode: 0 -stdout: 4045 bytes +stdout: 4232 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -341,7 +349,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -367,6 +377,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -385,8 +396,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -406,12 +418,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 4199 +size: 4394 location: src/tests/client/test-client.py:test_004()/14 cmd: $NMCLI con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4055 bytes +stdout: 4250 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -437,7 +449,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -463,6 +477,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -481,8 +496,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -574,12 +590,12 @@ con-xx1 UUID-con-xx1-REPLACED-REPLACED-REPLA wifi wlan0 con-1 5fcfd6d7-1e63-3332-8826-a7eda103792d ethernet -- <<< -size: 5307 +size: 5494 location: src/tests/client/test-client.py:test_004()/21 cmd: $NMCLI con s con-vpn-1 lang: C returncode: 0 -stdout: 5173 bytes +stdout: 5360 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -605,7 +621,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -631,6 +649,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -649,8 +668,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -691,12 +711,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5333 +size: 5528 location: src/tests/client/test-client.py:test_004()/22 cmd: $NMCLI con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5189 bytes +stdout: 5384 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -722,7 +742,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -748,6 +770,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -766,8 +789,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -890,12 +914,12 @@ Strony podręcznika nmcli(1) i nmcli-examples(7) zawierają pełne informacje o użyciu. <<< -size: 5313 +size: 5500 location: src/tests/client/test-client.py:test_004()/25 cmd: $NMCLI con s con-vpn-1 lang: C returncode: 0 -stdout: 5179 bytes +stdout: 5366 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -921,7 +945,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -947,6 +973,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -965,8 +992,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -1007,12 +1035,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5343 +size: 5538 location: src/tests/client/test-client.py:test_004()/26 cmd: $NMCLI con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5199 bytes +stdout: 5394 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -1038,7 +1066,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -1064,6 +1094,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -1082,8 +1113,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -1124,12 +1156,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5313 +size: 5500 location: src/tests/client/test-client.py:test_004()/27 cmd: $NMCLI con s con-vpn-1 lang: C returncode: 0 -stdout: 5179 bytes +stdout: 5366 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -1155,7 +1187,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -1181,6 +1215,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -1199,8 +1234,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -1241,12 +1277,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5343 +size: 5538 location: src/tests/client/test-client.py:test_004()/28 cmd: $NMCLI con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5199 bytes +stdout: 5394 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -1272,7 +1308,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -1298,6 +1336,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -1316,8 +1355,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -1358,12 +1398,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 4186 +size: 4373 location: src/tests/client/test-client.py:test_004()/29 cmd: $NMCLI -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 4045 bytes +stdout: 4232 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -1389,7 +1429,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -1415,6 +1457,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -1433,8 +1476,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -1454,12 +1498,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 4206 +size: 4401 location: src/tests/client/test-client.py:test_004()/30 cmd: $NMCLI -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4055 bytes +stdout: 4250 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -1485,7 +1529,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -1511,6 +1557,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -1529,8 +1576,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -4144,12 +4192,12 @@ connection.type: 802-11-wireless connection.interface-name: -- <<< -size: 5325 +size: 5512 location: src/tests/client/test-client.py:test_004()/75 cmd: $NMCLI --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 5179 bytes +stdout: 5366 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -4175,7 +4223,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -4201,6 +4251,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -4219,8 +4270,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -4261,12 +4313,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5355 +size: 5550 location: src/tests/client/test-client.py:test_004()/76 cmd: $NMCLI --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5199 bytes +stdout: 5394 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -4292,7 +4344,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -4318,6 +4372,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -4336,8 +4391,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -4378,12 +4434,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5325 +size: 5512 location: src/tests/client/test-client.py:test_004()/77 cmd: $NMCLI --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 5179 bytes +stdout: 5366 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -4409,7 +4465,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -4435,6 +4493,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -4453,8 +4512,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -4495,12 +4555,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5355 +size: 5550 location: src/tests/client/test-client.py:test_004()/78 cmd: $NMCLI --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5199 bytes +stdout: 5394 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -4526,7 +4586,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -4552,6 +4614,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -4570,8 +4633,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -4612,12 +4676,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 4198 +size: 4385 location: src/tests/client/test-client.py:test_004()/79 cmd: $NMCLI --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 4045 bytes +stdout: 4232 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -4643,7 +4707,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -4669,6 +4735,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -4687,8 +4754,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -4708,12 +4776,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 4218 +size: 4413 location: src/tests/client/test-client.py:test_004()/80 cmd: $NMCLI --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4055 bytes +stdout: 4250 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -4739,7 +4807,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -4765,6 +4835,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -4783,8 +4854,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -7398,12 +7470,12 @@ connection.type: 802-11-wireless connection.interface-name: -- <<< -size: 6334 +size: 6521 location: src/tests/client/test-client.py:test_004()/125 cmd: $NMCLI --pretty con s con-vpn-1 lang: C returncode: 0 -stdout: 6190 bytes +stdout: 6377 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -7432,7 +7504,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -7459,6 +7533,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -7478,8 +7553,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -7528,12 +7604,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6377 +size: 6572 location: src/tests/client/test-client.py:test_004()/126 cmd: $NMCLI --pretty con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6223 bytes +stdout: 6418 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -7562,7 +7638,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -7589,6 +7667,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -7608,8 +7687,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -7658,12 +7738,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6334 +size: 6521 location: src/tests/client/test-client.py:test_004()/127 cmd: $NMCLI --pretty con s con-vpn-1 lang: C returncode: 0 -stdout: 6190 bytes +stdout: 6377 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -7692,7 +7772,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -7719,6 +7801,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -7738,8 +7821,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -7788,12 +7872,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6377 +size: 6572 location: src/tests/client/test-client.py:test_004()/128 cmd: $NMCLI --pretty con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6223 bytes +stdout: 6418 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -7822,7 +7906,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -7849,6 +7935,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -7868,8 +7955,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -7918,12 +8006,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 4815 +size: 5002 location: src/tests/client/test-client.py:test_004()/129 cmd: $NMCLI --pretty -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 4664 bytes +stdout: 4851 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -7952,7 +8040,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -7979,6 +8069,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -7998,8 +8089,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -8022,12 +8114,12 @@ proxy.pac-script: -- ------------------------------------------------------------------------------- <<< -size: 4840 +size: 5035 location: src/tests/client/test-client.py:test_004()/130 cmd: $NMCLI --pretty -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4679 bytes +stdout: 4874 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -8056,7 +8148,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -8083,6 +8177,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -8102,8 +8197,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -11324,12 +11420,12 @@ connection.interface-name: -- ------------------------------------------------------------------------------- <<< -size: 6346 +size: 6533 location: src/tests/client/test-client.py:test_004()/175 cmd: $NMCLI --pretty --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 6190 bytes +stdout: 6377 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -11358,7 +11454,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -11385,6 +11483,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -11404,8 +11503,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -11454,12 +11554,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6389 +size: 6584 location: src/tests/client/test-client.py:test_004()/176 cmd: $NMCLI --pretty --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6223 bytes +stdout: 6418 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -11488,7 +11588,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -11515,6 +11617,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -11534,8 +11637,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -11584,12 +11688,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6346 +size: 6533 location: src/tests/client/test-client.py:test_004()/177 cmd: $NMCLI --pretty --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 6190 bytes +stdout: 6377 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -11618,7 +11722,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -11645,6 +11751,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -11664,8 +11771,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -11714,12 +11822,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6389 +size: 6584 location: src/tests/client/test-client.py:test_004()/178 cmd: $NMCLI --pretty --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6223 bytes +stdout: 6418 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -11748,7 +11856,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -11775,6 +11885,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -11794,8 +11905,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -11844,12 +11956,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 4827 +size: 5014 location: src/tests/client/test-client.py:test_004()/179 cmd: $NMCLI --pretty --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 4664 bytes +stdout: 4851 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -11878,7 +11990,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -11905,6 +12019,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -11924,8 +12039,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -11948,12 +12064,12 @@ proxy.pac-script: -- ------------------------------------------------------------------------------- <<< -size: 4852 +size: 5047 location: src/tests/client/test-client.py:test_004()/180 cmd: $NMCLI --pretty --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4679 bytes +stdout: 4874 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -11982,7 +12098,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -12009,6 +12127,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -12028,8 +12147,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -15250,12 +15370,12 @@ connection.interface-name: -- ------------------------------------------------------------------------------- <<< -size: 2682 +size: 2770 location: src/tests/client/test-client.py:test_004()/225 cmd: $NMCLI --terse con s con-vpn-1 lang: C returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -15281,7 +15401,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -15307,6 +15429,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -15325,8 +15448,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -15367,12 +15491,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2692 +size: 2780 location: src/tests/client/test-client.py:test_004()/226 cmd: $NMCLI --terse con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -15398,7 +15522,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -15424,6 +15550,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -15442,8 +15569,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -15484,12 +15612,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2682 +size: 2770 location: src/tests/client/test-client.py:test_004()/227 cmd: $NMCLI --terse con s con-vpn-1 lang: C returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -15515,7 +15643,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -15541,6 +15671,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -15559,8 +15690,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -15601,12 +15733,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2692 +size: 2780 location: src/tests/client/test-client.py:test_004()/228 cmd: $NMCLI --terse con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -15632,7 +15764,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -15658,6 +15792,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -15676,8 +15811,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -15718,12 +15854,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2107 +size: 2195 location: src/tests/client/test-client.py:test_004()/229 cmd: $NMCLI --terse -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 1957 bytes +stdout: 2045 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -15749,7 +15885,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -15775,6 +15913,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -15793,8 +15932,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -15814,12 +15954,12 @@ proxy.pac-url: proxy.pac-script: <<< -size: 2117 +size: 2205 location: src/tests/client/test-client.py:test_004()/230 cmd: $NMCLI --terse -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 1957 bytes +stdout: 2045 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -15845,7 +15985,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -15871,6 +16013,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -15889,8 +16032,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -18474,12 +18618,12 @@ connection.type:802-11-wireless connection.interface-name: <<< -size: 2694 +size: 2782 location: src/tests/client/test-client.py:test_004()/275 cmd: $NMCLI --terse --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -18505,7 +18649,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -18531,6 +18677,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -18549,8 +18696,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -18591,12 +18739,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2704 +size: 2792 location: src/tests/client/test-client.py:test_004()/276 cmd: $NMCLI --terse --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -18622,7 +18770,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -18648,6 +18798,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -18666,8 +18817,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -18708,12 +18860,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2694 +size: 2782 location: src/tests/client/test-client.py:test_004()/277 cmd: $NMCLI --terse --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -18739,7 +18891,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -18765,6 +18919,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -18783,8 +18938,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -18825,12 +18981,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2704 +size: 2792 location: src/tests/client/test-client.py:test_004()/278 cmd: $NMCLI --terse --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -18856,7 +19012,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -18882,6 +19040,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -18900,8 +19059,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -18942,12 +19102,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2119 +size: 2207 location: src/tests/client/test-client.py:test_004()/279 cmd: $NMCLI --terse --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 1957 bytes +stdout: 2045 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -18973,7 +19133,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -18999,6 +19161,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -19017,8 +19180,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -19038,12 +19202,12 @@ proxy.pac-url: proxy.pac-script: <<< -size: 2129 +size: 2217 location: src/tests/client/test-client.py:test_004()/280 cmd: $NMCLI --terse --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 1957 bytes +stdout: 2045 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -19069,7 +19233,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -19095,6 +19261,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -19113,8 +19280,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -21698,21 +21866,21 @@ connection.type:802-11-wireless connection.interface-name: <<< -size: 3482 +size: 3594 location: src/tests/client/test-client.py:test_004()/325 cmd: $NMCLI --mode tabular con s con-vpn-1 lang: C returncode: 0 -stdout: 3332 bytes +stdout: 3444 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name service-type user-name data secrets persistent timeout vpn org.freedesktop.NetworkManager.openvpn -- key1 = val1, key2 = val2, key3 = val3 no 0 @@ -21727,21 +21895,21 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 3505 +size: 3633 location: src/tests/client/test-client.py:test_004()/326 cmd: $NMCLI --mode tabular con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3345 bytes +stdout: 3473 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name service-type user-name data secrets persistent timeout vpn org.freedesktop.NetworkManager.openvpn -- key1 = val1, key2 = val2, key3 = val3 nie 0 @@ -21756,21 +21924,21 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 3482 +size: 3594 location: src/tests/client/test-client.py:test_004()/327 cmd: $NMCLI --mode tabular con s con-vpn-1 lang: C returncode: 0 -stdout: 3332 bytes +stdout: 3444 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name service-type user-name data secrets persistent timeout vpn org.freedesktop.NetworkManager.openvpn -- key1 = val1, key2 = val2, key3 = val3 no 0 @@ -21785,21 +21953,21 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 3505 +size: 3633 location: src/tests/client/test-client.py:test_004()/328 cmd: $NMCLI --mode tabular con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3345 bytes +stdout: 3473 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name service-type user-name data secrets persistent timeout vpn org.freedesktop.NetworkManager.openvpn -- key1 = val1, key2 = val2, key3 = val3 nie 0 @@ -21814,21 +21982,21 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 2730 +size: 2842 location: src/tests/client/test-client.py:test_004()/329 cmd: $NMCLI --mode tabular -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 2573 bytes +stdout: 2685 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name service-type user-name data secrets persistent timeout vpn org.freedesktop.NetworkManager.openvpn -- key1 = val1, key2 = val2, key3 = val3 no 0 @@ -21838,21 +22006,21 @@ proxy none no -- -- <<< -size: 2742 +size: 2870 location: src/tests/client/test-client.py:test_004()/330 cmd: $NMCLI --mode tabular -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2575 bytes +stdout: 2703 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name service-type user-name data secrets persistent timeout vpn org.freedesktop.NetworkManager.openvpn -- key1 = val1, key2 = val2, key3 = val3 nie 0 @@ -23352,21 +23520,21 @@ interface-name <<< -size: 3494 +size: 3606 location: src/tests/client/test-client.py:test_004()/375 cmd: $NMCLI --mode tabular --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 3332 bytes +stdout: 3444 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name service-type user-name data secrets persistent timeout vpn org.freedesktop.NetworkManager.openvpn -- key1 = val1, key2 = val2, key3 = val3 no 0 @@ -23381,21 +23549,21 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 3517 +size: 3645 location: src/tests/client/test-client.py:test_004()/376 cmd: $NMCLI --mode tabular --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3345 bytes +stdout: 3473 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name service-type user-name data secrets persistent timeout vpn org.freedesktop.NetworkManager.openvpn -- key1 = val1, key2 = val2, key3 = val3 nie 0 @@ -23410,21 +23578,21 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 3494 +size: 3606 location: src/tests/client/test-client.py:test_004()/377 cmd: $NMCLI --mode tabular --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 3332 bytes +stdout: 3444 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name service-type user-name data secrets persistent timeout vpn org.freedesktop.NetworkManager.openvpn -- key1 = val1, key2 = val2, key3 = val3 no 0 @@ -23439,21 +23607,21 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 3517 +size: 3645 location: src/tests/client/test-client.py:test_004()/378 cmd: $NMCLI --mode tabular --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3345 bytes +stdout: 3473 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name service-type user-name data secrets persistent timeout vpn org.freedesktop.NetworkManager.openvpn -- key1 = val1, key2 = val2, key3 = val3 nie 0 @@ -23468,21 +23636,21 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 2742 +size: 2854 location: src/tests/client/test-client.py:test_004()/379 cmd: $NMCLI --mode tabular --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 2573 bytes +stdout: 2685 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name service-type user-name data secrets persistent timeout vpn org.freedesktop.NetworkManager.openvpn -- key1 = val1, key2 = val2, key3 = val3 no 0 @@ -23492,21 +23660,21 @@ proxy none no -- -- <<< -size: 2754 +size: 2882 location: src/tests/client/test-client.py:test_004()/380 cmd: $NMCLI --mode tabular --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2575 bytes +stdout: 2703 bytes >>> -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name service-type user-name data secrets persistent timeout vpn org.freedesktop.NetworkManager.openvpn -- key1 = val1, key2 = val2, key3 = val3 nie 0 @@ -25006,27 +25174,27 @@ interface-name <<< -size: 5493 +size: 5661 location: src/tests/client/test-client.py:test_004()/425 cmd: $NMCLI --mode tabular --pretty con s con-vpn-1 lang: C returncode: 0 -stdout: 5334 bytes +stdout: 5502 bytes >>> ========================================== Connection profile details (con-vpn-1) ========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name service-type user-name data secrets persistent timeout ------------------------------------------------------------------------------------------------------------------------------- @@ -25048,27 +25216,27 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 5555 +size: 5747 location: src/tests/client/test-client.py:test_004()/426 cmd: $NMCLI --mode tabular --pretty con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5386 bytes +stdout: 5578 bytes >>> ============================================ Szczegóły profilu połączenia (con-vpn-1) ============================================ -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name service-type user-name data secrets persistent timeout ------------------------------------------------------------------------------------------------------------------------------- @@ -25090,27 +25258,27 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 5493 +size: 5661 location: src/tests/client/test-client.py:test_004()/427 cmd: $NMCLI --mode tabular --pretty con s con-vpn-1 lang: C returncode: 0 -stdout: 5334 bytes +stdout: 5502 bytes >>> ========================================== Connection profile details (con-vpn-1) ========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name service-type user-name data secrets persistent timeout ------------------------------------------------------------------------------------------------------------------------------- @@ -25132,27 +25300,27 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 5555 +size: 5747 location: src/tests/client/test-client.py:test_004()/428 cmd: $NMCLI --mode tabular --pretty con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5386 bytes +stdout: 5578 bytes >>> ============================================ Szczegóły profilu połączenia (con-vpn-1) ============================================ -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name service-type user-name data secrets persistent timeout ------------------------------------------------------------------------------------------------------------------------------- @@ -25174,27 +25342,27 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 4155 +size: 4323 location: src/tests/client/test-client.py:test_004()/429 cmd: $NMCLI --mode tabular --pretty -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 3989 bytes +stdout: 4157 bytes >>> ========================================== Connection profile details (con-vpn-1) ========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name service-type user-name data secrets persistent timeout ------------------------------------------------------------------------------------------------------------------------------- @@ -25206,27 +25374,27 @@ proxy none no -- -- <<< -size: 4178 +size: 4370 location: src/tests/client/test-client.py:test_004()/430 cmd: $NMCLI --mode tabular --pretty -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4002 bytes +stdout: 4194 bytes >>> ============================================ Szczegóły profilu połączenia (con-vpn-1) ============================================ -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name service-type user-name data secrets persistent timeout ------------------------------------------------------------------------------------------------------------------------------- @@ -27314,27 +27482,27 @@ interface-name <<< -size: 5505 +size: 5673 location: src/tests/client/test-client.py:test_004()/475 cmd: $NMCLI --mode tabular --pretty --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 5334 bytes +stdout: 5502 bytes >>> ========================================== Connection profile details (con-vpn-1) ========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name service-type user-name data secrets persistent timeout ------------------------------------------------------------------------------------------------------------------------------- @@ -27356,27 +27524,27 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 5567 +size: 5759 location: src/tests/client/test-client.py:test_004()/476 cmd: $NMCLI --mode tabular --pretty --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5386 bytes +stdout: 5578 bytes >>> ============================================ Szczegóły profilu połączenia (con-vpn-1) ============================================ -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name service-type user-name data secrets persistent timeout ------------------------------------------------------------------------------------------------------------------------------- @@ -27398,27 +27566,27 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 5505 +size: 5673 location: src/tests/client/test-client.py:test_004()/477 cmd: $NMCLI --mode tabular --pretty --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 5334 bytes +stdout: 5502 bytes >>> ========================================== Connection profile details (con-vpn-1) ========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name service-type user-name data secrets persistent timeout ------------------------------------------------------------------------------------------------------------------------------- @@ -27440,27 +27608,27 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 - VPN connected key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 5567 +size: 5759 location: src/tests/client/test-client.py:test_004()/478 cmd: $NMCLI --mode tabular --pretty --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5386 bytes +stdout: 5578 bytes >>> ============================================ Szczegóły profilu połączenia (con-vpn-1) ============================================ -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name service-type user-name data secrets persistent timeout ------------------------------------------------------------------------------------------------------------------------------- @@ -27482,27 +27650,27 @@ NAME TYPE USERNAME GATEWAY BANNER VPN-STATE VPN openvpn -- -- *** VPN connection con-vpn-1 *** 5 — Połączono z VPN key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 4167 +size: 4335 location: src/tests/client/test-client.py:test_004()/479 cmd: $NMCLI --mode tabular --pretty --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 3989 bytes +stdout: 4157 bytes >>> ========================================== Connection profile details (con-vpn-1) ========================================== -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- yes 0 -1 (default) 0 (default) -1 0 no -- -- -- -- -1 (default) -- 0 unknown default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no -- -- 0 (default) yes -- -- 0x0 (none) no yes -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) yes -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- no no no yes -1 (default) -1 (unknown) default 0 (default) auto -- -- 0 (default) yes -- 0x0 (none) -- name service-type user-name data secrets persistent timeout ------------------------------------------------------------------------------------------------------------------------------- @@ -27514,27 +27682,27 @@ proxy none no -- -- <<< -size: 4190 +size: 4382 location: src/tests/client/test-client.py:test_004()/480 cmd: $NMCLI --mode tabular --pretty --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4002 bytes +stdout: 4194 bytes >>> ============================================ Szczegóły profilu połączenia (con-vpn-1) ============================================ -name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls wait-device-timeout ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) -1 +name id uuid stable-id type interface-name autoconnect autoconnect-priority autoconnect-retries multi-connect auth-retries timestamp read-only permissions zone master slave-type autoconnect-slaves secondaries gateway-ping-timeout metered lldp mdns llmnr dns-over-tls mptcp-flags wait-device-timeout wait-activation-delay +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +connection con-vpn-1 UUID-con-vpn-1-REPLACED-REPLACED-REP -- vpn -- tak 0 -1 (default) 0 (default) -1 0 nie -- -- -- -- -1 (default) -- 0 nieznane default -1 (default) -1 (default) -1 (default) 0x0 (default) -1 -1 -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier dhcp-reject-servers ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns dhcp-client-id dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-fqdn dhcp-hostname-flags never-default may-fail required-timeout dad-timeout dhcp-vendor-class-identifier link-local dhcp-reject-servers +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv4 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie -- -- 0 (default) tak -- -- 0x0 (none) nie tak -1 (default) -1 (default) -- 0 (default) -- -name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) stable-privacy 0 (default) -- -- 0 (default) tak -- 0x0 (none) -- +name method dns dns-search dns-options dns-priority addresses gateway routes route-metric route-table routing-rules ignore-auto-routes ignore-auto-dns never-default may-fail required-timeout ip6-privacy addr-gen-mode ra-timeout mtu dhcp-duid dhcp-iaid dhcp-timeout dhcp-send-hostname dhcp-hostname dhcp-hostname-flags token +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ipv6 auto -- -- -- 0 -- -- -- -1 0 (unspec) -- nie nie nie tak -1 (default) -1 (unknown) default 0 (default) automatyczne -- -- 0 (default) tak -- 0x0 (none) -- name service-type user-name data secrets persistent timeout ------------------------------------------------------------------------------------------------------------------------------- @@ -29622,94 +29790,94 @@ interface-name <<< -size: 823 +size: 830 location: src/tests/client/test-client.py:test_004()/525 cmd: $NMCLI --mode tabular --terse con s con-vpn-1 lang: C returncode: 0 -stdout: 666 bytes +stdout: 673 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3::no:0 proxy:none:no:: GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no:no::yes:/org/freedesktop/NetworkManager/ActiveConnection/2:/org/freedesktop/NetworkManager/Settings/Connection/3:: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 833 +size: 840 location: src/tests/client/test-client.py:test_004()/526 cmd: $NMCLI --mode tabular --terse con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 666 bytes +stdout: 673 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3::no:0 proxy:none:no:: GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no:no::yes:/org/freedesktop/NetworkManager/ActiveConnection/2:/org/freedesktop/NetworkManager/Settings/Connection/3:: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 823 +size: 830 location: src/tests/client/test-client.py:test_004()/527 cmd: $NMCLI --mode tabular --terse con s con-vpn-1 lang: C returncode: 0 -stdout: 666 bytes +stdout: 673 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3::no:0 proxy:none:no:: GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no:no::yes:/org/freedesktop/NetworkManager/ActiveConnection/2:/org/freedesktop/NetworkManager/Settings/Connection/3:: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 833 +size: 840 location: src/tests/client/test-client.py:test_004()/528 cmd: $NMCLI --mode tabular --terse con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 666 bytes +stdout: 673 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3::no:0 proxy:none:no:: GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no:no::yes:/org/freedesktop/NetworkManager/ActiveConnection/2:/org/freedesktop/NetworkManager/Settings/Connection/3:: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 530 +size: 537 location: src/tests/client/test-client.py:test_004()/529 cmd: $NMCLI --mode tabular --terse -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 366 bytes +stdout: 373 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3::no:0 proxy:none:no:: <<< -size: 540 +size: 547 location: src/tests/client/test-client.py:test_004()/530 cmd: $NMCLI --mode tabular --terse -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 366 bytes +stdout: 373 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3::no:0 proxy:none:no:: @@ -30560,94 +30728,94 @@ UUID-con-xx1-REPLACED-REPLACED-REPLA <<< -size: 835 +size: 842 location: src/tests/client/test-client.py:test_004()/575 cmd: $NMCLI --mode tabular --terse --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 666 bytes +stdout: 673 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3::no:0 proxy:none:no:: GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no:no::yes:/org/freedesktop/NetworkManager/ActiveConnection/2:/org/freedesktop/NetworkManager/Settings/Connection/3:: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 845 +size: 852 location: src/tests/client/test-client.py:test_004()/576 cmd: $NMCLI --mode tabular --terse --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 666 bytes +stdout: 673 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3::no:0 proxy:none:no:: GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no:no::yes:/org/freedesktop/NetworkManager/ActiveConnection/2:/org/freedesktop/NetworkManager/Settings/Connection/3:: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 835 +size: 842 location: src/tests/client/test-client.py:test_004()/577 cmd: $NMCLI --mode tabular --terse --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 666 bytes +stdout: 673 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3::no:0 proxy:none:no:: GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no:no::yes:/org/freedesktop/NetworkManager/ActiveConnection/2:/org/freedesktop/NetworkManager/Settings/Connection/3:: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 845 +size: 852 location: src/tests/client/test-client.py:test_004()/578 cmd: $NMCLI --mode tabular --terse --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 666 bytes +stdout: 673 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3::no:0 proxy:none:no:: GENERAL:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP:wlan0:wlan0:activated:no:no::yes:/org/freedesktop/NetworkManager/ActiveConnection/2:/org/freedesktop/NetworkManager/Settings/Connection/3:: VPN:openvpn:::*** VPN connection con-vpn-1 ***:5 - VPN connected:key1 = val1 | key2 = val2 | key3 = val3 <<< -size: 542 +size: 549 location: src/tests/client/test-client.py:test_004()/579 cmd: $NMCLI --mode tabular --terse --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 366 bytes +stdout: 373 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3::no:0 proxy:none:no:: <<< -size: 552 +size: 559 location: src/tests/client/test-client.py:test_004()/580 cmd: $NMCLI --mode tabular --terse --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 366 bytes +stdout: 373 bytes >>> -connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:-1 -ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1:: -ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:stable-privacy:0:::0:yes::0x0: +connection:con-vpn-1:UUID-con-vpn-1-REPLACED-REPLACED-REP::vpn::yes:0:-1:0:-1:0:no:::::-1::0:unknown:default:-1:-1:-1:0x0:-1:-1 +ipv4:auto::::0::::-1:0::no:no:::0:yes:::0x0:no:yes:-1:-1::0: +ipv6:auto::::0::::-1:0::no:no:no:yes:-1:-1:default:0:auto:::0:yes::0x0: vpn:org.freedesktop.NetworkManager.openvpn::key1 = val1, key2 = val2, key3 = val3::no:0 proxy:none:no:: @@ -31498,12 +31666,12 @@ UUID-con-xx1-REPLACED-REPLACED-REPLA <<< -size: 5331 +size: 5518 location: src/tests/client/test-client.py:test_004()/625 cmd: $NMCLI --mode multiline con s con-vpn-1 lang: C returncode: 0 -stdout: 5179 bytes +stdout: 5366 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -31529,7 +31697,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -31555,6 +31725,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -31573,8 +31744,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -31615,12 +31787,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5361 +size: 5556 location: src/tests/client/test-client.py:test_004()/626 cmd: $NMCLI --mode multiline con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5199 bytes +stdout: 5394 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -31646,7 +31818,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -31672,6 +31846,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -31690,8 +31865,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -31732,12 +31908,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5331 +size: 5518 location: src/tests/client/test-client.py:test_004()/627 cmd: $NMCLI --mode multiline con s con-vpn-1 lang: C returncode: 0 -stdout: 5179 bytes +stdout: 5366 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -31763,7 +31939,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -31789,6 +31967,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -31807,8 +31986,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -31849,12 +32029,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5361 +size: 5556 location: src/tests/client/test-client.py:test_004()/628 cmd: $NMCLI --mode multiline con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5199 bytes +stdout: 5394 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -31880,7 +32060,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -31906,6 +32088,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -31924,8 +32107,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -31966,12 +32150,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 4204 +size: 4391 location: src/tests/client/test-client.py:test_004()/629 cmd: $NMCLI --mode multiline -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 4045 bytes +stdout: 4232 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -31997,7 +32181,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -32023,6 +32209,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -32041,8 +32228,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -32062,12 +32250,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 4224 +size: 4419 location: src/tests/client/test-client.py:test_004()/630 cmd: $NMCLI --mode multiline -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4055 bytes +stdout: 4250 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -32093,7 +32281,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -32119,6 +32309,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -32137,8 +32328,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -35252,12 +35444,12 @@ connection.type: 802-11-wireless connection.interface-name: -- <<< -size: 5343 +size: 5530 location: src/tests/client/test-client.py:test_004()/675 cmd: $NMCLI --mode multiline --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 5179 bytes +stdout: 5366 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -35283,7 +35475,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -35309,6 +35503,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -35327,8 +35522,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -35369,12 +35565,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5373 +size: 5568 location: src/tests/client/test-client.py:test_004()/676 cmd: $NMCLI --mode multiline --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5199 bytes +stdout: 5394 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -35400,7 +35596,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -35426,6 +35624,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -35444,8 +35643,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -35486,12 +35686,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5343 +size: 5530 location: src/tests/client/test-client.py:test_004()/677 cmd: $NMCLI --mode multiline --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 5179 bytes +stdout: 5366 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -35517,7 +35717,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -35543,6 +35745,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -35561,8 +35764,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -35603,12 +35807,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 5373 +size: 5568 location: src/tests/client/test-client.py:test_004()/678 cmd: $NMCLI --mode multiline --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 5199 bytes +stdout: 5394 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -35634,7 +35838,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -35660,6 +35866,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -35678,8 +35885,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -35720,12 +35928,12 @@ VPN.CFG[2]: key2 = val2 VPN.CFG[3]: key3 = val3 <<< -size: 4216 +size: 4403 location: src/tests/client/test-client.py:test_004()/679 cmd: $NMCLI --mode multiline --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 4045 bytes +stdout: 4232 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -35751,7 +35959,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -35777,6 +35987,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -35795,8 +36006,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -35816,12 +36028,12 @@ proxy.pac-url: -- proxy.pac-script: -- <<< -size: 4236 +size: 4431 location: src/tests/client/test-client.py:test_004()/680 cmd: $NMCLI --mode multiline --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4055 bytes +stdout: 4250 bytes >>> connection.id: con-vpn-1 connection.uuid: UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -35847,7 +36059,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- @@ -35873,6 +36087,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ipv6.method: auto ipv6.dns: -- @@ -35891,8 +36106,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -39006,12 +39222,12 @@ connection.type: 802-11-wireless connection.interface-name: -- <<< -size: 6351 +size: 6538 location: src/tests/client/test-client.py:test_004()/725 cmd: $NMCLI --mode multiline --pretty con s con-vpn-1 lang: C returncode: 0 -stdout: 6190 bytes +stdout: 6377 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -39040,7 +39256,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -39067,6 +39285,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -39086,8 +39305,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -39136,12 +39356,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6394 +size: 6589 location: src/tests/client/test-client.py:test_004()/726 cmd: $NMCLI --mode multiline --pretty con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6223 bytes +stdout: 6418 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -39170,7 +39390,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -39197,6 +39419,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -39216,8 +39439,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -39266,12 +39490,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6351 +size: 6538 location: src/tests/client/test-client.py:test_004()/727 cmd: $NMCLI --mode multiline --pretty con s con-vpn-1 lang: C returncode: 0 -stdout: 6190 bytes +stdout: 6377 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -39300,7 +39524,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -39327,6 +39553,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -39346,8 +39573,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -39396,12 +39624,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6394 +size: 6589 location: src/tests/client/test-client.py:test_004()/728 cmd: $NMCLI --mode multiline --pretty con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6223 bytes +stdout: 6418 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -39430,7 +39658,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -39457,6 +39687,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -39476,8 +39707,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -39526,12 +39758,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 4832 +size: 5019 location: src/tests/client/test-client.py:test_004()/729 cmd: $NMCLI --mode multiline --pretty -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 4664 bytes +stdout: 4851 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -39560,7 +39792,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -39587,6 +39821,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -39606,8 +39841,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -39630,12 +39866,12 @@ proxy.pac-script: -- ------------------------------------------------------------------------------- <<< -size: 4857 +size: 5052 location: src/tests/client/test-client.py:test_004()/730 cmd: $NMCLI --mode multiline --pretty -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4679 bytes +stdout: 4874 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -39664,7 +39900,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -39691,6 +39929,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -39710,8 +39949,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -43462,12 +43702,12 @@ connection.interface-name: -- ------------------------------------------------------------------------------- <<< -size: 6363 +size: 6550 location: src/tests/client/test-client.py:test_004()/775 cmd: $NMCLI --mode multiline --pretty --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 6190 bytes +stdout: 6377 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -43496,7 +43736,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -43523,6 +43765,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -43542,8 +43785,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -43592,12 +43836,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6406 +size: 6601 location: src/tests/client/test-client.py:test_004()/776 cmd: $NMCLI --mode multiline --pretty --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6223 bytes +stdout: 6418 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -43626,7 +43870,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -43653,6 +43899,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -43672,8 +43919,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -43722,12 +43970,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6363 +size: 6550 location: src/tests/client/test-client.py:test_004()/777 cmd: $NMCLI --mode multiline --pretty --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 6190 bytes +stdout: 6377 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -43756,7 +44004,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -43783,6 +44033,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -43802,8 +44053,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -43852,12 +44104,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 6406 +size: 6601 location: src/tests/client/test-client.py:test_004()/778 cmd: $NMCLI --mode multiline --pretty --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 6223 bytes +stdout: 6418 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -43886,7 +44138,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -43913,6 +44167,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -43932,8 +44187,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -43982,12 +44238,12 @@ VPN.CFG[3]: key3 = val3 ------------------------------------------------------------------------------- <<< -size: 4844 +size: 5031 location: src/tests/client/test-client.py:test_004()/779 cmd: $NMCLI --mode multiline --pretty --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 4664 bytes +stdout: 4851 bytes >>> =============================================================================== Connection profile details (con-vpn-1) @@ -44016,7 +44272,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -44043,6 +44301,7 @@ ipv4.may-fail: yes ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -44062,8 +44321,9 @@ ipv6.never-default: no ipv6.may-fail: yes ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: auto ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -44086,12 +44346,12 @@ proxy.pac-script: -- ------------------------------------------------------------------------------- <<< -size: 4869 +size: 5064 location: src/tests/client/test-client.py:test_004()/780 cmd: $NMCLI --mode multiline --pretty --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 4679 bytes +stdout: 4874 bytes >>> =============================================================================== Szczegóły profilu połączenia (con-vpn-1) @@ -44120,7 +44380,9 @@ connection.lldp: default connection.mdns: -1 (default) connection.llmnr: -1 (default) connection.dns-over-tls: -1 (default) +connection.mptcp-flags: 0x0 (default) connection.wait-device-timeout: -1 +connection.wait-activation-delay: -1 ------------------------------------------------------------------------------- ipv4.method: auto ipv4.dns: -- @@ -44147,6 +44409,7 @@ ipv4.may-fail: tak ipv4.required-timeout: -1 (default) ipv4.dad-timeout: -1 (default) ipv4.dhcp-vendor-class-identifier: -- +ipv4.link-local: 0 (default) ipv4.dhcp-reject-servers: -- ------------------------------------------------------------------------------- ipv6.method: auto @@ -44166,8 +44429,9 @@ ipv6.never-default: nie ipv6.may-fail: tak ipv6.required-timeout: -1 (default) ipv6.ip6-privacy: -1 (unknown) -ipv6.addr-gen-mode: stable-privacy +ipv6.addr-gen-mode: default ipv6.ra-timeout: 0 (default) +ipv6.mtu: automatyczne ipv6.dhcp-duid: -- ipv6.dhcp-iaid: -- ipv6.dhcp-timeout: 0 (default) @@ -47918,12 +48182,12 @@ connection.interface-name: -- ------------------------------------------------------------------------------- <<< -size: 2699 +size: 2787 location: src/tests/client/test-client.py:test_004()/825 cmd: $NMCLI --mode multiline --terse con s con-vpn-1 lang: C returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -47949,7 +48213,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -47975,6 +48241,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -47993,8 +48260,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -48035,12 +48303,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2709 +size: 2797 location: src/tests/client/test-client.py:test_004()/826 cmd: $NMCLI --mode multiline --terse con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -48066,7 +48334,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -48092,6 +48362,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -48110,8 +48381,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -48152,12 +48424,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2699 +size: 2787 location: src/tests/client/test-client.py:test_004()/827 cmd: $NMCLI --mode multiline --terse con s con-vpn-1 lang: C returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -48183,7 +48455,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -48209,6 +48483,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -48227,8 +48502,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -48269,12 +48545,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2709 +size: 2797 location: src/tests/client/test-client.py:test_004()/828 cmd: $NMCLI --mode multiline --terse con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -48300,7 +48576,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -48326,6 +48604,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -48344,8 +48623,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -48386,12 +48666,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2124 +size: 2212 location: src/tests/client/test-client.py:test_004()/829 cmd: $NMCLI --mode multiline --terse -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 1957 bytes +stdout: 2045 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -48417,7 +48697,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -48443,6 +48725,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -48461,8 +48744,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -48482,12 +48766,12 @@ proxy.pac-url: proxy.pac-script: <<< -size: 2134 +size: 2222 location: src/tests/client/test-client.py:test_004()/830 cmd: $NMCLI --mode multiline --terse -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 1957 bytes +stdout: 2045 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -48513,7 +48797,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -48539,6 +48825,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -48557,8 +48844,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -51672,12 +51960,12 @@ connection.type:802-11-wireless connection.interface-name: <<< -size: 2711 +size: 2799 location: src/tests/client/test-client.py:test_004()/875 cmd: $NMCLI --mode multiline --terse --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -51703,7 +51991,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -51729,6 +52019,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -51747,8 +52038,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -51789,12 +52081,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2721 +size: 2809 location: src/tests/client/test-client.py:test_004()/876 cmd: $NMCLI --mode multiline --terse --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -51820,7 +52112,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -51846,6 +52140,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -51864,8 +52159,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -51906,12 +52202,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2711 +size: 2799 location: src/tests/client/test-client.py:test_004()/877 cmd: $NMCLI --mode multiline --terse --color yes con s con-vpn-1 lang: C returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -51937,7 +52233,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -51963,6 +52261,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -51981,8 +52280,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -52023,12 +52323,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2721 +size: 2809 location: src/tests/client/test-client.py:test_004()/878 cmd: $NMCLI --mode multiline --terse --color yes con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 2539 bytes +stdout: 2627 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -52054,7 +52354,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -52080,6 +52382,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -52098,8 +52401,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -52140,12 +52444,12 @@ VPN.CFG[2]:key2 = val2 VPN.CFG[3]:key3 = val3 <<< -size: 2136 +size: 2224 location: src/tests/client/test-client.py:test_004()/879 cmd: $NMCLI --mode multiline --terse --color yes -f ALL con s con-vpn-1 lang: C returncode: 0 -stdout: 1957 bytes +stdout: 2045 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -52171,7 +52475,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -52197,6 +52503,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -52215,8 +52522,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 @@ -52236,12 +52544,12 @@ proxy.pac-url: proxy.pac-script: <<< -size: 2146 +size: 2234 location: src/tests/client/test-client.py:test_004()/880 cmd: $NMCLI --mode multiline --terse --color yes -f ALL con s con-vpn-1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 1957 bytes +stdout: 2045 bytes >>> connection.id:con-vpn-1 connection.uuid:UUID-con-vpn-1-REPLACED-REPLACED-REP @@ -52267,7 +52575,9 @@ connection.lldp:default connection.mdns:-1 connection.llmnr:-1 connection.dns-over-tls:-1 +connection.mptcp-flags:0x0 connection.wait-device-timeout:-1 +connection.wait-activation-delay:-1 ipv4.method:auto ipv4.dns: ipv4.dns-search: @@ -52293,6 +52603,7 @@ ipv4.may-fail:yes ipv4.required-timeout:-1 ipv4.dad-timeout:-1 ipv4.dhcp-vendor-class-identifier: +ipv4.link-local:0 ipv4.dhcp-reject-servers: ipv6.method:auto ipv6.dns: @@ -52311,8 +52622,9 @@ ipv6.never-default:no ipv6.may-fail:yes ipv6.required-timeout:-1 ipv6.ip6-privacy:-1 -ipv6.addr-gen-mode:stable-privacy +ipv6.addr-gen-mode:default ipv6.ra-timeout:0 +ipv6.mtu:auto ipv6.dhcp-duid: ipv6.dhcp-iaid: ipv6.dhcp-timeout:0 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 00000000..fcb59f0e --- /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: 312 +location: src/tests/client/test-client.py:test_offline()/2 +cmd: $NMCLI --offline c add type ethernet +lang: C +returncode: 0 +stdout: 162 bytes +>>> +[connection] +id=ethernet +uuid=UUID-WAS-HERE-BUT-IS-NO-MORE-SADLY +type=ethernet + +[ethernet] + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=default +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: 436 +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: 225 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=default +method=auto + +[proxy] + +<<< +size: 474 +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: 229 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=default +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 d025d12e..6b2c51f5 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, @@ -108,6 +120,7 @@ import random import dbus.service import dbus.mainloop.glib import io +import pexpect ############################################################################### @@ -202,6 +215,13 @@ class Util: t = basestring 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 = [] @@ -334,6 +354,48 @@ class Util: except: 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: @@ -342,27 +404,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 +709,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 = [] @@ -774,6 +838,47 @@ class TestNmcli(NmTestBase): frame, ) + def call_nmcli_pexpect(self, args): + env = self._env() + return pexpect.spawn( + conf.get(ENV_NM_TEST_CLIENT_NMCLI_PATH), args, timeout=5, env=env + ) + + def _env( + self, lang="C", calling_num=None, fatal_warnings=_DEFAULT_ARG, extra_env=None + ): + if lang == "C": + language = "" + elif lang == "de_DE.utf8": + language = "de" + elif lang == "pl_PL.UTF-8": + language = "pl" + else: + self.fail("invalid language %s" % (lang)) + + env = {} + for k in ["LD_LIBRARY_PATH", "DBUS_SESSION_BUS_ADDRESS"]: + val = os.environ.get(k, None) + if val is not None: + env[k] = val + env["LANG"] = lang + env["LANGUAGE"] = language + env["LIBNM_USE_SESSION_BUS"] = "1" + env["LIBNM_USE_NO_UDEV"] = "1" + env["TERM"] = "linux" + env["ASAN_OPTIONS"] = conf.get(ENV_NM_TEST_ASAN_OPTIONS) + env["LSAN_OPTIONS"] = conf.get(ENV_NM_TEST_LSAN_OPTIONS) + env["LBSAN_OPTIONS"] = conf.get(ENV_NM_TEST_UBSAN_OPTIONS) + env["XDG_CONFIG_HOME"] = PathConfiguration.srcdir() + if calling_num is not None: + 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 + return env + def _call_nmcli( self, args, @@ -826,37 +931,13 @@ class TestNmcli(NmTestBase): if lang is None or lang == "C": lang = "C" - language = "" elif lang == "de": lang = "de_DE.utf8" - language = "de" elif lang == "pl": lang = "pl_PL.UTF-8" - language = "pl" else: 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: - env[k] = val - env["LANG"] = lang - env["LANGUAGE"] = language - env["LIBNM_USE_SESSION_BUS"] = "1" - env["LIBNM_USE_NO_UDEV"] = "1" - env["TERM"] = "linux" - env["ASAN_OPTIONS"] = conf.get(ENV_NM_TEST_ASAN_OPTIONS) - env["LSAN_OPTIONS"] = conf.get(ENV_NM_TEST_LSAN_OPTIONS) - env["LBSAN_OPTIONS"] = conf.get(ENV_NM_TEST_UBSAN_OPTIONS) - env["XDG_CONFIG_HOME"] = PathConfiguration.srcdir() - env["NM_TEST_CALLING_NUM"] = str(calling_num) - if fatal_warnings is _DEFAULT_ARG or fatal_warnings: - env["G_DEBUG"] = "fatal-warnings" - args = [conf.get(ENV_NM_TEST_CLIENT_NMCLI_PATH)] + list(args) if replace_stdout is not None: @@ -967,6 +1048,7 @@ class TestNmcli(NmTestBase): "content": content, } + env = self._env(lang, calling_num, fatal_warnings, extra_env) async_job = AsyncProcess(args=args, env=env, complete_cb=complete_cb) self._async_jobs.append(async_job) @@ -1012,26 +1094,22 @@ 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 results = self._results self._results = None + if len(results) == 0: + return + skip_test_for_l10n_diff = self._skip_test_for_l10n_diff self._skip_test_for_l10n_diff = None @@ -1130,7 +1208,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 +1314,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 +1327,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 +1359,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 +1488,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 +1534,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 +1744,126 @@ 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, + ) + + @nm_test + def test_ask_mode(self): + nmc = self.call_nmcli_pexpect(["--ask", "c", "add"]) + nmc.expect("Connection type:") + nmc.sendline("ethernet") + nmc.expect("Interface name:") + nmc.sendline("eth0") + nmc.expect("There are 3 optional settings for Wired Ethernet.") + nmc.expect("Do you want to provide them\? \(yes/no\) \[yes]") + nmc.sendline("no") + nmc.expect("There are 2 optional settings for IPv4 protocol.") + nmc.expect("Do you want to provide them\? \(yes/no\) \[yes]") + nmc.sendline("no") + nmc.expect("There are 2 optional settings for IPv6 protocol.") + nmc.expect("Do you want to provide them\? \(yes/no\) \[yes]") + nmc.sendline("no") + nmc.expect("There are 4 optional settings for Proxy.") + nmc.expect("Do you want to provide them\? \(yes/no\) \[yes]") + nmc.sendline("no") + nmc.expect("Connection 'ethernet' \(.*\) successfully added.") + nmc.expect(pexpect.EOF) + ############################################################################### -- cgit 1.3.0-6-gf8a5