From the upstream NEWS file: =============================================== NetworkManager-1.30.6 Overview of changes since NetworkManager-1.30.4 =============================================== * By default, don't touch existing traffic control (TC) configuration on devices. * Send ARP announcements only when the interface gets carrier. * Support the 'peer_notif_delay' bond option. * Always start DHCPv6 on the default interface when an IPv6 prefix delegation is needed. * Prefer the IPv4 address to determine the system hostname via address lookup. * Support DHCP option 249 (Microsoft classless static route) with the internal nettools client. * Force a restart of hostname resolution via DNS on signal SIGUSR1 when resolv.conf is not managed by NetworkManager. * Fix adding duplicate iptables rules for shared mode. * Fix parsing of Wi-Fi Information Element (IE) for Microsoft Network Cost. * Fix parsing of empty DHCP option 40 (NIS domain name) in the internal nettools client. * Other various bugfixes. =============================================== NetworkManager-1.30.4 Overview of changes since NetworkManager-1.30.2 =============================================== * Fix crash evaluating match setting properties (CVE-2021-20297). * Fix leak of local route added by NetworkManager for configured addresses. * Fix name of the device autoconnect D-Bus property. * Multiple bugfixes in the initrd generator. * Various minor bugfixes. =============================================== NetworkManager-1.30.2 Overview of changes since NetworkManager-1.30.0 =============================================== * Increase the limit of open file descriptors in NetworkManager.service * Fix hostname lookup via DNS when resolv.conf is managed by systemd-resolved * Enable WPA3 for Wi-Fi connections with key_mgmt=WPA-PSK * Fix crash with the IWD Wi-Fi backend * Avoid logging warning when setting bond option "ad_actor_system=00:00:00:00:00:00" * Update SpecificObject D-Bus property of ActiveConnection after WiFi roaming * Multiple bugfixes in the initrd generator * Various minor bugfixes Am 18.09.21 um 20:41 schrieb Michael Biebl:
Package: release.debian.org Severity: normal Tags: bullseye User: release.debian.org@packages.debian.org Usertags: pu Hi, I'd like to make a stable upload for network-manager. Debian bullseye currently shis 1.30.0. Upstream provides stable branches for 1.X, in this case 1.30.x, where only bug fixes are backported. The current release from that branch [1] is 1.30.6. I've been shipping 1.30.6-1 in unstable for several without any reported regressions and I'd like to ship that version for stable as well as a simple rebuild. The full debdiff is attached. If you prefer, I can provide a filtered debdiff, where changes to build system and the generated .html files are excluded. Thanks for considering. Regards, Michael [1] https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/tree/nm-1-30
diff --git a/Makefile.am b/Makefile.am index 9279672c1f..c8e417729b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3300,6 +3300,7 @@ EXTRA_DIST += \ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected \ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc \ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write.cexpected \ + src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write-empty.cexpected \ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 \ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 \ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-invalid \ diff --git a/Makefile.in b/Makefile.in index 1aa0d7036e..f9a761d6d3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4574,6 +4574,7 @@ EXTRA_DIST = shared/c-stdaux/src/c-stdaux.h $(NULL) \ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected \ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc \ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write.cexpected \ + src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write-empty.cexpected \ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-1 \ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-2 \ src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-team-master-invalid \ diff --git a/NEWS b/NEWS index f65738e505..fd22a52a1c 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,56 @@ +=============================================== +NetworkManager-1.30.6 +Overview of changes since NetworkManager-1.30.4 +=============================================== + +* By default, don't touch existing traffic control (TC) configuration + on devices. +* Send ARP announcements only when the interface gets carrier. +* Support the 'peer_notif_delay' bond option. +* Always start DHCPv6 on the default interface when an IPv6 prefix + delegation is needed. +* Prefer the IPv4 address to determine the system hostname via address + lookup. +* Support DHCP option 249 (Microsoft classless static route) with the + internal nettools client. +* Force a restart of hostname resolution via DNS on signal SIGUSR1 + when resolv.conf is not managed by NetworkManager. +* Fix adding duplicate iptables rules for shared mode. +* Fix parsing of Wi-Fi Information Element (IE) for Microsoft Network + Cost. +* Fix parsing of empty DHCP option 40 (NIS domain name) in the + internal nettools client. +* Other various bugfixes. + +=============================================== +NetworkManager-1.30.4 +Overview of changes since NetworkManager-1.30.2 +=============================================== + +* Fix crash evaluating match setting properties (CVE-2021-20297). +* Fix leak of local route added by NetworkManager for configured + addresses. +* Fix name of the device autoconnect D-Bus property. +* Multiple bugfixes in the initrd generator. +* Various minor bugfixes. + +=============================================== +NetworkManager-1.30.2 +Overview of changes since NetworkManager-1.30.0 +=============================================== + +* Increase the limit of open file descriptors in NetworkManager.service +* Fix hostname lookup via DNS when resolv.conf is managed by + systemd-resolved +* Enable WPA3 for Wi-Fi connections with key_mgmt=WPA-PSK +* Fix crash with the IWD Wi-Fi backend +* Avoid logging warning when setting bond option + "ad_actor_system=00:00:00:00:00:00" +* Update SpecificObject D-Bus property of ActiveConnection after WiFi + roaming +* Multiple bugfixes in the initrd generator +* Various minor bugfixes + ============================================= NetworkManager-1.30 Overview of changes since NetworkManager-1.28 diff --git a/aclocal.m4 b/aclocal.m4 index e3d5eee31a..27676944f5 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1292,12 +1292,14 @@ AC_DEFUN([AM_PATH_PYTHON], m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])]) else - dnl Query Python for its version number. Getting [:3] seems to be - dnl the best way to do this; it's what "site.py" does in the standard - dnl library. + dnl Query Python for its version number. Although site.py simply uses + dnl sys.version[:3], printing that failed with Python 3.10, since the + dnl trailing zero was eliminated. So now we output just the major + dnl and minor version numbers, as numbers. Apparently the tertiary + dnl version is not of interest. AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], - [am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`]) + [am_cv_python_version=`$PYTHON -c "import sys; print('%u.%u' % sys.version_info[[:2]])"`]) AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) dnl Use the values of $prefix and $exec_prefix for the corresponding diff --git a/clients/cli/connections.c b/clients/cli/connections.c index ee7b8fbbe9..fe4f8855cb 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -19,6 +19,7 @@ #include "nm-vpn-helpers.h" #include "nm-meta-setting-access.h" #include "nm-secret-agent-simple.h" +#include "nm-glib-aux/nm-dbus-aux.h" #include "utils.h" #include "common.h" @@ -9184,28 +9185,42 @@ do_connection_monitor(const NMCCommand *cmd, NmCli *nmc, int argc, const char *c } static void -do_connection_reload(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) +connection_reload_cb(GObject *source, GAsyncResult *result, gpointer user_data) { - gs_unref_variant GVariant *result = NULL; - gs_free_error GError *error = NULL; - - next_arg(nmc, &argc, &argv, NULL); - if (nmc->complete) - return; + NmCli * nmc = user_data; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *ret = NULL; - result = nmc_dbus_call_sync(nmc, - "/org/freedesktop/NetworkManager/Settings", - "org.freedesktop.NetworkManager.Settings", - "ReloadConnections", - g_variant_new("()"), - G_VARIANT_TYPE("(b)"), - &error); + ret = nm_dbus_call_finish(result, &error); if (error) { g_string_printf(nmc->return_text, _("Error: failed to reload connections: %s."), nmc_error_get_simple_message(error)); nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; } + + quit(); +} + +static void +do_connection_reload(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) +{ + next_arg(nmc, &argc, &argv, NULL); + if (nmc->complete) + return; + + nmc->should_wait++; + nm_dbus_call(G_BUS_TYPE_SYSTEM, + NM_DBUS_SERVICE, + NM_DBUS_PATH_SETTINGS, + NM_DBUS_INTERFACE_SETTINGS, + "ReloadConnections", + g_variant_new("()"), + G_VARIANT_TYPE("(b)"), + NULL, + (nmc->timeout == -1 ? 90 : nmc->timeout) * 1000, + connection_reload_cb, + nmc); } static void diff --git a/clients/cli/devices.c b/clients/cli/devices.c index eea82653c0..5800fe760d 100644 --- a/clients/cli/devices.c +++ b/clients/cli/devices.c @@ -4595,7 +4595,7 @@ print_wifi_connection(const NmcConfig *nmc_config, NMConnection *connection) const char * psk = NULL; const char * type = NULL; GBytes * ssid_bytes; - char * ssid; + gs_free char * ssid = NULL; GString * string; s_wireless = nm_connection_get_setting_wireless(connection); diff --git a/clients/cli/general.c b/clients/cli/general.c index 1dae57e116..b1182709f7 100644 --- a/clients/cli/general.c +++ b/clients/cli/general.c @@ -10,6 +10,7 @@ #include "nm-libnm-core-intern/nm-common-macros.h" #include "nm-client-utils.h" +#include "nm-glib-aux/nm-dbus-aux.h" #include "polkit-agent.h" #include "utils.h" @@ -344,7 +345,8 @@ usage_general_reload(void) " can be reloaded through 'nmcli connection reload' instead.\n" "\n" " 'dns-rc' Update DNS configuration, which usually involves writing\n" - " /etc/resolv.conf anew.\n" + " /etc/resolv.conf anew. This is equivalent to sending the\n" + " SIGUSR1 signal to the NetworkManager process.\n" "\n" " 'dns-full' Restart the DNS plugin. This is for example useful when\n" " using dnsmasq plugin, which uses additional configuration\n" @@ -598,15 +600,31 @@ show_nm_permissions(NmCli *nmc) return TRUE; } +static void +reload_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + NmCli * nmc = user_data; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *ret = NULL; + + ret = nm_dbus_call_finish(result, &error); + if (error) { + g_string_printf(nmc->return_text, + _("Error: failed to reload: %s"), + nmc_error_get_simple_message(error)); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + } + + quit(); +} + static void do_general_reload(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) { - gs_unref_variant GVariant *result = NULL; - gs_free_error GError *error = NULL; - gs_free const char ** values = NULL; - gs_free char * err_token = NULL; - gs_free char * joined = NULL; - int flags = 0; + gs_free const char **values = NULL; + gs_free char * err_token = NULL; + gs_free char * joined = NULL; + int flags = 0; next_arg(nmc, &argc, &argv, NULL); @@ -649,20 +667,18 @@ do_general_reload(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const return; } - result = nmc_dbus_call_sync(nmc, - "/org/freedesktop/NetworkManager", - "org.freedesktop.NetworkManager", - "Reload", - g_variant_new("(u)", flags), - G_VARIANT_TYPE("()"), - &error); - - if (error) { - g_string_printf(nmc->return_text, - _("Error: failed to reload: %s"), - nmc_error_get_simple_message(error)); - nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; - } + nmc->should_wait++; + nm_dbus_call(G_BUS_TYPE_SYSTEM, + NM_DBUS_SERVICE, + NM_DBUS_PATH, + NM_DBUS_INTERFACE, + "Reload", + g_variant_new("(u)", flags), + G_VARIANT_TYPE("()"), + NULL, + (nmc->timeout == -1 ? 90 : nmc->timeout) * 1000, + reload_cb, + nmc); } static void diff --git a/clients/cli/generate-docs-nm-settings-nmcli.xml b/clients/cli/generate-docs-nm-settings-nmcli.xml index 1044ae0d38..0a75a0e681 100644 --- a/clients/cli/generate-docs-nm-settings-nmcli.xml +++ b/clients/cli/generate-docs-nm-settings-nmcli.xml @@ -914,9 +914,9 @@ </setting> <setting name="tc" > <property name="qdiscs" - description="Array of TC queueing disciplines." /> + description="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." /> <property name="tfilters" - description="Array of TC traffic filters." /> + description="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." /> </setting> <setting name="team" > <property name="config" diff --git a/clients/cli/generate-docs-nm-settings-nmcli.xml.in b/clients/cli/generate-docs-nm-settings-nmcli.xml.in index 1044ae0d38..0a75a0e681 100644 --- a/clients/cli/generate-docs-nm-settings-nmcli.xml.in +++ b/clients/cli/generate-docs-nm-settings-nmcli.xml.in @@ -914,9 +914,9 @@ </setting> <setting name="tc" > <property name="qdiscs" - description="Array of TC queueing disciplines." /> + description="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." /> <property name="tfilters" - description="Array of TC traffic filters." /> + description="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." /> </setting> <setting name="team" > <property name="config" diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index b6e3d671fa..744def6313 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -864,7 +864,7 @@ _get_fcn_gobject_impl(const NMMetaPropertyInfo *property_info, * signal them differently. */ cstr = g_value_get_string(&val); nm_assert((!!is_default) == (cstr == NULL)); - RETURN_STR_EMPTYUNSET(get_type, is_default, NULL); + RETURN_STR_EMPTYUNSET(get_type, is_default, cstr); } } diff --git a/clients/common/nm-secret-agent-simple.c b/clients/common/nm-secret-agent-simple.c index 1857432538..35c3ed3d30 100644 --- a/clients/common/nm-secret-agent-simple.c +++ b/clients/common/nm-secret-agent-simple.c @@ -867,7 +867,7 @@ request_secrets_from_ui(RequestData *request) if (nm_connection_is_type(request->connection, NM_SETTING_WIRELESS_SETTING_NAME)) { NMSettingWireless *s_wireless; GBytes * ssid; - char * ssid_utf8; + gs_free char * ssid_utf8 = NULL; s_wireless = nm_connection_get_setting_wireless(request->connection); ssid = nm_setting_wireless_get_ssid(s_wireless); diff --git a/clients/common/settings-docs.h b/clients/common/settings-docs.h index 2c275a99c8..7c3ff25fe3 100644 --- a/clients/common/settings-docs.h +++ b/clients/common/settings-docs.h @@ -342,8 +342,8 @@ #define DESCRIBE_DOC_NM_SETTING_SRIOV_AUTOPROBE_DRIVERS N_("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).") #define DESCRIBE_DOC_NM_SETTING_SRIOV_TOTAL_VFS N_("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.") #define DESCRIBE_DOC_NM_SETTING_SRIOV_VFS N_("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.") -#define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_QDISCS N_("Array of TC queueing disciplines.") -#define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_TFILTERS N_("Array of TC traffic filters.") +#define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_QDISCS N_("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.") +#define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_TFILTERS N_("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.") #define DESCRIBE_DOC_NM_SETTING_TEAM_CONFIG N_("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.") #define DESCRIBE_DOC_NM_SETTING_TEAM_LINK_WATCHERS N_("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.") #define DESCRIBE_DOC_NM_SETTING_TEAM_MCAST_REJOIN_COUNT N_("Corresponds to the teamd mcast_rejoin.count.") diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index 2c275a99c8..7c3ff25fe3 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -342,8 +342,8 @@ #define DESCRIBE_DOC_NM_SETTING_SRIOV_AUTOPROBE_DRIVERS N_("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).") #define DESCRIBE_DOC_NM_SETTING_SRIOV_TOTAL_VFS N_("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.") #define DESCRIBE_DOC_NM_SETTING_SRIOV_VFS N_("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.") -#define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_QDISCS N_("Array of TC queueing disciplines.") -#define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_TFILTERS N_("Array of TC traffic filters.") +#define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_QDISCS N_("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.") +#define DESCRIBE_DOC_NM_SETTING_TC_CONFIG_TFILTERS N_("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.") #define DESCRIBE_DOC_NM_SETTING_TEAM_CONFIG N_("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.") #define DESCRIBE_DOC_NM_SETTING_TEAM_LINK_WATCHERS N_("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.") #define DESCRIBE_DOC_NM_SETTING_TEAM_MCAST_REJOIN_COUNT N_("Corresponds to the teamd mcast_rejoin.count.") diff --git a/clients/tui/newt/meson.build b/clients/tui/newt/meson.build index 0c89c0f681..cbe9d55449 100644 --- a/clients/tui/newt/meson.build +++ b/clients/tui/newt/meson.build @@ -26,6 +26,7 @@ libnmt_newt = static_library( ), dependencies: [ libnm_nm_default_dep, + libnm_dep, newt_dep, ], c_args: [ diff --git a/clients/tui/newt/nmt-newt-button.c b/clients/tui/newt/nmt-newt-button.c index 1a30a63d4c..1fc89b7632 100644 --- a/clients/tui/newt/nmt-newt-button.c +++ b/clients/tui/newt/nmt-newt-button.c @@ -108,7 +108,8 @@ nmt_newt_button_build_component(NmtNewtComponent *component, gboolean sensitive) { NmtNewtButtonPrivate *priv = NMT_NEWT_BUTTON_GET_PRIVATE(component); newtComponent co; - char * label = NULL, *label_lc; + gs_free char * label = NULL; + char * label_lc; if (sensitive) { label_lc = nmt_newt_locale_from_utf8(priv->label); diff --git a/configure.ac b/configure.ac index 3e660ff7e1..f54e354a0d 100644 --- a/configure.ac +++ b/configure.ac @@ -8,7 +8,7 @@ dnl "shared/nm-version-macros.h.in" dnl - update number in meson.build m4_define([nm_major_version], [1]) m4_define([nm_minor_version], [30]) -m4_define([nm_micro_version], [0]) +m4_define([nm_micro_version], [6]) m4_define([nm_version], [nm_major_version.nm_minor_version.nm_micro_version]) @@ -1229,9 +1229,13 @@ else fi AC_SUBST(NM_LOG_COMPILER, 'LOG_COMPILER = "$(top_srcdir)/tools/run-nm-test.sh" --called-from-make "$(abs_top_builddir)" "$(LIBTOOL)" "$(with_valgrind)" "'"$with_valgrind_suppressions"'" --launch-dbus=auto') -AM_PATH_PYTHON([3], [], [PYTHON=]) -if test -z "$PYTHON"; then - AM_PATH_PYTHON([], [], [PYTHON=python]) +if test -n "$PYTHON" ; then + AM_PATH_PYTHON([], [], []) +else + AM_PATH_PYTHON([3], [], [PYTHON=]) + if test -z "$PYTHON"; then + AM_PATH_PYTHON([], [], []) + fi fi AC_SUBST(PYTHON, [$PYTHON]) AC_DEFINE_UNQUOTED(TEST_NM_PYTHON, "$PYTHON", [Define python path for test binary]) diff --git a/data/NetworkManager.service.in b/data/NetworkManager.service.in index 91ebd9a36e..9cf1c3d28f 100644 --- a/data/NetworkManager.service.in +++ b/data/NetworkManager.service.in @@ -19,6 +19,10 @@ CapabilityBoundingSet=CAP_NET_ADMIN CAP_DAC_OVERRIDE CAP_NET_RAW CAP_NET_BIND_SE ProtectSystem=true ProtectHome=read-only +# We require file descriptors for DHCP etc. When activating many interfaces, +# the default limit of 1024 is easily reached. +LimitNOFILE=65536 + [Install] WantedBy=multi-user.target Also=NetworkManager-dispatcher.service diff --git a/debian/changelog b/debian/changelog index 3431459d47..55a8c1fa91 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,16 @@ +network-manager (1.30.6-1~deb11u1) bullseye; urgency=medium + + * Rebuild for bullseye + + -- Michael Biebl <biebl@debian.org> Sat, 18 Sep 2021 20:29:30 +0200 + +network-manager (1.30.6-1) unstable; urgency=medium + + * New upstream version 1.30.6 + * Rebase patches + + -- Michael Biebl <biebl@debian.org> Mon, 16 Aug 2021 09:56:57 +0200 + network-manager (1.30.0-2) unstable; urgency=medium * core: fix crash in nm_wildcard_match_check() diff --git a/debian/gbp.conf b/debian/gbp.conf index 05e704d031..a64b3aab04 100644 --- a/debian/gbp.conf +++ b/debian/gbp.conf @@ -1,5 +1,5 @@ [DEFAULT] pristine-tar = True patch-numbers = False -debian-branch = debian/master +debian-branch = debian/bullseye upstream-branch = upstream/latest diff --git a/debian/patches/Force-online-state-with-unmanaged-devices.patch b/debian/patches/Force-online-state-with-unmanaged-devices.patch index a639e11aac..af3a739872 100644 --- a/debian/patches/Force-online-state-with-unmanaged-devices.patch +++ b/debian/patches/Force-online-state-with-unmanaged-devices.patch @@ -12,7 +12,7 @@ Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=512286 1 file changed, 115 insertions(+) diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c -index 5a6e05a..4c56b77 100644 +index f44306e..9439c16 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -52,6 +52,8 @@ @@ -35,7 +35,7 @@ index 5a6e05a..4c56b77 100644 guint timestamp_update_id; guint devices_inited_id; -@@ -1463,6 +1469,27 @@ find_best_device_state(NMManager *manager) +@@ -1471,6 +1477,27 @@ find_best_device_state(NMManager *manager) return best_state; } @@ -63,7 +63,7 @@ index 5a6e05a..4c56b77 100644 static void nm_manager_update_metered(NMManager *self) { -@@ -1509,6 +1536,9 @@ nm_manager_update_state(NMManager *self) +@@ -1517,6 +1544,9 @@ nm_manager_update_state(NMManager *self) else new_state = find_best_device_state(self); @@ -73,7 +73,7 @@ index 5a6e05a..4c56b77 100644 if (new_state >= NM_STATE_CONNECTED_LOCAL && priv->connectivity_state == NM_CONNECTIVITY_FULL) { new_state = NM_STATE_CONNECTED_GLOBAL; } -@@ -6603,6 +6633,62 @@ impl_manager_set_logging(NMDBusObject * obj, +@@ -6661,6 +6691,62 @@ impl_manager_set_logging(NMDBusObject * obj, g_dbus_method_invocation_return_value(invocation, NULL); } @@ -136,7 +136,7 @@ index 5a6e05a..4c56b77 100644 static void impl_manager_get_logging(NMDBusObject * obj, const NMDBusInterfaceInfoExtended *interface_info, -@@ -6932,6 +7018,9 @@ nm_manager_start(NMManager *self, GError **error) +@@ -6990,6 +7076,9 @@ nm_manager_start(NMManager *self, GError **error) 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); @@ -146,7 +146,7 @@ index 5a6e05a..4c56b77 100644 return TRUE; } -@@ -7826,6 +7915,22 @@ nm_manager_init(NMManager *self) +@@ -7884,6 +7973,22 @@ nm_manager_init(NMManager *self) _LOGW(LOGD_CORE, "failed to monitor kernel firmware directory '%s'.", KERNEL_FIRMWARE_DIR); } @@ -169,7 +169,7 @@ index 5a6e05a..4c56b77 100644 /* Update timestamps in active connections */ priv->timestamp_update_id = g_timeout_add_seconds(300, -@@ -8111,6 +8216,16 @@ dispose(GObject *object) +@@ -8169,6 +8274,16 @@ dispose(GObject *object) g_clear_object(&priv->fw_monitor); } diff --git a/debian/patches/core-fix-crash-in-nm_wildcard_match_check.patch b/debian/patches/core-fix-crash-in-nm_wildcard_match_check.patch deleted file mode 100644 index 02d4484dd0..0000000000 --- a/debian/patches/core-fix-crash-in-nm_wildcard_match_check.patch +++ /dev/null @@ -1,74 +0,0 @@ -From: Thomas Haller <thaller@redhat.com> -Date: Wed, 24 Mar 2021 21:05:19 +0100 -Subject: core: fix crash in nm_wildcard_match_check() - -It's not entirely clear how to treat %NULL. -Clearly "match.interface-name=eth0" should not -match with an interface %NULL. But what about -"match.interface-name=!eth0"? It's now implemented -that negative matches still succeed against %NULL. -What about "match.interface-name=*"? That probably -should also match with %NULL. So we treat %NULL really -like "". - -Against commit 11cd443448bc ('iwd: Don't call IWD methods when device -unmanaged'), we got this backtrace: - - #0 0x00007f1c164069f1 in __strnlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:62 - #1 0x00007f1c1637ac9e in __fnmatch (pattern=<optimized out>, string=<optimized out>, string@entry=0x0, flags=flags@entry=0) at fnmatch.c:379 - p = 0x0 - res = <optimized out> - orig_pattern = <optimized out> - n = <optimized out> - wpattern = 0x7fff8d860730 L"pci-0000:03:00.0" - ps = {__count = 0, __value = {__wch = 0, __wchb = "\000\000\000"}} - wpattern_malloc = 0x0 - wstring_malloc = 0x0 - wstring = <optimized out> - alloca_used = 80 - __PRETTY_FUNCTION__ = "__fnmatch" - #2 0x0000564484a978bf in nm_wildcard_match_check (str=0x0, patterns=<optimized out>, num_patterns=<optimized out>) at src/core/nm-core-utils.c:1959 - is_inverted = 0 - is_mandatory = 0 - match = <optimized out> - p = 0x564486c43fa0 "pci-0000:03:00.0" - has_optional = 0 - has_any_optional = 0 - i = <optimized out> - #3 0x0000564484bf4797 in check_connection_compatible (self=<optimized out>, connection=<optimized out>, error=0x0) at src/core/devices/nm-device.c:7499 - patterns = <optimized out> - device_driver = 0x564486c76bd0 "veth" - num_patterns = 1 - priv = 0x564486cbe0b0 - __func__ = "check_connection_compatible" - device_iface = <optimized out> - local = 0x564486c99a60 - conn_iface = 0x0 - klass = <optimized out> - s_match = 0x564486c63df0 [NMSettingMatch] - #4 0x0000564484c38491 in check_connection_compatible (device=0x564486cbe590 [NMDeviceVeth], connection=0x564486c6b160, error=0x0) at src/core/devices/nm-device-ethernet.c:348 - self = 0x564486cbe590 [NMDeviceVeth] - s_wired = <optimized out> - -Fixes: 3ced486f4162 ('libnm/match: extend syntax for match patterns with '|', '&', '!' and '\\'') - -https://bugzilla.redhat.com/show_bug.cgi?id=1942741 -(cherry picked from commit 420784e342da4883f6debdfe10cde68507b10d27) ---- - src/core/nm-core-utils.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c -index 9075c30..eed8cd7 100644 ---- a/src/core/nm-core-utils.c -+++ b/src/core/nm-core-utils.c -@@ -1956,7 +1956,8 @@ nm_wildcard_match_check(const char *str, const char *const *patterns, guint num_ - - _pattern_parse(patterns[i], &p, &is_inverted, &is_mandatory); - -- match = (fnmatch(p, str, 0) == 0); -+ match = (fnmatch(p, str ?: "", 0) == 0); -+ - if (is_inverted) - match = !match; - diff --git a/debian/patches/series b/debian/patches/series index b31950d2cb..a2d7e06dbd 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1 @@ Force-online-state-with-unmanaged-devices.patch -core-fix-crash-in-nm_wildcard_match_check.patch diff --git a/gtk-doc.make b/gtk-doc.make index c673175d71..7d9a27f34b 100644 --- a/gtk-doc.make +++ b/gtk-doc.make @@ -57,7 +57,6 @@ DOC_STAMPS=setup-build.stamp scan-build.stamp sgml-build.stamp \ sgml.stamp html.stamp pdf.stamp SCANOBJ_FILES = \ - $(DOC_MODULE).actions \ $(DOC_MODULE).args \ $(DOC_MODULE).hierarchy \ $(DOC_MODULE).interfaces \ diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index d9374fe5a7..e386d5e9d0 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -586,6 +586,8 @@ NMBondOptionType _nm_setting_bond_get_option_type(NMSettingBond *setting, const 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" + /*****************************************************************************/ /* nm_connection_get_uuid() asserts against NULL, which is the right thing to diff --git a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c index 1ab0fcf253..3b4c2da741 100644 --- a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c +++ b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c @@ -25,6 +25,7 @@ _nm_setting_bond_remove_options_miimon(NMSettingBond *s_bond) nm_setting_bond_remove_option(s_bond, NM_SETTING_BOND_OPTION_MIIMON); nm_setting_bond_remove_option(s_bond, NM_SETTING_BOND_OPTION_UPDELAY); nm_setting_bond_remove_option(s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY); + nm_setting_bond_remove_option(s_bond, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY); } void diff --git a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h index 946c7a2c0e..ea887f3f87 100644 --- a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h +++ b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h @@ -36,6 +36,9 @@ NM_AUTO_DEFINE_FCN0(NMTCQdisc *, _nm_auto_unref_tc_qdisc, nm_tc_qdisc_unref); #define nm_auto_unref_tc_tfilter nm_auto(_nm_auto_unref_tc_tfilter) NM_AUTO_DEFINE_FCN0(NMTCTfilter *, _nm_auto_unref_tc_tfilter, nm_tc_tfilter_unref); +#define nm_auto_unref_tc_action nm_auto(_nm_auto_unref_tc_action) +NM_AUTO_DEFINE_FCN0(NMTCAction *, _nm_auto_unref_tc_action, nm_tc_action_unref); + #define nm_auto_unref_bridge_vlan nm_auto(_nm_auto_unref_bridge_vlan) NM_AUTO_DEFINE_FCN0(NMBridgeVlan *, _nm_auto_unref_bridge_vlan, nm_bridge_vlan_unref); diff --git a/libnm-core/nm-setting-bond.c b/libnm-core/nm-setting-bond.c index 2d64ef02b4..60470200f5 100644 --- a/libnm-core/nm-setting-bond.c +++ b/libnm-core/nm-setting-bond.c @@ -74,6 +74,7 @@ static const char *const valid_options_lst[] = { NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB, NM_SETTING_BOND_OPTION_LP_INTERVAL, + NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, NULL, }; @@ -191,6 +192,7 @@ static NM_UTILS_STRING_TABLE_LOOKUP_STRUCT_DEFINE( {NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, {"1", NM_BOND_OPTION_TYPE_INT, 0, 255}}, {NM_SETTING_BOND_OPTION_NUM_UNSOL_NA, {"1", NM_BOND_OPTION_TYPE_INT, 0, 255}}, {NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, {"1", NM_BOND_OPTION_TYPE_INT, 0, 65535}}, + {NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, {"0", NM_BOND_OPTION_TYPE_INT, 0, G_MAXINT}}, {NM_SETTING_BOND_OPTION_PRIMARY, {"", NM_BOND_OPTION_TYPE_IFNAME}}, {NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, {"always", NM_BOND_OPTION_TYPE_BOTH, 0, 2, _option_default_strv_primary_reselect}}, @@ -225,7 +227,7 @@ static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( {NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, ~(BIT(NM_BOND_MODE_ROUNDROBIN))}, {NM_SETTING_BOND_OPTION_PRIMARY, ~(BIT(NM_BOND_MODE_ACTIVEBACKUP) | BIT(NM_BOND_MODE_TLB) | BIT(NM_BOND_MODE_ALB))}, - {NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB, ~(BIT(NM_BOND_MODE_TLB))}, ); + {NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB, ~(BIT(NM_BOND_MODE_TLB) | BIT(NM_BOND_MODE_ALB))}, ); gboolean _nm_setting_bond_option_supported(const char *option, NMBondMode mode) @@ -337,7 +339,7 @@ _bond_get_option_normalized(NMSettingBond *self, const char *option, gboolean ge if (nm_streq(option, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM)) { /* The default value depends on the current mode */ if (mode == NM_BOND_MODE_8023AD) - return "00:00:00:00:00:00"; + return NM_BOND_AD_ACTOR_SYSTEM_DEFAULT; return ""; } @@ -766,6 +768,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) int arp_interval; int num_grat_arp; int num_unsol_na; + int peer_notif_delay; const char * mode_str; const char * arp_ip_target = NULL; const char * lacp_rate; @@ -794,6 +797,8 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) arp_interval = _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_ARP_INTERVAL)); num_grat_arp = _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP)); num_unsol_na = _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_NUM_UNSOL_NA)); + peer_notif_delay = + _atoi(_bond_get_option_or_default(self, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY)); /* Option restrictions: * @@ -802,6 +807,8 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) * arp_validate does not work with [ BOND_MODE_8023AD, BOND_MODE_TLB, BOND_MODE_ALB ] * downdelay needs miimon * updelay needs miimon + * peer_notif_delay needs miimon enabled + * peer_notif_delay must be a miimon multiple * primary needs [ active-backup, tlb, alb ] */ @@ -910,6 +917,36 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) } } + if (peer_notif_delay) { + if (miimon == 0) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' option requires '%s' option to be enabled"), + NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, + NM_SETTING_BOND_OPTION_MIIMON); + g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + return FALSE; + } + + /* The code disables miimon when arp is set, so they never occur together. + * But this occurs after this verification, so this check can occur in + * an invalid state, when both arp and miimon are enabled. To assure not + * dealing with an invalid state, this arp_interval == 0 condition, + * that is implicit, was made explicit. + */ + if ((peer_notif_delay % miimon) && (arp_interval == 0)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' option needs to be a value multiple of '%s' value"), + NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY, + NM_SETTING_BOND_OPTION_MIIMON); + g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS); + return FALSE; + } + } + /* arp_ip_target can only be used with arp_interval, and must * contain a comma-separated list of IPv4 addresses. */ diff --git a/libnm-core/nm-setting-bond.h b/libnm-core/nm-setting-bond.h index 25ae8c36e7..abaebb9eaa 100644 --- a/libnm-core/nm-setting-bond.h +++ b/libnm-core/nm-setting-bond.h @@ -56,6 +56,7 @@ G_BEGIN_DECLS #define NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE "packets_per_slave" #define NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB "tlb_dynamic_lb" #define NM_SETTING_BOND_OPTION_LP_INTERVAL "lp_interval" +#define NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY "peer_notif_delay" /** * NMSettingBond: diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c index 45ecbd8868..1addf8c644 100644 --- a/libnm-core/nm-setting-ip-config.c +++ b/libnm-core/nm-setting-ip-config.c @@ -5738,6 +5738,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps priv->dhcp_timeout = g_value_get_int(value); break; case PROP_DHCP_IAID: + g_free(priv->dhcp_iaid); priv->dhcp_iaid = g_value_dup_string(value); break; case PROP_DHCP_HOSTNAME_FLAGS: diff --git a/libnm-core/nm-setting-ip-config.h b/libnm-core/nm-setting-ip-config.h index 1cb1671714..cb8a3f2458 100644 --- a/libnm-core/nm-setting-ip-config.h +++ b/libnm-core/nm-setting-ip-config.h @@ -291,7 +291,7 @@ char *nm_ip_routing_rule_to_string(const NMIPRoutingRule * self, #define NM_SETTING_IP_CONFIG(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTING_IP_CONFIG, NMSettingIPConfig)) #define NM_SETTING_IP_CONFIG_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SETTING_IPCONFIG, NMSettingIPConfigClass)) + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SETTING_IP_CONFIG, NMSettingIPConfigClass)) #define NM_IS_SETTING_IP_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTING_IP_CONFIG)) #define NM_IS_SETTING_IP_CONFIG_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_SETTING_IP_CONFIG)) diff --git a/libnm-core/nm-setting-tc-config.c b/libnm-core/nm-setting-tc-config.c index 33df6d34e5..31e829c1d2 100644 --- a/libnm-core/nm-setting-tc-config.c +++ b/libnm-core/nm-setting-tc-config.c @@ -1810,11 +1810,23 @@ nm_setting_tc_config_class_init(NMSettingTCConfigClass *klass) * NMSettingTCConfig:qdiscs: (type GPtrArray(NMTCQdisc)) * * Array of TC queueing disciplines. + * + * When the #NMSettingTCConfig 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 #NMSettingTCConfig setting is not present, NetworkManager + * doesn't touch the qdiscs present on the interface. **/ /* ---ifcfg-rh--- * property: qdiscs - * variable: QDISC1(+), QDISC2(+), ... - * description: Queueing disciplines + * variable: QDISC1(+), QDISC2(+), ..., TC_COMMIT(+) + * description: Queueing disciplines to set on the interface. When no + * QDISC1, QDISC2, ..., FILTER1, FILTER2, ... keys are present, + * NetworkManager doesn't touch qdiscs and filters present on the + * interface, unless TC_COMMIT is set to 'yes'. * example: QDISC1=ingress, QDISC2="root handle 1234: fq_codel" * ---end--- */ @@ -1834,11 +1846,21 @@ nm_setting_tc_config_class_init(NMSettingTCConfigClass *klass) * NMSettingTCConfig:tfilters: (type GPtrArray(NMTCTfilter)) * * Array of TC traffic filters. + * + * When the #NMSettingTCConfig setting is present, filters from this + * property are applied upon activation. If the property is empty, + * NetworkManager removes all the filters. + * + * If the #NMSettingTCConfig setting is not present, NetworkManager + * doesn't touch the filters present on the interface. **/ /* ---ifcfg-rh--- * property: qdiscs - * variable: FILTER1(+), FILTER2(+), ... - * description: Traffic filters + * variable: FILTER1(+), FILTER2(+), ..., TC_COMMIT(+) + * description: Traffic filters to set on the interface. When no + * QDISC1, QDISC2, ..., FILTER1, FILTER2, ... keys are present, + * NetworkManager doesn't touch qdiscs and filters present on the + * interface, unless TC_COMMIT is set to 'yes'. * example: FILTER1="parent ffff: matchall action simple sdata Input", ... * ---end--- */ diff --git a/libnm-core/nm-setting-wireless-security.c b/libnm-core/nm-setting-wireless-security.c index 162f92202c..f3fabc6ea2 100644 --- a/libnm-core/nm-setting-wireless-security.c +++ b/libnm-core/nm-setting-wireless-security.c @@ -866,8 +866,9 @@ need_secrets(NMSetting *setting) goto no_secrets; } - g_assert_not_reached(); - return secrets; + /* If we get here, we're an older libnm talking to a newer NetworkManager + * service (perhaps from a container or during an upgrade). Assume that + * unknown/future key management modes don't need any extra secrets. */ no_secrets: if (secrets) diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 6ceef1e402..eebd73cfd4 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -2823,14 +2823,14 @@ static const NMVariantAttributeSpec *const tc_tfilter_attribute_spec[] = { NMTCTfilter * nm_utils_tc_tfilter_from_str(const char *str, GError **error) { - guint32 handle = TC_H_UNSPEC; - guint32 parent = TC_H_UNSPEC; - gs_free char * kind = NULL; - gs_free char * rest = NULL; - NMTCAction * action = NULL; - const char * extra_opts = NULL; - NMTCTfilter * tfilter = NULL; - gs_unref_hashtable GHashTable *ht = NULL; + guint32 handle = TC_H_UNSPEC; + guint32 parent = TC_H_UNSPEC; + gs_free char * kind = NULL; + gs_free char * rest = NULL; + nm_auto_unref_tc_action NMTCAction *action = NULL; + const char * extra_opts = NULL; + NMTCTfilter * tfilter = NULL; + gs_unref_hashtable GHashTable *ht = NULL; GVariant * variant; nm_assert(str); @@ -2870,10 +2870,8 @@ nm_utils_tc_tfilter_from_str(const char *str, GError **error) return NULL; nm_tc_tfilter_set_handle(tfilter, handle); - if (action) { + if (action) nm_tc_tfilter_set_action(tfilter, action); - nm_tc_action_unref(action); - } return tfilter; } diff --git a/libnm-core/nm-version-macros.h b/libnm-core/nm-version-macros.h index a7b074def3..4a93679112 100644 --- a/libnm-core/nm-version-macros.h +++ b/libnm-core/nm-version-macros.h @@ -30,7 +30,7 @@ * Evaluates to the micro version number of NetworkManager which this source * compiled against. */ -#define NM_MICRO_VERSION (0) +#define NM_MICRO_VERSION (6) /** * NM_CHECK_VERSION: diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c index 01cdb41cb2..56ba31541a 100644 --- a/libnm-core/tests/test-setting.c +++ b/libnm-core/tests/test-setting.c @@ -687,7 +687,7 @@ test_bond_normalize(void) ((const char *[]){"mode", "active-backup", "miimon", "1", NULL})); test_bond_normalize_options( ((const char *[]){"mode", "balance-alb", "tlb_dynamic_lb", "1", NULL}), - ((const char *[]){"mode", "balance-alb", NULL})); + ((const char *[]){"mode", "balance-alb", "tlb_dynamic_lb", "1", NULL})); test_bond_normalize_options( ((const char *[]){"mode", "balance-tlb", "tlb_dynamic_lb", "1", NULL}), ((const char *[]){"mode", "balance-tlb", "tlb_dynamic_lb", "1", NULL})); diff --git a/libnm/nm-device.c b/libnm/nm-device.c index 9cb88dae8e..e9e8feccd7 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -1386,7 +1386,7 @@ nm_device_get_autoconnect(NMDevice *device) * Enables or disables automatic activation of the #NMDevice. * * Deprecated: 1.22: Use the async command nm_client_dbus_set_property() on - * nm_object_get_path(), %NM_DBUS_INTERFACE_DEVICE to set "AutoConnect" property to a "(b)" value. + * nm_object_get_path(), %NM_DBUS_INTERFACE_DEVICE to set "Autoconnect" property to a "(b)" value. * This function is deprecated because it calls a synchronous D-Bus method * and modifies the content of the NMClient cache client side. **/ @@ -1400,7 +1400,7 @@ nm_device_set_autoconnect(NMDevice *device, gboolean autoconnect) _nm_client_set_property_sync_legacy(_nm_object_get_client(device), _nm_object_get_path(device), NM_DBUS_INTERFACE_DEVICE, - "AutoConnect", + "Autoconnect", "b", autoconnect); } diff --git a/libnm/nm-property-infos-ifcfg-rh.xml b/libnm/nm-property-infos-ifcfg-rh.xml index 1c6aced24d..454cf1ef4a 100644 --- a/libnm/nm-property-infos-ifcfg-rh.xml +++ b/libnm/nm-property-infos-ifcfg-rh.xml @@ -309,8 +309,14 @@ proxy configuration, or set the PAC file via PAC_URL or PAC_SCRIPT."/> <property name="autoprobe-drivers" variable="SRIOV_AUTOPROBE_DRIVERS(+)" format="" values="" default="missing variable means global default" example="SRIOV_AUTOPROBE_DRIVERS=0,1" description="Whether to autoprobe virtual functions by a compatible driver"/> </setting> <setting name="tc"> -<property name="qdiscs" variable="QDISC1(+), QDISC2(+), ..." format="" values="" default="" example="QDISC1=ingress, QDISC2="root handle 1234: fq_codel"" description="Queueing disciplines"/> -<property name="qdiscs" variable="FILTER1(+), FILTER2(+), ..." format="" values="" default="" example="FILTER1="parent ffff: matchall action simple sdata Input", ..." description="Traffic filters"/> +<property name="qdiscs" variable="QDISC1(+), QDISC2(+), ..., TC_COMMIT(+)" format="" values="" default="" example="QDISC1=ingress, QDISC2="root handle 1234: fq_codel"" description="Queueing disciplines to set on the interface. When no +QDISC1, QDISC2, ..., FILTER1, FILTER2, ... keys are present, +NetworkManager doesn't touch qdiscs and filters present on the +interface, unless TC_COMMIT is set to 'yes'."/> +<property name="qdiscs" variable="FILTER1(+), FILTER2(+), ..., TC_COMMIT(+)" format="" values="" default="" example="FILTER1="parent ffff: matchall action simple sdata Input", ..." description="Traffic filters to set on the interface. When no +QDISC1, QDISC2, ..., FILTER1, FILTER2, ... keys are present, +NetworkManager doesn't touch qdiscs and filters present on the +interface, unless TC_COMMIT is set to 'yes'."/> </setting> <setting name="team-port"> <property name="config" variable="TEAM_PORT_CONFIG" format="" values="" default="" example="" description="Team port configuration in JSON. See man teamd.conf for details."/> diff --git a/libnm/nm-settings-docs-gir.xml b/libnm/nm-settings-docs-gir.xml index f71d2bad36..5089fb9e22 100644 --- a/libnm/nm-settings-docs-gir.xml +++ b/libnm/nm-settings-docs-gir.xml @@ -362,8 +362,8 @@ <property name="vfs" name_upper="VFS" type="array of vardict" description="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." /> </setting> <setting name="tc" description="Linux Traffic Control Settings" name_upper="TC_CONFIG" > - <property name="qdiscs" name_upper="QDISCS" type="array of vardict" description="Array of TC queueing disciplines." /> - <property name="tfilters" name_upper="TFILTERS" type="array of vardict" description="Array of TC traffic filters." /> + <property name="qdiscs" name_upper="QDISCS" type="array of vardict" description="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." /> + <property name="tfilters" name_upper="TFILTERS" type="array of vardict" description="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." /> </setting> <setting name="team" description="Teaming Settings" name_upper="TEAM" > <property name="config" name_upper="CONFIG" type="string" description="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." /> diff --git a/libnm/nm-vpn-plugin-old.c b/libnm/nm-vpn-plugin-old.c index f45d0c09e9..3365602603 100644 --- a/libnm/nm-vpn-plugin-old.c +++ b/libnm/nm-vpn-plugin-old.c @@ -420,12 +420,12 @@ _connect_generic(NMVpnPluginOld * plugin, GVariant * properties, GVariant * details) { - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE(plugin); - NMVpnPluginOldClass * vpn_class = NM_VPN_PLUGIN_OLD_GET_CLASS(plugin); - NMConnection * connection; - gboolean success = FALSE; - GError * error = NULL; - guint fail_stop_timeout = 0; + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE(plugin); + NMVpnPluginOldClass * vpn_class = NM_VPN_PLUGIN_OLD_GET_CLASS(plugin); + gs_unref_object NMConnection *connection = NULL; + gboolean success = FALSE; + GError * error = NULL; + guint fail_stop_timeout = 0; if (priv->state != NM_VPN_SERVICE_STATE_STOPPED && priv->state != NM_VPN_SERVICE_STATE_INIT) { g_dbus_method_invocation_return_error(context, @@ -445,6 +445,7 @@ _connect_generic(NMVpnPluginOld * plugin, "Invalid connection: %s", error->message); g_clear_error(&error); + return; } priv->interactive = FALSE; @@ -485,8 +486,6 @@ _connect_generic(NMVpnPluginOld * plugin, */ schedule_fail_stop(plugin, fail_stop_timeout); } - - g_object_unref(connection); } static void diff --git a/libnm/nm-vpn-service-plugin.c b/libnm/nm-vpn-service-plugin.c index 34de21b875..bf5f292fa1 100644 --- a/libnm/nm-vpn-service-plugin.c +++ b/libnm/nm-vpn-service-plugin.c @@ -755,11 +755,11 @@ nm_vpn_service_plugin_read_vpn_details(int fd, GHashTable **out_data, GHashTable gs_unref_hashtable GHashTable *secrets = NULL; gboolean success = FALSE; GHashTable * hash = NULL; - GString * key = NULL, *val = NULL; - nm_auto_free_gstring GString *line = NULL; + nm_auto_free_gstring GString *key = NULL; + nm_auto_free_gstring GString *val = NULL; + nm_auto_free_gstring GString *line = NULL; char c; - - GString *str = NULL; + GString * str = NULL; if (out_data) g_return_val_if_fail(*out_data == NULL, FALSE); @@ -807,16 +807,12 @@ nm_vpn_service_plugin_read_vpn_details(int fd, GHashTable **out_data, GHashTable /* finish marker */ break; } else if (strncmp(line->str, DATA_KEY_TAG, strlen(DATA_KEY_TAG)) == 0) { - if (key != NULL) { + if (nm_clear_g_string(&key)) g_warning("a value expected"); - g_string_free(key, TRUE); - } key = g_string_new(line->str + strlen(DATA_KEY_TAG)); str = key; hash = data; } else if (strncmp(line->str, DATA_VAL_TAG, strlen(DATA_VAL_TAG)) == 0) { - if (val != NULL) - g_string_free(val, TRUE); if (val || !key || hash != data) { g_warning("%s not preceded by %s", DATA_VAL_TAG, DATA_KEY_TAG); break; @@ -824,16 +820,12 @@ nm_vpn_service_plugin_read_vpn_details(int fd, GHashTable **out_data, GHashTable val = g_string_new(line->str + strlen(DATA_VAL_TAG)); str = val; } else if (strncmp(line->str, SECRET_KEY_TAG, strlen(SECRET_KEY_TAG)) == 0) { - if (key != NULL) { + if (nm_clear_g_string(&key)) g_warning("a value expected"); - g_string_free(key, TRUE); - } key = g_string_new(line->str + strlen(SECRET_KEY_TAG)); str = key; hash = secrets; } else if (strncmp(line->str, SECRET_VAL_TAG, strlen(SECRET_VAL_TAG)) == 0) { - if (val != NULL) - g_string_free(val, TRUE); if (val || !key || hash != secrets) { g_warning("%s not preceded by %s", SECRET_VAL_TAG, SECRET_KEY_TAG); break; diff --git a/meson.build b/meson.build index 9fcb2f6e7a..6392c2fe9d 100644 --- a/meson.build +++ b/meson.build @@ -6,7 +6,7 @@ project( # - add corresponding NM_VERSION_x_y_z macros in # "shared/nm-version-macros.h.in" # - update number in configure.ac - version: '1.30.0', + version: '1.30.6', license: 'GPL2+', default_options: [ 'buildtype=debugoptimized', diff --git a/shared/nm-glib-aux/nm-dbus-aux.c b/shared/nm-glib-aux/nm-dbus-aux.c index ec409ff1fa..9fb02a3fcd 100644 --- a/shared/nm-glib-aux/nm-dbus-aux.c +++ b/shared/nm-glib-aux/nm-dbus-aux.c @@ -268,6 +268,119 @@ nm_dbus_connection_call_finish_variant_strip_dbus_error_cb(GObject * source, /*****************************************************************************/ +typedef struct { + char * bus_name; + char * object_path; + char * interface_name; + char * method_name; + GVariant * parameters; + GDBusConnection * connection; + const GVariantType *reply_type; + int timeout_msec; +} CallAsyncInfo; + +static void +call_async_info_destroy(CallAsyncInfo *info) +{ + g_free(info->bus_name); + g_free(info->object_path); + g_free(info->interface_name); + g_free(info->method_name); + g_variant_unref(info->parameters); + nm_g_object_unref(info->connection); + g_free(info); +} + +static void +call_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + gs_unref_object GTask *task = user_data; + GError * error = NULL; + GVariant * ret; + + ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error); + if (!ret) { + g_task_return_error(task, error); + return; + } + + g_task_return_pointer(task, ret, (GDestroyNotify) g_variant_unref); +} + +static void +call_bus_get_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + gs_unref_object GTask *task = user_data; + GCancellable * cancellable; + CallAsyncInfo * info; + GError * error = NULL; + + info = g_task_get_task_data(task); + info->connection = g_bus_get_finish(result, &error); + cancellable = g_task_get_cancellable(task); + + if (!info->connection) { + g_task_return_error(task, g_steal_pointer(&error)); + return; + } + + g_dbus_connection_call(info->connection, + info->bus_name, + info->object_path, + info->interface_name, + info->method_name, + info->parameters, + info->reply_type, + G_DBUS_CALL_FLAGS_NONE, + info->timeout_msec, + cancellable, + call_cb, + g_steal_pointer(&task)); +} + +void +nm_dbus_call(GBusType bus_type, + const char * bus_name, + const char * object_path, + const char * interface_name, + const char * method_name, + GVariant * parameters, + const GVariantType *reply_type, + GCancellable * cancellable, + int timeout_msec, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask * task; + CallAsyncInfo *info; + + info = g_new(CallAsyncInfo, 1); + *info = (CallAsyncInfo){ + .bus_name = g_strdup(bus_name), + .object_path = g_strdup(object_path), + .interface_name = g_strdup(interface_name), + .method_name = g_strdup(method_name), + .parameters = g_variant_ref_sink(parameters), + .reply_type = reply_type, + .timeout_msec = timeout_msec, + }; + + task = nm_g_task_new(NULL, cancellable, nm_dbus_call, callback, user_data); + g_task_set_task_data(task, info, (GDestroyNotify) call_async_info_destroy); + + g_bus_get(bus_type, cancellable, call_bus_get_cb, task); +} + +GVariant * +nm_dbus_call_finish(GAsyncResult *result, GError **error) +{ + nm_assert(nm_g_task_is_valid(result, NULL, nm_dbus_call)); + + return g_task_propagate_pointer(G_TASK(result), error); +} + +/*****************************************************************************/ + gboolean _nm_dbus_error_is(GError *error, ...) { diff --git a/shared/nm-glib-aux/nm-dbus-aux.h b/shared/nm-glib-aux/nm-dbus-aux.h index 4e3ae22d82..c810708260 100644 --- a/shared/nm-glib-aux/nm-dbus-aux.h +++ b/shared/nm-glib-aux/nm-dbus-aux.h @@ -186,6 +186,22 @@ void nm_dbus_connection_call_finish_variant_strip_dbus_error_cb(GObject * so /*****************************************************************************/ +void nm_dbus_call(GBusType bus_type, + const char * bus_name, + const char * object_path, + const char * interface_name, + const char * method_name, + GVariant * parameters, + const GVariantType *reply_type, + GCancellable * cancellable, + int timeout_msec, + GAsyncReadyCallback callback, + gpointer user_data); + +GVariant *nm_dbus_call_finish(GAsyncResult *result, GError **error); + +/*****************************************************************************/ + gboolean _nm_dbus_error_is(GError *error, ...) G_GNUC_NULL_TERMINATED; #define nm_dbus_error_is(error, ...) \ diff --git a/shared/nm-glib-aux/nm-errno.c b/shared/nm-glib-aux/nm-errno.c index 668606cacd..c05379ec52 100644 --- a/shared/nm-glib-aux/nm-errno.c +++ b/shared/nm-glib-aux/nm-errno.c @@ -7,8 +7,6 @@ #include "nm-errno.h" -#include <pthread.h> - /*****************************************************************************/ static NM_UTILS_LOOKUP_STR_DEFINE( @@ -162,19 +160,9 @@ nm_strerror_native(int errsv) buf = buf_static; if (G_UNLIKELY(!buf)) { - int errno_saved = errno; - pthread_key_t key; - buf = g_malloc(NM_STRERROR_BUFSIZE); buf_static = buf; - - if (pthread_key_create(&key, g_free) != 0 || pthread_setspecific(key, buf) != 0) { - /* Failure. We will leak the buffer when the thread exits. - * - * Nothing we can do about it really. For Debug builds we fail with an assertion. */ - nm_assert_not_reached(); - } - errno = errno_saved; + nm_utils_thread_local_register_destroy(buf, g_free); } return nm_strerror_native_r(errsv, buf, NM_STRERROR_BUFSIZE); diff --git a/shared/nm-glib-aux/nm-macros-internal.h b/shared/nm-glib-aux/nm-macros-internal.h index 113a67a0d2..6f63f20482 100644 --- a/shared/nm-glib-aux/nm-macros-internal.h +++ b/shared/nm-glib-aux/nm-macros-internal.h @@ -121,14 +121,6 @@ _nm_auto_free_gstring(GString **str) } #define nm_auto_free_gstring nm_auto(_nm_auto_free_gstring) -static inline void -_nm_auto_protect_errno(int *p_saved_errno) -{ - errno = *p_saved_errno; -} -#define NM_AUTO_PROTECT_ERRNO(errsv_saved) \ - nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno) - NM_AUTO_DEFINE_FCN0(GSource *, _nm_auto_unref_gsource, g_source_unref); #define nm_auto_unref_gsource nm_auto(_nm_auto_unref_gsource) @@ -1111,6 +1103,18 @@ nm_clear_g_variant(GVariant **variant) return FALSE; } +static inline gboolean +nm_clear_g_string(GString **ptr) +{ + GString *s; + + if (ptr && (s = *ptr)) { + *ptr = NULL; + g_string_free(s, TRUE); + }; + return FALSE; +} + static inline gboolean nm_clear_g_cancellable(GCancellable **cancellable) { @@ -1805,8 +1809,13 @@ NM_AUTO_DEFINE_FCN_VOID0(GMutex *, _nm_auto_unlock_g_mutex, g_mutex_unlock); #define nm_auto_unlock_g_mutex nm_auto(_nm_auto_unlock_g_mutex) -#define _NM_G_MUTEX_LOCKED(lock, uniq) \ - nm_auto_unlock_g_mutex GMutex *NM_UNIQ_T(nm_lock, uniq) = (lock) +#define _NM_G_MUTEX_LOCKED(lock, uniq) \ + _nm_unused nm_auto_unlock_g_mutex GMutex *NM_UNIQ_T(nm_lock, uniq) = ({ \ + GMutex *const _lock = (lock); \ + \ + g_mutex_lock(_lock); \ + _lock; \ + }) #define NM_G_MUTEX_LOCKED(lock) _NM_G_MUTEX_LOCKED(lock, NM_UNIQ) diff --git a/shared/nm-glib-aux/nm-random-utils.c b/shared/nm-glib-aux/nm-random-utils.c index c95d368dd3..97272ca31c 100644 --- a/shared/nm-glib-aux/nm-random-utils.c +++ b/shared/nm-glib-aux/nm-random-utils.c @@ -122,8 +122,10 @@ fd_open: */ has_high_quality = FALSE; - if (G_UNLIKELY(!rand)) + if (G_UNLIKELY(!rand)) { rand = g_rand_new(); + nm_utils_thread_local_register_destroy(rand, (GDestroyNotify) g_rand_free); + } nm_assert(n > 0); i = 0; diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index 3215a33b5b..e7cea23a72 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -15,7 +15,9 @@ #include <glib-unix.h> #include <net/if.h> #include <net/ethernet.h> +#include <pthread.h> +#include "c-list/src/c-list.h" #include "nm-errno.h" #include "nm-str-buf.h" @@ -5708,3 +5710,80 @@ nm_utils_name_to_uid(const char *name, uid_t *out_uid) buf = buf_heap; } } + +/*****************************************************************************/ + +typedef struct { + CList lst; + gpointer tls_data; + GDestroyNotify destroy_notify; +} TlsRegData; + +static pthread_key_t _tls_reg_key; + +static void +_tls_reg_destroy(gpointer data) +{ + CList * lst_head = data; + TlsRegData *entry; + + if (!lst_head) + return; + + /* For no strong reason are we destroying the elements in reverse + * order than they were added. It seems a bit more sensible (but shouldn't + * matter nor should you rely on that). */ + while ((entry = c_list_last_entry(lst_head, TlsRegData, lst))) { + c_list_unlink_stale(&entry->lst); + entry->destroy_notify(entry->tls_data); + nm_g_slice_free(entry); + } + + nm_g_slice_free(lst_head); +} + +static void +_tls_reg_make_key(void) +{ + if (pthread_key_create(&_tls_reg_key, _tls_reg_destroy) != 0) + g_return_if_reached(); +} + +/** + * nm_utils_thread_local_register_destroy: + * @tls_data: the thread local storage data that should be destroyed when the thread + * exits. This pointer will be "owned" by the current thread. There is no way + * to un-register the destruction. + * @destroy_notify: the free function that will be called when the thread exits. + * + * If _nm_tread_local storage is heap allocated it requires freeing the pointer + * when the thread exits. Use this function to register the pointer to be + * released. + * + * This function does not change errno. + */ +void +nm_utils_thread_local_register_destroy(gpointer tls_data, GDestroyNotify destroy_notify) +{ + NM_AUTO_PROTECT_ERRNO(errsv); + static pthread_once_t key_once = PTHREAD_ONCE_INIT; + CList * lst_head; + TlsRegData * entry; + + nm_assert(destroy_notify); + + if (pthread_once(&key_once, _tls_reg_make_key) != 0) + g_return_if_reached(); + + if ((lst_head = pthread_getspecific(_tls_reg_key)) == NULL) { + lst_head = g_slice_new(CList); + c_list_init(lst_head); + if (pthread_setspecific(_tls_reg_key, lst_head) != 0) + g_return_if_reached(); + } + + entry = g_slice_new(TlsRegData); + entry->tls_data = tls_data; + entry->destroy_notify = destroy_notify; + c_list_link_tail(lst_head, &entry->lst); +} diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index 7d330458c1..f9c21a000e 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -2477,4 +2477,8 @@ gboolean nm_utils_is_specific_hostname(const char *name); char * nm_utils_uid_to_name(uid_t uid); gboolean nm_utils_name_to_uid(const char *name, uid_t *out_uid); +/*****************************************************************************/ + +void nm_utils_thread_local_register_destroy(gpointer tls_data, GDestroyNotify destroy_notify); + #endif /* __NM_SHARED_UTILS_H__ */ diff --git a/shared/nm-platform/nmp-netns.c b/shared/nm-platform/nmp-netns.c index f97339a756..4dd9e8487a 100644 --- a/shared/nm-platform/nmp-netns.c +++ b/shared/nm-platform/nmp-netns.c @@ -11,7 +11,6 @@ #include <sys/mount.h> #include <sys/stat.h> #include <sys/types.h> -#include <pthread.h> #include "nm-log-core/nm-logging.h" @@ -151,20 +150,13 @@ _netns_stack_get_impl(void) { gs_unref_object NMPNetns *netns = NULL; gs_free_error GError *error = NULL; - pthread_key_t key; GArray * s; s = g_array_new(FALSE, FALSE, sizeof(NetnsInfo)); g_array_set_clear_func(s, _netns_stack_clear_cb); _netns_stack = s; - /* register a destructor function to cleanup the array. If we fail - * to do so, we will leak NMPNetns instances (and their file descriptor) when the - * thread exits. */ - if (pthread_key_create(&key, (void (*)(void *)) g_array_unref) != 0) - _LOGE(NULL, "failure to initialize thread-local storage"); - else if (pthread_setspecific(key, s) != 0) - _LOGE(NULL, "failure to set thread-local storage"); + nm_utils_thread_local_register_destroy(s, (GDestroyNotify) g_array_unref); /* at the bottom of the stack we must try to create a netns instance * that we never pop. It's the base to which we need to return. */ diff --git a/shared/nm-std-aux/nm-std-aux.h b/shared/nm-std-aux/nm-std-aux.h index 30adeb5893..a619cebd90 100644 --- a/shared/nm-std-aux/nm-std-aux.h +++ b/shared/nm-std-aux/nm-std-aux.h @@ -695,6 +695,14 @@ nm_close(int fd) NM_AUTO_DEFINE_FCN_VOID0(void *, _nm_auto_free_impl, free); #define nm_auto_free nm_auto(_nm_auto_free_impl) +static inline void +_nm_auto_protect_errno(const int *p_saved_errno) +{ + errno = *p_saved_errno; +} +#define NM_AUTO_PROTECT_ERRNO(errsv_saved) \ + nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno) + /*****************************************************************************/ static inline void diff --git a/src/core/devices/bluetooth/nm-bluez-manager.c b/src/core/devices/bluetooth/nm-bluez-manager.c index dd998d29b0..459ea409e4 100644 --- a/src/core/devices/bluetooth/nm-bluez-manager.c +++ b/src/core/devices/bluetooth/nm-bluez-manager.c @@ -2879,6 +2879,8 @@ dispose(GObject *object) g_clear_object(&priv->dbus_connection); nm_clear_pointer(&priv->bzobjs, g_hash_table_destroy); + nm_clear_pointer(&priv->conn_data_heads, g_hash_table_destroy); + nm_clear_pointer(&priv->conn_data_elems, g_hash_table_destroy); } static void diff --git a/src/core/devices/nm-acd-manager.c b/src/core/devices/nm-acd-manager.c index b95f90fd45..81a28797bb 100644 --- a/src/core/devices/nm-acd-manager.c +++ b/src/core/devices/nm-acd-manager.c @@ -188,6 +188,7 @@ acd_event(int fd, GIOCondition condition, gpointer data) char to_string_buffer[ACD_EVENT_TO_STRING_BUF_SIZE]; gs_free char *hwaddr_str = NULL; gboolean check_probing_done = FALSE; + char buf[ETH_ALEN * 3]; switch (event->event) { case N_ACD_EVENT_READY: @@ -202,8 +203,9 @@ acd_event(int fd, GIOCondition condition, gpointer data) nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex), acd_error_to_string(r)); } else { - _LOGD("announcing address %s", - _nm_utils_inet4_ntop(info->address, address_str)); + _LOGD("announcing address %s (hw-addr %s)", + _nm_utils_inet4_ntop(info->address, address_str), + _nm_utils_hwaddr_ntoa(self->hwaddr, ETH_ALEN, TRUE, buf, sizeof(buf))); } } check_probing_done = TRUE; @@ -394,6 +396,7 @@ nm_acd_manager_announce_addresses(NMAcdManager *self) int r; int fd; gboolean success = TRUE; + char buf[ETH_ALEN * 3]; r = acd_init(self); if (r) { @@ -428,7 +431,9 @@ nm_acd_manager_announce_addresses(NMAcdManager *self) acd_error_to_string(r)); success = FALSE; } else - _LOGD("announcing address %s", _nm_utils_inet4_ntop(info->address, sbuf)); + _LOGD("announcing address %s (hw-addr %s)", + _nm_utils_inet4_ntop(info->address, sbuf), + _nm_utils_hwaddr_ntoa(self->hwaddr, ETH_ALEN, TRUE, buf, sizeof(buf))); } } diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index f68c080b18..9c1c484fe7 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -34,7 +34,7 @@ NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, \ NM_SETTING_BOND_OPTION_RESEND_IGMP, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB, \ NM_SETTING_BOND_OPTION_USE_CARRIER, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, \ - NM_SETTING_BOND_OPTION_NUM_GRAT_ARP + NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY #define OPTIONS_REAPPLY_SUBSET \ NM_SETTING_BOND_OPTION_MIIMON, NM_SETTING_BOND_OPTION_UPDELAY, \ @@ -46,7 +46,7 @@ NM_SETTING_BOND_OPTION_MIN_LINKS, NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, \ NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, NM_SETTING_BOND_OPTION_RESEND_IGMP, \ NM_SETTING_BOND_OPTION_USE_CARRIER, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, \ - NM_SETTING_BOND_OPTION_NUM_GRAT_ARP + NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, NM_SETTING_BOND_OPTION_PEER_NOTIF_DELAY #define OPTIONS_REAPPLY_FULL \ OPTIONS_REAPPLY_SUBSET, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE, \ @@ -109,6 +109,24 @@ _set_bond_attr(NMDevice *device, const char *attr, const char *value) int ifindex = nm_device_get_ifindex(device); gboolean ret; + nm_assert(attr && attr[0]); + nm_assert(value); + + if (nm_streq(value, NM_BOND_AD_ACTOR_SYSTEM_DEFAULT) + && nm_streq(attr, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM)) { + gs_free char *cur_val = NULL; + + /* kernel does not allow setting ad_actor_system to "00:00:00:00:00:00". We would thus + * log an EINVAL error. Avoid that... at least, if the value is already "00:00:00:00:00:00". */ + cur_val = + nm_platform_sysctl_master_get_option(nm_device_get_platform(device), ifindex, attr); + if (nm_streq0(cur_val, NM_BOND_AD_ACTOR_SYSTEM_DEFAULT)) + return TRUE; + + /* OK, the current value is different, and we will proceed setting "00:00:00:00:00:00". + * That will fail, and we will log a warning. There is nothing else to do. */ + } + ret = nm_platform_sysctl_master_set_option(nm_device_get_platform(device), ifindex, attr, value); if (!ret) @@ -426,9 +444,10 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure) _LOGD(LOGD_BOND, "bond slave %s is already released", nm_device_get_ip_iface(slave)); if (configure) { - /* When the last slave is released the bond MAC will be set to a random - * value by kernel; remember the current one and restore it afterwards. - */ + NMConnection * applied; + NMSettingWired *s_wired; + const char * cloned_mac; + address = g_strdup(nm_device_get_hw_address(device)); if (ifindex_slave > 0) { @@ -443,9 +462,16 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure) } } - nm_platform_process_events(nm_device_get_platform(device)); - if (nm_device_update_hw_address(device)) - nm_device_hw_addr_set(device, address, "restore", FALSE); + if ((applied = nm_device_get_applied_connection(device)) + && ((s_wired = nm_connection_get_setting_wired(applied))) + && ((cloned_mac = nm_setting_wired_get_cloned_mac_address(s_wired)))) { + /* When the last slave is released the bond MAC will be set to a random + * value by kernel; if we have set a cloned-mac-address, we need to + * restore it to the previous value. */ + nm_platform_process_events(nm_device_get_platform(device)); + if (nm_device_update_hw_address(device)) + nm_device_hw_addr_set(device, address, "restore", FALSE); + } /* Kernel bonding code "closes" the slave when releasing it, (which clears * IFF_UP), so we must bring it back up here to ensure carrier changes and diff --git a/src/core/devices/nm-device-ethernet.c b/src/core/devices/nm-device-ethernet.c index 44428869cd..59f6c61338 100644 --- a/src/core/devices/nm-device-ethernet.c +++ b/src/core/devices/nm-device-ethernet.c @@ -730,7 +730,9 @@ supplicant_iface_state_cb(NMSupplicantInterface *iface, if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { supplicant_interface_release(self); - wired_auth_cond_fail(self, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + nm_device_state_changed(NM_DEVICE(self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); return; } diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 040dd0b4d3..3874e58636 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -125,7 +125,6 @@ typedef struct { typedef struct { NMDevice *device; guint idle_add_id; - int ifindex; } DeleteOnDeactivateData; typedef struct { @@ -4703,10 +4702,6 @@ nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *co */ nm_device_update_hw_address(self); - /* Send ARP announcements if did not yet and have addresses. */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && !priv->acd.announcing) - nm_device_arp_announce(self); - /* Restart IP configuration if we're waiting for slaves. Do this * after updating the hardware address as IP config may need the * new address. @@ -5053,6 +5048,10 @@ nm_device_set_carrier(NMDevice *self, gboolean carrier) nm_device_remove_pending_action(self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); _carrier_wait_check_queued_act_request(self); } + + /* Send ARP announcements if did not yet and have carrier. */ + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && !priv->acd.announcing) + nm_device_arp_announce(self); } else { if (priv->carrier_wait_id) nm_device_add_pending_action(self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); @@ -5415,11 +5414,11 @@ device_link_changed(NMDevice *self) /* Ensure the assume check is queued before any queued state changes * from the transition to UNAVAILABLE. */ - nm_device_queue_recheck_assume(self); reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED; } } + nm_device_queue_recheck_assume(self); nm_device_set_unmanaged_by_flags(self, NM_UNMANAGED_PLATFORM_INIT, FALSE, reason); } @@ -8362,26 +8361,23 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode) static gboolean tc_commit(NMDevice *self) { - NMConnection * connection = NULL; gs_unref_ptrarray GPtrArray *qdiscs = NULL; gs_unref_ptrarray GPtrArray *tfilters = NULL; - NMSettingTCConfig * s_tc = NULL; + NMSettingTCConfig * s_tc; NMPlatform * platform; int ip_ifindex; - platform = nm_device_get_platform(self); - connection = nm_device_get_applied_connection(self); - if (connection) - s_tc = nm_connection_get_setting_tc_config(connection); + s_tc = nm_device_get_applied_setting(self, NM_TYPE_SETTING_TC_CONFIG); + if (!s_tc) + return TRUE; ip_ifindex = nm_device_get_ip_ifindex(self); if (!ip_ifindex) - return s_tc == NULL; + return FALSE; - if (s_tc) { - qdiscs = nm_utils_qdiscs_from_tc_setting(platform, s_tc, ip_ifindex); - tfilters = nm_utils_tfilters_from_tc_setting(platform, s_tc, ip_ifindex); - } + platform = nm_device_get_platform(self); + qdiscs = nm_utils_qdiscs_from_tc_setting(platform, s_tc, ip_ifindex); + tfilters = nm_utils_tfilters_from_tc_setting(platform, s_tc, ip_ifindex); if (!nm_platform_qdisc_sync(platform, ip_ifindex, qdiscs)) return FALSE; @@ -9980,7 +9976,9 @@ nm_device_request_ip6_prefixes(NMDevice *self, int needed_prefixes) _LOGD(LOGD_IP6, "ipv6-pd: asking DHCPv6 for %d prefixes", needed_prefixes); nm_device_dhcp6_renew(self, FALSE); } else { - _LOGI(LOGD_IP6, "ipv6-pd: device doesn't use DHCPv6, can't request prefixes"); + priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_OTHERCONF; + _LOGD(LOGD_DEVICE | LOGD_DHCP6, "ipv6-pd: starting DHCPv6 to request a prefix"); + dhcp6_start(self, FALSE); } } @@ -11679,8 +11677,6 @@ start_sharing(NMDevice *self, NMIP4Config *config, GError **error) nm_utils_share_rules_add_all_rules(share_rules, ip_iface, ip4_addr->address, ip4_addr->plen); - nm_utils_share_rules_apply(share_rules, TRUE); - nm_act_request_set_shared(req, share_rules); conn = nm_act_request_get_applied_connection(req); @@ -11792,7 +11788,6 @@ activate_stage5_ip_config_result_x(NMDevice *self, int addr_family) const char * method; int ip_ifindex; int errsv; - gboolean do_announce = FALSE; req = nm_device_get_act_request(self); g_assert(req); @@ -11918,31 +11913,13 @@ activate_stage5_ip_config_result_x(NMDevice *self, int addr_family) } } - if (IS_IPv4) { - /* Send ARP announcements */ - - if (nm_device_is_master(self)) { - CList * iter; - SlaveInfo *info; - - /* Skip announcement if there are no device enslaved, for two reasons: - * 1) the master has a temporary MAC address until the first slave comes - * 2) announcements are going to be dropped anyway without slaves - */ - do_announce = FALSE; - - c_list_for_each (iter, &priv->slaves) { - info = c_list_entry(iter, SlaveInfo, lst_slave); - if (info->slave_is_enslaved) { - do_announce = TRUE; - break; - } - } - } else - do_announce = TRUE; - - if (do_announce) - nm_device_arp_announce(self); + if (IS_IPv4 && priv->carrier) { + /* We send ARP announcements only when the link gets carrier, + * otherwise the announcements would be lost. Furthermore, for + * controllers having carrier implies that there is at least one + * port and therefore the MAC address is the correct one. + */ + nm_device_arp_announce(self); } if (IS_IPv4) { @@ -12141,28 +12118,19 @@ nm_device_is_nm_owned(NMDevice *self) static gboolean delete_on_deactivate_link_delete(gpointer user_data) { - DeleteOnDeactivateData *data = user_data; - NMDevice * self = data->device; + DeleteOnDeactivateData *data = user_data; + nm_auto_unref_object NMDevice *self = data->device; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + gs_free_error GError *error = NULL; _LOGD(LOGD_DEVICE, - "delete_on_deactivate: cleanup and delete virtual link #%d (id=%u)", - data->ifindex, + "delete_on_deactivate: cleanup and delete virtual link (id=%u)", data->idle_add_id); - if (data->device) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(data->device); - gs_free_error GError *error = NULL; - - g_object_remove_weak_pointer(G_OBJECT(data->device), (void **) &data->device); - priv->delete_on_deactivate_data = NULL; + priv->delete_on_deactivate_data = NULL; - if (!nm_device_unrealize(data->device, TRUE, &error)) - _LOGD(LOGD_DEVICE, - "delete_on_deactivate: unrealizing %d failed (%s)", - data->ifindex, - error->message); - } else if (data->ifindex > 0) - nm_platform_link_delete(nm_device_get_platform(self), data->ifindex); + if (!nm_device_unrealize(self, TRUE, &error)) + _LOGD(LOGD_DEVICE, "delete_on_deactivate: unrealizing failed (%s)", error->message); nm_device_emit_recheck_auto_activate(self); @@ -12181,17 +12149,16 @@ delete_on_deactivate_unschedule(NMDevice *self) priv->delete_on_deactivate_data = NULL; g_source_remove(data->idle_add_id); - g_object_remove_weak_pointer(G_OBJECT(self), (void **) &data->device); _LOGD(LOGD_DEVICE, - "delete_on_deactivate: cancel cleanup and delete virtual link #%d (id=%u)", - data->ifindex, + "delete_on_deactivate: cancel cleanup and delete virtual link (id=%u)", data->idle_add_id); + g_object_unref(data->device); g_free(data); } } static void -delete_on_deactivate_check_and_schedule(NMDevice *self, int ifindex) +delete_on_deactivate_check_and_schedule(NMDevice *self) { NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); DeleteOnDeactivateData *data; @@ -12208,16 +12175,13 @@ delete_on_deactivate_check_and_schedule(NMDevice *self, int ifindex) return; delete_on_deactivate_unschedule(self); /* always cancel and reschedule */ - data = g_new(DeleteOnDeactivateData, 1); - g_object_add_weak_pointer(G_OBJECT(self), (void **) &data->device); - data->device = self; - data->ifindex = ifindex; + data = g_new(DeleteOnDeactivateData, 1); + data->device = g_object_ref(self); data->idle_add_id = g_idle_add(delete_on_deactivate_link_delete, data); priv->delete_on_deactivate_data = data; _LOGD(LOGD_DEVICE, - "delete_on_deactivate: schedule cleanup and delete virtual link #%d (id=%u)", - ifindex, + "delete_on_deactivate: schedule cleanup and delete virtual link (id=%u)", data->idle_add_id); } @@ -13478,12 +13442,13 @@ nm_device_set_ip_config(NMDevice * self, gboolean commit, GPtrArray * ip4_dev_route_blacklist) { - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - const int IS_IPv4 = NM_IS_IPv4(addr_family); - NMIPConfig * old_config; - gboolean has_changes = FALSE; - gboolean success = TRUE; - NMSettingsConnection *settings_connection; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMIPConfig * old_config; + gboolean has_changes = FALSE; + gboolean success = TRUE; + NMSettingsConnection * settings_connection; + NMIPRouteTableSyncMode route_table_sync_mode; nm_assert_addr_family(addr_family); nm_assert(!new_config || nm_ip_config_get_addr_family(new_config) == addr_family); @@ -13495,11 +13460,18 @@ nm_device_set_ip_config(NMDevice * self, }))); nm_assert(IS_IPv4 || !ip4_dev_route_blacklist); + if (commit && new_config) + route_table_sync_mode = _get_route_table_sync_mode_stateful(self, addr_family); + else + route_table_sync_mode = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE; + _LOGD(LOGD_IPX(IS_IPv4), - "ip%c-config: update (commit=%d, new-config=%p)", + "ip%c-config: update (commit=%d, new-config=" NM_HASH_OBFUSCATE_PTR_FMT + ", route-table-sync-mode=%d)", nm_utils_addr_family_to_char(addr_family), commit, - new_config); + NM_HASH_OBFUSCATE_PTR(new_config), + (int) route_table_sync_mode); /* Always commit to nm-platform to update lifetimes */ if (commit && new_config) { @@ -13508,7 +13480,7 @@ nm_device_set_ip_config(NMDevice * self, if (IS_IPv4) { success = nm_ip4_config_commit(NM_IP4_CONFIG(new_config), nm_device_get_platform(self), - _get_route_table_sync_mode_stateful(self, AF_INET)); + route_table_sync_mode); nm_platform_ip4_dev_route_blacklist_set(nm_device_get_platform(self), nm_ip_config_get_ifindex(new_config), ip4_dev_route_blacklist); @@ -13517,7 +13489,7 @@ nm_device_set_ip_config(NMDevice * self, success = nm_ip6_config_commit(NM_IP6_CONFIG(new_config), nm_device_get_platform(self), - _get_route_table_sync_mode_stateful(self, AF_INET6), + route_table_sync_mode, &temporary_not_available); if (!_rt6_temporary_not_available_set(self, temporary_not_available)) @@ -15846,7 +15818,7 @@ _cleanup_generic_post(NMDevice *self, CleanupType cleanup_type) /* Check if the device was deactivated, and if so, delete_link. * Don't call delete_link synchronously because we are currently * handling a state change -- which is not reentrant. */ - delete_on_deactivate_check_and_schedule(self, nm_device_get_ip_ifindex(self)); + delete_on_deactivate_check_and_schedule(self); } /* ip_iface should be cleared after flushing all routes and addresses, since @@ -15906,9 +15878,12 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu nm_platform_ip_route_flush(platform, AF_UNSPEC, ifindex); nm_platform_ip_address_flush(platform, AF_UNSPEC, ifindex); - nm_platform_tfilter_sync(platform, ifindex, NULL); - nm_platform_qdisc_sync(platform, ifindex, NULL); set_ipv6_token(self, iid, "::"); + + if (nm_device_get_applied_setting(self, NM_TYPE_SETTING_TC_CONFIG)) { + nm_platform_tfilter_sync(platform, ifindex, NULL); + nm_platform_qdisc_sync(platform, ifindex, NULL); + } } } diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h index 72777d0aaf..68343ef5e9 100644 --- a/src/core/devices/nm-device.h +++ b/src/core/devices/nm-device.h @@ -627,27 +627,28 @@ void nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device); * setting the NM_UNMANAGED_IS_SLAVE to %TRUE makes no sense, this flag has only * meaning to set a slave device as managed if the parent is managed too. */ -typedef enum { /*< skip >*/ - NM_UNMANAGED_NONE = 0, +typedef enum { + NM_UNMANAGED_NONE = 0, - /* these flags are authoritative. If one of them is set, + /* these flags are authoritative. If one of them is set, * the device cannot be managed. */ - NM_UNMANAGED_SLEEPING = (1LL << 0), - NM_UNMANAGED_QUITTING = (1LL << 1), - NM_UNMANAGED_PARENT = (1LL << 2), - NM_UNMANAGED_BY_TYPE = (1LL << 3), - NM_UNMANAGED_PLATFORM_INIT = (1LL << 4), - NM_UNMANAGED_USER_EXPLICIT = (1LL << 5), - NM_UNMANAGED_USER_SETTINGS = (1LL << 6), - - /* These flags can be non-effective and be overwritten + NM_UNMANAGED_SLEEPING = (1LL << 0), + NM_UNMANAGED_QUITTING = (1LL << 1), + NM_UNMANAGED_PARENT = (1LL << 2), + NM_UNMANAGED_BY_TYPE = (1LL << 3), + NM_UNMANAGED_PLATFORM_INIT = (1LL << 4), + NM_UNMANAGED_USER_EXPLICIT = (1LL << 5), + NM_UNMANAGED_USER_SETTINGS = (1LL << 6), + + /* These flags can be non-effective and be overwritten * by other flags. */ - NM_UNMANAGED_BY_DEFAULT = (1LL << 8), - NM_UNMANAGED_USER_CONF = (1LL << 9), - NM_UNMANAGED_USER_UDEV = (1LL << 10), - NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 11), - NM_UNMANAGED_IS_SLAVE = (1LL << 12), + NM_UNMANAGED_BY_DEFAULT = (1LL << 7), + NM_UNMANAGED_USER_CONF = (1LL << 8), + NM_UNMANAGED_USER_UDEV = (1LL << 9), + NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 10), + NM_UNMANAGED_IS_SLAVE = (1LL << 11), + NM_UNMANAGED_ALL = ((1LL << 12) - 1), } NMUnmanagedFlags; typedef enum { diff --git a/src/core/devices/ovs/nm-device-ovs-interface.c b/src/core/devices/ovs/nm-device-ovs-interface.c index 5d07c2117e..0a537f7ac3 100644 --- a/src/core/devices/ovs/nm-device-ovs-interface.c +++ b/src/core/devices/ovs/nm-device-ovs-interface.c @@ -77,6 +77,15 @@ is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) return nm_ovsdb_is_ready(priv->ovsdb); } +static gboolean +can_auto_connect(NMDevice *device, NMSettingsConnection *sett_conn, char **specific_object) +{ + NMDeviceOvsInterface * self = NM_DEVICE_OVS_INTERFACE(device); + NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); + + return nm_ovsdb_is_ready(priv->ovsdb); +} + static gboolean check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) { @@ -427,6 +436,7 @@ nm_device_ovs_interface_class_init(NMDeviceOvsInterfaceClass *klass) device_class->connection_type_check_compatible = NM_SETTING_OVS_INTERFACE_SETTING_NAME; device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_OPENVSWITCH); + device_class->can_auto_connect = can_auto_connect; device_class->can_update_from_platform_link = can_update_from_platform_link; device_class->deactivate = deactivate; device_class->deactivate_async = deactivate_async; diff --git a/src/core/devices/wifi/nm-device-iwd.c b/src/core/devices/wifi/nm-device-iwd.c index 95ade44b58..01f2a30396 100644 --- a/src/core/devices/wifi/nm-device-iwd.c +++ b/src/core/devices/wifi/nm-device-iwd.c @@ -588,10 +588,16 @@ deactivate(NMDevice *device) return; } - cleanup_association_attempt(self, TRUE); + cleanup_association_attempt(self, FALSE); priv->act_mode_switch = FALSE; - if (!priv->dbus_station_proxy) + /* Don't trigger any actions on the IWD side until the device is managed */ + if (priv->iwd_autoconnect && nm_device_get_state(device) < NM_DEVICE_STATE_DISCONNECTED) + return; + + if (priv->dbus_station_proxy) + send_disconnect(self); + else reset_mode(self, NULL, NULL, NULL); } @@ -647,6 +653,11 @@ deactivate_async(NMDevice * device, cleanup_association_attempt(self, FALSE); priv->act_mode_switch = FALSE; + if (priv->iwd_autoconnect && nm_device_get_state(device) < NM_DEVICE_STATE_DISCONNECTED) { + nm_utils_invoke_on_idle(cancellable, disconnect_cb_on_idle, user_data); + return; + } + if (priv->dbus_station_proxy) { g_dbus_proxy_call(priv->dbus_station_proxy, "Disconnect", diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c index 042d48871a..c9655eea49 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -2565,6 +2565,7 @@ supplicant_iface_notify_current_bss(NMSupplicantInterface *iface, NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); NMRefString * current_bss; NMWifiAP * new_ap = NULL; + NMActRequest * req; current_bss = nm_supplicant_interface_get_current_bss(iface); if (current_bss) @@ -2612,6 +2613,13 @@ supplicant_iface_notify_current_bss(NMSupplicantInterface *iface, } set_current_ap(self, new_ap, TRUE); + + req = nm_device_get_act_request(NM_DEVICE(self)); + if (req) { + nm_active_connection_set_specific_object( + NM_ACTIVE_CONNECTION(req), + new_ap ? nm_dbus_object_get_path(NM_DBUS_OBJECT(new_ap)) : NULL); + } } } diff --git a/src/core/devices/wifi/nm-iwd-manager.c b/src/core/devices/wifi/nm-iwd-manager.c index b4b019d3e5..68a744380f 100644 --- a/src/core/devices/wifi/nm-iwd-manager.c +++ b/src/core/devices/wifi/nm-iwd-manager.c @@ -1119,6 +1119,7 @@ object_compare_interfaces(gconstpointer a, gconstpointer b) NM_IWD_KNOWN_NETWORK_INTERFACE, NM_IWD_NETWORK_INTERFACE, NM_IWD_DEVICE_INTERFACE, + NULL, }; int rank_a = G_N_ELEMENTS(interface_order); int rank_b = G_N_ELEMENTS(interface_order); diff --git a/src/core/devices/wwan/nm-modem-broadband.c b/src/core/devices/wwan/nm-modem-broadband.c index ca02880417..1297d96433 100644 --- a/src/core/devices/wwan/nm-modem-broadband.c +++ b/src/core/devices/wwan/nm-modem-broadband.c @@ -369,10 +369,10 @@ static void connect_ready(MMModemSimple *simple_iface, GAsyncResult *res, NMModemBroadband *self) { ConnectContext *ctx; - GError * error = NULL; - NMModemIPMethod ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; - NMModemIPMethod ip6_method = NM_MODEM_IP_METHOD_UNKNOWN; - MMBearer * bearer; + GError * error = NULL; + NMModemIPMethod ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; + NMModemIPMethod ip6_method = NM_MODEM_IP_METHOD_UNKNOWN; + gs_unref_object MMBearer *bearer = NULL; bearer = mm_modem_simple_connect_finish(simple_iface, res, &error); @@ -386,7 +386,7 @@ connect_ready(MMModemSimple *simple_iface, GAsyncResult *res, NMModemBroadband * if (!ctx) return; - self->_priv.bearer = bearer; + self->_priv.bearer = g_steal_pointer(&bearer); if (!self->_priv.bearer) { if (g_error_matches(error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index c38c814ead..3b0343fdd7 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -84,6 +84,11 @@ G_DEFINE_ABSTRACT_TYPE(NMDhcpClient, nm_dhcp_client, G_TYPE_OBJECT) /*****************************************************************************/ +/* we use pid=-1 for invalid PIDs. Ensure that pid_t can hold negative values. */ +G_STATIC_ASSERT(!(((pid_t) -1) > 0)); + +/*****************************************************************************/ + pid_t nm_dhcp_client_get_pid(NMDhcpClient *self) { @@ -749,7 +754,7 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release) _LOGI("canceled DHCP transaction"); nm_assert(priv->pid == -1); - nm_dhcp_client_set_state(self, NM_DHCP_STATE_DONE, NULL, NULL); + nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL, NULL); } /*****************************************************************************/ diff --git a/src/core/dhcp/nm-dhcp-client.h b/src/core/dhcp/nm-dhcp-client.h index 72ab477dfb..af3406ccea 100644 --- a/src/core/dhcp/nm-dhcp-client.h +++ b/src/core/dhcp/nm-dhcp-client.h @@ -51,7 +51,7 @@ typedef enum { NM_DHCP_STATE_BOUND, /* new lease */ NM_DHCP_STATE_EXTENDED, /* lease extended */ NM_DHCP_STATE_TIMEOUT, /* timed out contacting server */ - NM_DHCP_STATE_DONE, /* client quit or stopped */ + NM_DHCP_STATE_DONE, /* client reported it's stopping */ NM_DHCP_STATE_EXPIRE, /* lease expired or NAKed */ NM_DHCP_STATE_FAIL, /* failed for some reason */ NM_DHCP_STATE_TERMINATED, /* client is no longer running */ diff --git a/src/core/dhcp/nm-dhcp-dhcpcd.c b/src/core/dhcp/nm-dhcp-dhcpcd.c index cf9fe5c2f6..cdb266edc2 100644 --- a/src/core/dhcp/nm-dhcp-dhcpcd.c +++ b/src/core/dhcp/nm-dhcp-dhcpcd.c @@ -169,27 +169,29 @@ stop(NMDhcpClient *client, gboolean release) int sig, errsv; pid = nm_dhcp_client_get_pid(client); - sig = release ? SIGALRM : SIGTERM; - _LOGD("sending %s to dhcpcd pid %d", sig == SIGALRM ? "SIGALRM" : "SIGTERM", pid); - - /* dhcpcd-9.x features privilege separation. - * It's not our job to track all these processes so we rely on dhcpcd - * to always cleanup after itself. - * Because it also re-parents itself to PID 1, the process cannot be - * reaped or waited for. - * As such, just send the correct signal. - */ - if (kill(pid, sig) == -1) { - errsv = errno; - _LOGE("failed to kill dhcpcd %d:%s", errsv, strerror(errsv)); - } + if (pid > 1) { + sig = release ? SIGALRM : SIGTERM; + _LOGD("sending %s to dhcpcd pid %d", sig == SIGALRM ? "SIGALRM" : "SIGTERM", pid); + + /* dhcpcd-9.x features privilege separation. + * It's not our job to track all these processes so we rely on dhcpcd + * to always cleanup after itself. + * Because it also re-parents itself to PID 1, the process cannot be + * reaped or waited for. + * As such, just send the correct signal. + */ + if (kill(pid, sig) == -1) { + errsv = errno; + _LOGE("failed to kill dhcpcd %d:%s", errsv, strerror(errsv)); + } - /* When this function exits NM expects the PID to be -1. - * This means we also need to stop watching the pid. - * If we need to know the exit status then we need to refactor NM - * to allow a non -1 to mean we're waiting to exit still. - */ - nm_dhcp_client_stop_watch_child(client, pid); + /* When this function exits NM expects the PID to be -1. + * This means we also need to stop watching the pid. + * If we need to know the exit status then we need to refactor NM + * to allow a non -1 to mean we're waiting to exit still. + */ + nm_dhcp_client_stop_watch_child(client, pid); + } } /*****************************************************************************/ diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c index 116e1bdb24..c8b80ea635 100644 --- a/src/core/dhcp/nm-dhcp-nettools.c +++ b/src/core/dhcp/nm-dhcp-nettools.c @@ -342,16 +342,16 @@ lease_parse_routes(NDhcp4ClientLease *lease, const guint8 *l_data; gsize l_data_len; int r; + guint i; - r = _client_lease_query(lease, - NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE, - &l_data, - &l_data_len); - if (r == 0) { - nm_str_buf_reset(sbuf); + for (i = 0; i < 2; i++) { + const guint8 option_code = (i == 0) ? NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE + : NM_DHCP_OPTION_DHCP4_PRIVATE_CLASSLESS_STATIC_ROUTE; - has_classless = TRUE; + if (_client_lease_query(lease, option_code, &l_data, &l_data_len) != 0) + continue; + nm_str_buf_reset(sbuf); while (lease_option_consume_route(&l_data, &l_data_len, TRUE, &dest, &plen, &gateway)) { _nm_utils_inet4_ntop(dest, dest_str); _nm_utils_inet4_ntop(gateway, gateway_str); @@ -359,6 +359,11 @@ lease_parse_routes(NDhcp4ClientLease *lease, nm_str_buf_append_required_delimiter(sbuf, ' '); nm_str_buf_append_printf(sbuf, "%s/%d %s", dest_str, (int) plen, gateway_str); + if (has_classless) { + /* Ignore private option if the standard one is present */ + continue; + } + if (plen == 0) { /* if there are multiple default routes, we add them with differing * metrics. */ @@ -384,10 +389,8 @@ lease_parse_routes(NDhcp4ClientLease *lease, NULL); } - nm_dhcp_option_add_option(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE, - nm_str_buf_get_str(sbuf)); + has_classless = TRUE; + nm_dhcp_option_add_option(options, AF_INET, option_code, nm_str_buf_get_str(sbuf)); } r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_STATIC_ROUTE, &l_data, &l_data_len); @@ -693,8 +696,8 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, v_str = 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_NIS_DOMAIN, v_str); - nm_ip4_config_set_nis_domain(ip4_config, v_str); + nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NIS_DOMAIN, v_str ?: ""); + nm_ip4_config_set_nis_domain(ip4_config, v_str ?: ""); } lease_parse_address_list(lease, ip4_config, NM_DHCP_OPTION_DHCP4_NIS_SERVERS, options, &sbuf); diff --git a/src/core/dhcp/nm-dhcp-systemd.c b/src/core/dhcp/nm-dhcp-systemd.c index b92a9073fa..100807aab3 100644 --- a/src/core/dhcp/nm-dhcp-systemd.c +++ b/src/core/dhcp/nm-dhcp-systemd.c @@ -85,29 +85,29 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, const struct in_addr * addr_list; char addr_str[NM_UTILS_INET_ADDRSTRLEN]; const char * s; - nm_auto_free_gstring GString *str = NULL; - gs_free sd_dhcp_route **routes = NULL; - const char *const * search_domains = NULL; - guint16 mtu; - int i, num; - const void * data; - gsize data_len; - gboolean metered = FALSE; - gboolean has_router_from_classless = FALSE; - gboolean has_classless_route = FALSE; - gboolean has_static_route = 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; + nm_auto_free_gstring GString *str = NULL; + nm_auto_free sd_dhcp_route **routes = NULL; + const char *const * search_domains = NULL; + guint16 mtu; + int i, num; + const void * data; + gsize data_len; + gboolean metered = FALSE; + gboolean has_router_from_classless = FALSE; + gboolean has_classless_route = FALSE; + gboolean has_static_route = 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); diff --git a/src/core/dhcp/nm-dhcp-utils.c b/src/core/dhcp/nm-dhcp-utils.c index 646411e201..63d90641d6 100644 --- a/src/core/dhcp/nm-dhcp-utils.c +++ b/src/core/dhcp/nm-dhcp-utils.c @@ -880,7 +880,7 @@ nm_dhcp_lease_data_parse_cstr(const guint8 *data, gsize n_data, gsize *out_new_l n_data--; if (n_data > 0) { - if (memchr(data, n_data, '\0')) { + if (memchr(data, '\0', n_data)) { /* we accept trailing NUL, but none in between. * * https://tools.ietf.org/html/rfc2132#section-2 diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c index f318b9b89b..59c8898a03 100644 --- a/src/core/dns/nm-dns-manager.c +++ b/src/core/dns/nm-dns-manager.c @@ -1624,7 +1624,7 @@ _mgr_configs_data_clear(NMDnsManager *self) /*****************************************************************************/ static gboolean -update_dns(NMDnsManager *self, gboolean no_caching, GError **error) +update_dns(NMDnsManager *self, gboolean no_caching, gboolean force_emit, GError **error) { NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self); const char * nis_domain = NULL; @@ -1815,8 +1815,8 @@ plugin_skip:; NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED); } - /* signal that resolv.conf was changed */ - if (do_update && result == SR_SUCCESS) + /* signal that DNS resolution configs were changed */ + if ((do_update || caching || force_emit) && result == SR_SUCCESS) g_signal_emit(self, signals[CONFIG_CHANGED], 0); nm_clear_pointer(&priv->config_variant, g_variant_unref); @@ -1924,7 +1924,7 @@ changed: if (!priv->updates_queue) { gs_free_error GError *error = NULL; - if (!update_dns(self, FALSE, &error)) + if (!update_dns(self, FALSE, FALSE, &error)) _LOGW("could not commit DNS changes: %s", error->message); } @@ -1965,7 +1965,7 @@ nm_dns_manager_set_hostname(NMDnsManager *self, const char *hostname, gboolean s if (!priv->updates_queue) { gs_free_error GError *error = NULL; - if (!update_dns(self, FALSE, &error)) + if (!update_dns(self, FALSE, FALSE, &error)) _LOGW("could not commit DNS changes: %s", error->message); } } @@ -2012,7 +2012,7 @@ nm_dns_manager_end_updates(NMDnsManager *self, const char *func) /* Commit all the outstanding changes */ _LOGD("(%s): committing DNS changes (%d)", func, priv->updates_queue); - if (!update_dns(self, FALSE, &error)) + if (!update_dns(self, FALSE, FALSE, &error)) _LOGW("could not commit DNS changes: %s", error->message); memset(priv->prev_hash, 0, sizeof(priv->prev_hash)); @@ -2038,7 +2038,7 @@ nm_dns_manager_stop(NMDnsManager *self) if (priv->dns_touched && priv->plugin && NM_IS_DNS_DNSMASQ(priv->plugin)) { gs_free_error GError *error = NULL; - if (!update_dns(self, TRUE, &error)) + if (!update_dns(self, TRUE, FALSE, &error)) _LOGW("could not commit DNS changes on shutdown: %s", error->message); priv->dns_touched = FALSE; @@ -2363,7 +2363,7 @@ config_changed_cb(NMConfig * config, | NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG)) { gs_free_error GError *error = NULL; - if (!update_dns(self, FALSE, &error)) + if (!update_dns(self, FALSE, TRUE, &error)) _LOGW("could not commit DNS changes: %s", error->message); } } diff --git a/src/core/initrd/nmi-cmdline-reader.c b/src/core/initrd/nmi-cmdline-reader.c index 508ef2b25c..0a24199efe 100644 --- a/src/core/initrd/nmi-cmdline-reader.c +++ b/src/core/initrd/nmi-cmdline-reader.c @@ -393,8 +393,9 @@ reader_read_all_connections_from_fw(Reader *reader, const char *sysfs_dir) static void reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument) { - NMConnection * connection; - NMSettingIPConfig *s_ip4 = NULL, *s_ip6 = NULL; + NMConnection * connection; + NMSettingConnection *s_con; + NMSettingIPConfig * s_ip4 = NULL, *s_ip6 = NULL; gs_unref_hashtable GHashTable *ibft = NULL; const char * tmp; const char * tmp2; @@ -495,6 +496,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument) g_hash_table_add(reader->explicit_ip_connections, g_object_ref(connection)); + s_con = nm_connection_get_setting_connection(connection); s_ip4 = nm_connection_get_setting_ip4_config(connection); s_ip6 = nm_connection_get_setting_ip6_config(connection); @@ -544,6 +546,12 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument) nm_assert_not_reached(); if (address) { + /* We don't want to have multiple devices up with the + * same static address. */ + g_object_set(s_con, + NM_SETTING_CONNECTION_MULTI_CONNECT, + NM_CONNECTION_MULTI_CONNECT_SINGLE, + NULL); switch (client_ip_family) { case AF_INET: g_object_set(s_ip4, @@ -599,7 +607,12 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument) NULL); } } else if (NM_IN_STRSET(kind, "auto6", "dhcp6")) { - g_object_set(s_ip4, NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE, NULL); + g_object_set(s_ip6, + NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP_CONFIG_MAY_FAIL, + FALSE, + NULL); if (nm_setting_ip_config_get_num_addresses(s_ip4) == 0) { g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, @@ -764,6 +777,9 @@ reader_parse_master(Reader *reader, char *argument, const char *type_name, const mtu = get_word(&argument, ':'); } + if (mtu) + connection_set(connection, NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MTU, mtu); + do { slave = get_word(&slaves, ','); if (slave == NULL) @@ -777,8 +793,6 @@ reader_parse_master(Reader *reader, char *argument, const char *type_name, const NM_SETTING_CONNECTION_MASTER, master, NULL); - if (mtu) - connection_set(connection, NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MTU, mtu); } while (slaves && *slaves != '\0'); if (argument && *argument) @@ -916,6 +930,11 @@ reader_parse_rd_znet(Reader *reader, char *argument, gboolean net_ifnames) subchannels[0] = get_word(&argument, ','); subchannels[1] = get_word(&argument, ','); + /* Without subchannels we can't univocally match + * a device. */ + if (!subchannels[0] || !subchannels[1]) + return; + if (nm_streq0(nettype, "ctc")) { if (net_ifnames == TRUE) { prefix = "sl"; diff --git a/src/core/initrd/tests/test-cmdline-reader.c b/src/core/initrd/tests/test-cmdline-reader.c index 33fb22d364..e3a3753e06 100644 --- a/src/core/initrd/tests/test-cmdline-reader.c +++ b/src/core/initrd/tests/test-cmdline-reader.c @@ -455,6 +455,46 @@ test_if_ip4_manual(void) g_assert(nm_setting_ip_config_get_may_fail(s_ip6)); } +static void +test_if_ip4_manual_no_dev(void) +{ + const char *const * ARGV = NM_MAKE_STRV("ip=192.0.2.2::192.0.2.1:24:::"); + NMConnection * connection; + NMSettingConnection *s_con; + NMSettingIPConfig * s_ip4; + NMSettingIPConfig * s_ip6; + NMIPAddress * ip_addr; + + connection = _parse_con(ARGV, "default_connection"); + g_assert_cmpstr(nm_connection_get_id(connection), ==, "Wired Connection"); + + s_con = nm_connection_get_setting_connection(connection); + g_assert(s_con); + g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1); + g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), + ==, + NM_CONNECTION_MULTI_CONNECT_SINGLE); + + s_ip4 = nm_connection_get_setting_ip4_config(connection); + g_assert(s_ip4); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), + ==, + NM_SETTING_IP4_CONFIG_METHOD_MANUAL); + g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4)); + g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 0); + g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1); + ip_addr = nm_setting_ip_config_get_address(s_ip4, 0); + g_assert(ip_addr); + g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "192.0.2.2"); + g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 24); + g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.0.2.1"); + + s_ip6 = nm_connection_get_setting_ip6_config(connection); + g_assert(s_ip6); + g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_assert(nm_setting_ip_config_get_may_fail(s_ip6)); +} + static void test_if_ip6_manual(void) { @@ -825,13 +865,14 @@ test_bond(void) { gs_unref_hashtable GHashTable *connections = NULL; const char *const * ARGV = NM_MAKE_STRV("rd.route=192.0.2.53::bong0", - "bond=bong0:eth0,eth1:mode=balance-rr", + "bond=bong0:eth0,eth1:mode=balance-rr:9000", "nameserver=203.0.113.53"); NMConnection * connection; NMSettingConnection * s_con; NMSettingIPConfig * s_ip4; NMSettingIPConfig * s_ip6; NMSettingBond * s_bond; + NMSettingWired * s_wired; NMIPRoute * ip_route; const char * master_uuid; @@ -847,6 +888,10 @@ test_bond(void) master_uuid = nm_connection_get_uuid(connection); g_assert(master_uuid); + s_wired = nm_connection_get_setting_wired(connection); + g_assert(s_wired); + g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 9000); + s_ip4 = nm_connection_get_setting_ip4_config(connection); g_assert(s_ip4); g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); @@ -1810,6 +1855,24 @@ test_rd_znet_no_ip(void) g_assert_cmpint(g_hash_table_size(connections), ==, 0); } +static void +test_rd_znet_malformed(void) +{ + const char *const *const ARGV0 = NM_MAKE_STRV("rd.znet="); + const char *const *const ARGV1 = NM_MAKE_STRV("rd.znet=,"); + const char *const *const ARGV2 = NM_MAKE_STRV("rd.znet=foobar"); + const char *const *const ARGV3 = NM_MAKE_STRV("rd.znet=qeth,0.0.0800,,,layer2=0,portno=1"); + const char *const *const ARGV[] = {ARGV0, ARGV1, ARGV2, ARGV3}; + guint i; + + for (i = 0; i < G_N_ELEMENTS(ARGV); i++) { + gs_unref_hashtable GHashTable *connections = NULL; + + connections = _parse_cons(ARGV[i]); + g_assert_cmpint(g_hash_table_size(connections), ==, 0); + } +} + static void test_bootif_ip(void) { @@ -2142,6 +2205,7 @@ main(int argc, char **argv) g_test_add_func("/initrd/cmdline/if_dhcp6", test_if_dhcp6); g_test_add_func("/initrd/cmdline/if_auto_with_mtu_and_mac", test_if_auto_with_mtu_and_mac); g_test_add_func("/initrd/cmdline/if_ip4_manual", test_if_ip4_manual); + g_test_add_func("/initrd/cmdline/if_ip4_manual_no_dev", test_if_ip4_manual_no_dev); g_test_add_func("/initrd/cmdline/if_ip6_manual", test_if_ip6_manual); g_test_add_func("/initrd/cmdline/if_mac_ifname", test_if_mac_ifname); g_test_add_func("/initrd/cmdline/if_off", test_if_off); @@ -2168,6 +2232,7 @@ main(int argc, char **argv) g_test_add_func("/initrd/cmdline/rd_znet", test_rd_znet); g_test_add_func("/initrd/cmdline/rd_znet/legacy", test_rd_znet_legacy); g_test_add_func("/initrd/cmdline/rd_znet/no_ip", test_rd_znet_no_ip); + g_test_add_func("/initrd/cmdline/rd_znet/empty", test_rd_znet_malformed); g_test_add_func("/initrd/cmdline/bootif/ip", test_bootif_ip); g_test_add_func("/initrd/cmdline/bootif/no_ip", test_bootif_no_ip); g_test_add_func("/initrd/cmdline/bootif/hwtype", test_bootif_hwtype); diff --git a/src/core/nm-config-data.c b/src/core/nm-config-data.c index c62c677372..d457f505ba 100644 --- a/src/core/nm-config-data.c +++ b/src/core/nm-config-data.c @@ -437,7 +437,7 @@ static NMAuthPolkitMode _config_data_get_main_auth_polkit(const NMConfigData *self, gboolean *out_invalid_config) { NMAuthPolkitMode auth_polkit_mode; - const char * str; + gs_free char * str = NULL; str = nm_config_data_get_value(self, NM_CONFIG_KEYFILE_GROUP_MAIN, diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index 9075c30dd0..a27c50dc1c 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -1956,7 +1956,8 @@ nm_wildcard_match_check(const char *str, const char *const *patterns, guint num_ _pattern_parse(patterns[i], &p, &is_inverted, &is_mandatory); - match = (fnmatch(p, str, 0) == 0); + match = (fnmatch(p, str ?: "", 0) == 0); + if (is_inverted) match = !match; @@ -5065,9 +5066,12 @@ nm_wifi_utils_parse_ies(const guint8 *bytes, case WLAN_EID_VENDOR_SPECIFIC: if (len == 8 && bytes[0] == 0x00 /* OUI: Microsoft */ && bytes[1] == 0x50 && bytes[2] == 0xf2 - && bytes[3] == 0x11) /* OUI type: Network cost */ - NM_SET_OUT(out_metered, (bytes[7] > 1)); /* Cost level > 1 */ - if (elem_len >= 10 && bytes[0] == 0x50 /* OUI: WiFi Alliance */ + && bytes[3] == 0x11) /* OUI type: Network cost */ + { + /* https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nct/ */ + NM_SET_OUT(out_metered, (bytes[4] > 1)); /* Cost level > 1 */ + } + if (elem_len >= 10 && bytes[0] == 0x50 /* OUI: WiFi Alliance */ && bytes[1] == 0x6f && bytes[2] == 0x9a && bytes[3] == 0x1c) /* OUI type: OWE Transition Mode */ NM_SET_OUT(out_owe_transition_mode, TRUE); diff --git a/src/core/nm-ip4-config.c b/src/core/nm-ip4-config.c index c49dfb4c34..608b7fc8b7 100644 --- a/src/core/nm-ip4-config.c +++ b/src/core/nm-ip4-config.c @@ -649,21 +649,6 @@ nm_ip4_config_add_dependent_routes(NMIP4Config *self, if (my_addr->external) continue; - /* Pre-generate local route added by kernel */ - r = nmp_object_new(NMP_OBJECT_TYPE_IP4_ROUTE, NULL); - route = NMP_OBJECT_CAST_IP4_ROUTE(r); - route->ifindex = ifindex; - route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL; - route->network = my_addr->address; - route->plen = 32; - route->pref_src = my_addr->address; - route->type_coerced = nm_platform_route_type_coerce(RTN_LOCAL); - route->scope_inv = nm_platform_route_scope_inv(RT_SCOPE_HOST); - route->table_coerced = - nm_platform_route_table_coerce(is_vrf ? route_table : RT_TABLE_LOCAL); - _add_route(self, r, NULL, NULL); - nm_clear_pointer(&r, nmp_object_unref); - if (nm_utils_ip4_address_is_zeronet(network)) { /* Kernel doesn't add device-routes for destinations that * start with 0.x.y.z. Skip them. */ diff --git a/src/core/nm-ip6-config.c b/src/core/nm-ip6-config.c index 1f7def3465..1e36050d9b 100644 --- a/src/core/nm-ip6-config.c +++ b/src/core/nm-ip6-config.c @@ -396,23 +396,6 @@ nm_ip6_config_add_dependent_routes(NMIP6Config *self, * * For manually added IPv6 routes, add the device routes explicitly. */ - /* Pre-generate multicast route */ - { - nm_auto_nmpobj NMPObject *r = NULL; - NMPlatformIP6Route * route; - - r = nmp_object_new(NMP_OBJECT_TYPE_IP6_ROUTE, NULL); - route = NMP_OBJECT_CAST_IP6_ROUTE(r); - route->ifindex = ifindex; - route->network.s6_addr[0] = 0xffu; - route->plen = 8; - route->table_coerced = nm_platform_route_table_coerce(RT_TABLE_LOCAL); - route->type_coerced = nm_platform_route_type_coerce(RTN_UNICAST); - route->metric = 256; - - _add_route(self, r, NULL, NULL); - } - nm_ip_config_iter_ip6_address_for_each (&iter, self, &my_addr) { NMPlatformIP6Route *route; gboolean has_peer; @@ -421,22 +404,6 @@ nm_ip6_config_add_dependent_routes(NMIP6Config *self, if (my_addr->external) continue; - { - nm_auto_nmpobj NMPObject *r = NULL; - - /* Pre-generate local route added by kernel */ - r = nmp_object_new(NMP_OBJECT_TYPE_IP6_ROUTE, NULL); - route = NMP_OBJECT_CAST_IP6_ROUTE(r); - route->ifindex = ifindex; - route->network = my_addr->address; - route->plen = 128; - route->type_coerced = nm_platform_route_type_coerce(RTN_LOCAL); - route->metric = 0; - route->table_coerced = - nm_platform_route_table_coerce(is_vrf ? route_table : RT_TABLE_LOCAL); - _add_route(self, r, NULL, NULL); - } - if (NM_FLAGS_HAS(my_addr->n_ifa_flags, IFA_F_NOPREFIXROUTE)) continue; if (my_addr->plen == 0) diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index 5a6e05a934..f44306e1b8 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -363,6 +363,7 @@ static NMActiveConnection *active_connection_find(NMManager * self, NMSettingsConnection * sett_conn, const char * uuid, NMActiveConnectionState max_state, + gboolean also_waiting_auth, GPtrArray ** out_all_matching); static NMConnectivity *concheck_get_mgr(NMManager *self); @@ -833,6 +834,7 @@ _delete_volatile_connection_do(NMManager *self, NMSettingsConnection *connection connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED, + TRUE, NULL)) return; @@ -978,6 +980,7 @@ active_connection_find( NMSettingsConnection * sett_conn, const char * uuid, NMActiveConnectionState max_state /* candidates in state @max_state will be found */, + gboolean also_waiting_auth /* return also ACs waiting authorization */, GPtrArray ** out_all_matching) { NMManagerPrivate * priv = NM_MANAGER_GET_PRIVATE(self); @@ -1017,11 +1020,14 @@ active_connection_find( if (!best_ac) { AsyncOpData *async_op_data; + if (!also_waiting_auth) + return NULL; + c_list_for_each_entry (async_op_data, &priv->async_op_lst_head, async_op_lst) { NMSettingsConnection *ac_conn; ac = async_op_data->ac_auth.active; - ac_conn = nm_active_connection_get_settings_connection(ac); + ac_conn = _nm_active_connection_get_settings_connection(ac); if (sett_conn && sett_conn != ac_conn) continue; if (uuid && !nm_streq0(uuid, nm_settings_connection_get_uuid(ac_conn))) @@ -1078,6 +1084,7 @@ active_connection_find_by_connection(NMManager * self, sett_conn, sett_conn ? NULL : nm_connection_get_uuid(connection), max_state, + FALSE, out_all_matching); } @@ -1112,6 +1119,7 @@ _get_activatable_connections_filter(NMSettings * settings, sett_conn, NULL, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, + FALSE, NULL); } @@ -2245,6 +2253,7 @@ connection_flags_changed(NMSettings *settings, NMSettingsConnection *connection, connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED, + FALSE, NULL)) { /* the connection still has an active-connection. It will be purged * when the active connection(s) get(s) removed. */ @@ -2564,6 +2573,7 @@ new_activation_allowed_for_connection(NMManager *self, NMSettingsConnection *con connection, NULL, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, + FALSE, NULL); } @@ -2839,14 +2849,16 @@ recheck_assume_connection(NMManager *self, NMDevice *device) g_return_val_if_fail(NM_IS_DEVICE(device), FALSE); if (!nm_device_get_managed(device, FALSE)) { - nm_device_assume_state_reset(device); + /* If the device is only unmanaged by NM_UNMANAGED_PLATFORM_INIT, + * don't reset the state now but wait until it becomes managed. */ + if (nm_device_get_unmanaged_flags(device, NM_UNMANAGED_ALL) != NM_UNMANAGED_PLATFORM_INIT) + nm_device_assume_state_reset(device); _LOG2D(LOGD_DEVICE, device, "assume: don't assume because %s", "not managed"); return FALSE; } state = nm_device_get_state(device); if (state > NM_DEVICE_STATE_DISCONNECTED) { - nm_device_assume_state_reset(device); _LOG2D(LOGD_DEVICE, device, "assume: don't assume due to device state %s", @@ -3161,7 +3173,10 @@ _device_realize_finish(NMManager *self, NMDevice *device, const NMPlatformLink * nm_device_realize_finish(device, plink); if (!nm_device_get_managed(device, FALSE)) { - nm_device_assume_state_reset(device); + /* If the device is only unmanaged by NM_UNMANAGED_PLATFORM_INIT, + * don't reset the state now but wait until it becomes managed. */ + if (nm_device_get_unmanaged_flags(device, NM_UNMANAGED_ALL) != NM_UNMANAGED_PLATFORM_INIT) + nm_device_assume_state_reset(device); return; } @@ -3509,6 +3524,45 @@ typedef struct { guint idle_id; } PlatformLinkCbData; +static gboolean +_check_remove_dev_on_link_deleted(NMManager *self, NMDevice *device) +{ + NMManagerPrivate * priv = NM_MANAGER_GET_PRIVATE(self); + NMSettingsConnection *const *scons = NULL; + NMConnection * con; + guint i; + + nm_assert(nm_device_is_software(device)); + + /* In general, software devices stick around as unrealized + * until their connection is removed. However, we don't want + * that a NM-generated connection keeps the device alive. + * If there are no other compatible connections, the device + * should be also removed. + */ + + scons = nm_settings_get_connections(priv->settings, NULL); + + for (i = 0; scons[i]; i++) { + con = nm_settings_connection_get_connection(scons[i]); + if (!nm_connection_is_virtual(con)) + continue; + + if (NM_FLAGS_HAS(nm_settings_connection_get_flags(scons[i]), + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) + continue; + + if (!nm_device_check_connection_compatible(device, con, NULL)) + continue; + + /* Found a virtual connection compatible, the device must + * stay around unrealized. */ + return FALSE; + } + + return TRUE; +} + static gboolean _platform_link_cb_idle(PlatformLinkCbData *data) { @@ -3534,13 +3588,15 @@ _platform_link_cb_idle(PlatformLinkCbData *data) if (device) { if (nm_device_is_software(device)) { nm_device_sys_iface_state_set(device, NM_DEVICE_SYS_IFACE_STATE_REMOVED); - /* Our software devices stick around until their connection is removed */ if (!nm_device_unrealize(device, FALSE, &error)) { _LOG2W(LOGD_DEVICE, device, "failed to unrealize: %s", error->message); g_clear_error(&error); remove_device(self, device, FALSE); } else { - nm_device_update_from_platform_link(device, NULL); + if (_check_remove_dev_on_link_deleted(self, device)) + remove_device(self, device, FALSE); + else + nm_device_update_from_platform_link(device, NULL); } } else { /* Hardware and external devices always get removed when their kernel link is gone */ @@ -4134,6 +4190,7 @@ find_master(NMManager * self, master_connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING, + FALSE, NULL); } @@ -4985,6 +5042,7 @@ _internal_activate_device(NMManager *self, NMActiveConnection *active, GError ** sett_conn, NULL, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, + FALSE, &all_ac_arr); if (ac) { n_all = all_ac_arr ? all_ac_arr->len : ((guint) 1); diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index db4983f889..71aa1eceaf 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -652,6 +652,7 @@ device_hostname_info_compare(gconstpointer a, gconstpointer b) NM_CMP_FIELD(info1, info2, priority); NM_CMP_FIELD_UNSAFE(info2, info1, is_default); + NM_CMP_FIELD_UNSAFE(info2, info1, IS_IPv4); return 0; } diff --git a/src/core/nm-types.h b/src/core/nm-types.h index ab2314594d..8a32b7d204 100644 --- a/src/core/nm-types.h +++ b/src/core/nm-types.h @@ -245,12 +245,16 @@ typedef enum { * local table (255). * @NM_IP_ROUTE_TABLE_SYNC_MODE_ALL: NM will sync all tables, including the * local table (255). + * @NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE: NM will sync all tables (including + * the local table). It will thereby remove all addresses, that is during + * deactivation. */ typedef enum { - NM_IP_ROUTE_TABLE_SYNC_MODE_NONE = 0, - NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN = 1, - NM_IP_ROUTE_TABLE_SYNC_MODE_FULL = 2, - NM_IP_ROUTE_TABLE_SYNC_MODE_ALL = 3, + NM_IP_ROUTE_TABLE_SYNC_MODE_NONE, + NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, + NM_IP_ROUTE_TABLE_SYNC_MODE_FULL, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL, + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE, } NMIPRouteTableSyncMode; /* settings */ diff --git a/src/core/platform/nm-platform.c b/src/core/platform/nm-platform.c index 0e5f8ab548..459a330717 100644 --- a/src/core/platform/nm-platform.c +++ b/src/core/platform/nm-platform.c @@ -4357,34 +4357,134 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self, GPtrArray * routes_prune; const NMDedupMultiHeadEntry *head_entry; CList * iter; + NMPlatformIP4Route rt_local4; + NMPlatformIP6Route rt_local6; + const NMPlatformLink * pllink; + const NMPlatformLnkVrf * lnk_vrf; + guint32 local_table; nm_assert(NM_IS_PLATFORM(self)); nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6)); nm_assert(NM_IN_SET(route_table_sync, NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, NM_IP_ROUTE_TABLE_SYNC_MODE_FULL, - NM_IP_ROUTE_TABLE_SYNC_MODE_ALL)); + 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); head_entry = nm_platform_lookup(self, &lookup); if (!head_entry) return NULL; + lnk_vrf = nm_platform_link_get_lnk_vrf(self, ifindex, &pllink); + if (!lnk_vrf && pllink && pllink->master > 0) + lnk_vrf = nm_platform_link_get_lnk_vrf(self, pllink->master, NULL); + local_table = lnk_vrf ? lnk_vrf->table : RT_TABLE_LOCAL; + + rt_local4.plen = 0; + rt_local6.plen = 0; + routes_prune = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref); c_list_for_each (iter, &head_entry->lst_entries_head) { - const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj; + const NMPObject * obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj; + const NMPlatformIPXRoute *rt = NMP_OBJECT_CAST_IPX_ROUTE(obj); - if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_FULL) { - if (nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj)) - == RT_TABLE_LOCAL) + switch (route_table_sync) { + case NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN: + if (!nm_platform_route_table_is_main(nm_platform_ip_route_get_effective_table(&rt->rx))) continue; - } else if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN) { - if (!nm_platform_route_table_is_main( - nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj)))) + break; + case NM_IP_ROUTE_TABLE_SYNC_MODE_FULL: + if (nm_platform_ip_route_get_effective_table(&rt->rx) == RT_TABLE_LOCAL) continue; - } else - nm_assert(route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_ALL); + break; + case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL: + + /* FIXME: we should better handle routes that are automatically added by kernel. + * + * For now, make a good guess which are those routes and exclude them from + * pruning them. */ + + if (NM_IS_IPv4(addr_family)) { + /* for each IPv4 address kernel adds a route like + * + * local $ADDR dev $IFACE table local proto kernel scope host src $PRIMARY_ADDR + * + * Check whether route could be of that kind. */ + if (nm_platform_ip_route_get_effective_table(&rt->rx) == local_table + && rt->rx.plen == 32 && rt->rx.rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL + && rt->rx.metric == 0 + && rt->r4.scope_inv == nm_platform_route_scope_inv(RT_SCOPE_HOST) + && rt->r4.gateway == INADDR_ANY) { + if (rt_local4.plen == 0) { + rt_local4 = (NMPlatformIP4Route){ + .ifindex = ifindex, + .type_coerced = nm_platform_route_type_coerce(RTN_LOCAL), + .plen = 32, + .rt_source = NM_IP_CONFIG_SOURCE_RTPROT_KERNEL, + .metric = 0, + .table_coerced = nm_platform_route_table_coerce(local_table), + .scope_inv = nm_platform_route_scope_inv(RT_SCOPE_HOST), + .gateway = INADDR_ANY, + }; + } + + /* the possible "network" depends on the addresses we have. We don't check that + * carefully. If the other parameters match, we assume that this route is the one + * generated by kernel. */ + rt_local4.network = rt->r4.network; + rt_local4.pref_src = rt->r4.pref_src; + + /* to be more confident about comparing the value, use our nm_platform_ip4_route_cmp() + * implementation. That will also consider parameters that we leave unspecified here. */ + if (nm_platform_ip4_route_cmp(&rt->r4, + &rt_local4, + NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) + == 0) + continue; + } + } else { + /* for each IPv6 address (that is no longer tentative) kernel adds a route like + * + * local $ADDR dev $IFACE table local proto kernel metric 0 pref medium + * + * Same as for the IPv4 case. */ + if (nm_platform_ip_route_get_effective_table(&rt->rx) == local_table + && rt->rx.plen == 128 && rt->rx.rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL + && rt->rx.metric == 0 && rt->r6.rt_pref == NM_ICMPV6_ROUTER_PREF_MEDIUM + && IN6_IS_ADDR_UNSPECIFIED(&rt->r6.gateway)) { + if (rt_local6.plen == 0) { + rt_local6 = (NMPlatformIP6Route){ + .ifindex = ifindex, + .type_coerced = nm_platform_route_type_coerce(RTN_LOCAL), + .plen = 128, + .rt_source = NM_IP_CONFIG_SOURCE_RTPROT_KERNEL, + .metric = 0, + .table_coerced = nm_platform_route_table_coerce(local_table), + .rt_pref = NM_ICMPV6_ROUTER_PREF_MEDIUM, + .gateway = IN6ADDR_ANY_INIT, + }; + } + + rt_local6.network = rt->r6.network; + + if (nm_platform_ip6_route_cmp(&rt->r6, + &rt_local6, + NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) + == 0) + continue; + } + } + break; + + case NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE: + break; + + default: + nm_assert_not_reached(); + break; + } g_ptr_array_add(routes_prune, (gpointer) nmp_object_ref(obj)); } @@ -4679,7 +4779,7 @@ nm_platform_ip_route_flush(NMPlatform *self, int addr_family, int ifindex) routes_prune = nm_platform_ip_route_get_prune_list(self, AF_INET, ifindex, - NM_IP_ROUTE_TABLE_SYNC_MODE_ALL); + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE); success &= nm_platform_ip_route_sync(self, AF_INET, ifindex, NULL, routes_prune, NULL); } if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)) { @@ -4688,7 +4788,7 @@ nm_platform_ip_route_flush(NMPlatform *self, int addr_family, int ifindex) routes_prune = nm_platform_ip_route_get_prune_list(self, AF_INET6, ifindex, - NM_IP_ROUTE_TABLE_SYNC_MODE_ALL); + NM_IP_ROUTE_TABLE_SYNC_MODE_ALL_PRUNE); success &= nm_platform_ip_route_sync(self, AF_INET6, ifindex, NULL, routes_prune, NULL); } return success; diff --git a/src/core/platform/tests/test-common.c b/src/core/platform/tests/test-common.c index 4a117d59da..1b977145e5 100644 --- a/src/core/platform/tests/test-common.c +++ b/src/core/platform/tests/test-common.c @@ -1542,7 +1542,10 @@ nmtstp_link_bridge_add(NMPlatform * platform, ll = NMP_OBJECT_CAST_LNK_BRIDGE(NMP_OBJECT_UP_CAST(pllink)->_link.netlink.lnk); - g_assert_cmpint(lnk->forward_delay, ==, ll->forward_delay); + /* account for roundtrip rounding error with clock_t_to_jiffies()/jiffies_to_clock_t(). */ + g_assert_cmpint(lnk->forward_delay, >=, ll->forward_delay - 1); + g_assert_cmpint(lnk->forward_delay, <=, ll->forward_delay); + g_assert_cmpint(lnk->hello_time, ==, ll->hello_time); g_assert_cmpint(lnk->max_age, ==, ll->max_age); g_assert_cmpint(lnk->ageing_time, ==, ll->ageing_time); 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 209957d9b8..a42c418884 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 @@ -2707,7 +2707,8 @@ make_tc_setting(shvarFile *ifcfg) } if (nm_setting_tc_config_get_num_qdiscs(s_tc) > 0 - || nm_setting_tc_config_get_num_tfilters(s_tc) > 0) + || nm_setting_tc_config_get_num_tfilters(s_tc) > 0 + || svGetValueBoolean(ifcfg, "TC_COMMIT", FALSE)) return NM_SETTING(s_tc); g_object_unref(s_tc); 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 8da5de473b..ada1942acb 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 @@ -1026,6 +1026,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { _KEY_TYPE("STABLE_ID", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("STP", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("SUBCHANNELS", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("TC_COMMIT", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("TEAM_CONFIG", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("TEAM_MASTER", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("TEAM_MASTER_UUID", 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 36ec922514..04a1b63d3e 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[247]; +extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[248]; 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 a968fce0ba..45b76456b5 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 @@ -1137,7 +1137,7 @@ write_wired_setting(NMConnection *connection, shvarFile *ifcfg, GError **error) svSetValueStr(ifcfg, "CTCPROT", nm_setting_wired_get_s390_option_by_key(s_wired, "ctcprot")); num_opts = nm_setting_wired_get_num_s390_options(s_wired); - if (s390_subchannels && num_opts) { + if (num_opts > 0) { nm_auto_free_gstring GString *tmp = NULL; for (i = 0; i < num_opts; i++) { @@ -2511,46 +2511,46 @@ write_sriov_setting(NMConnection *connection, shvarFile *ifcfg) } } -static gboolean -write_tc_setting(NMConnection *connection, shvarFile *ifcfg, GError **error) +static void +write_tc_setting(NMConnection *connection, shvarFile *ifcfg) { NMSettingTCConfig *s_tc; - guint i, num, n; + guint num_qdiscs; + guint num_filters; + guint i; + guint n; char tag[64]; s_tc = nm_connection_get_setting_tc_config(connection); if (!s_tc) - return TRUE; + return; - num = nm_setting_tc_config_get_num_qdiscs(s_tc); - for (n = 1, i = 0; i < num; i++) { + num_qdiscs = nm_setting_tc_config_get_num_qdiscs(s_tc); + for (n = 1, i = 0; i < num_qdiscs; i++) { NMTCQdisc * qdisc; gs_free char *str = NULL; qdisc = nm_setting_tc_config_get_qdisc(s_tc, i); - str = nm_utils_tc_qdisc_to_str(qdisc, error); - if (!str) - return FALSE; - + str = nm_utils_tc_qdisc_to_str(qdisc, NULL); + nm_assert(str); svSetValueStr(ifcfg, numbered_tag(tag, "QDISC", n), str); n++; } - num = nm_setting_tc_config_get_num_tfilters(s_tc); - for (n = 1, i = 0; i < num; i++) { + num_filters = nm_setting_tc_config_get_num_tfilters(s_tc); + for (n = 1, i = 0; i < num_filters; i++) { NMTCTfilter * tfilter; gs_free char *str = NULL; tfilter = nm_setting_tc_config_get_tfilter(s_tc, i); - str = nm_utils_tc_tfilter_to_str(tfilter, error); - if (!str) - return FALSE; - + str = nm_utils_tc_tfilter_to_str(tfilter, NULL); + nm_assert(str); svSetValueStr(ifcfg, numbered_tag(tag, "FILTER", n), str); n++; } - return TRUE; + if (num_qdiscs == 0 && num_filters == 0) + svSetValueBoolean(ifcfg, "TC_COMMIT", TRUE); } static void @@ -3373,9 +3373,7 @@ do_write_construct(NMConnection * connection, write_match_setting(connection, ifcfg); write_hostname_setting(connection, ifcfg); write_sriov_setting(connection, ifcfg); - - if (!write_tc_setting(connection, ifcfg, error)) - return FALSE; + write_tc_setting(connection, ifcfg); route_path_is_svformat = utils_has_route_file_new_syntax(route_path); 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 new file mode 100644 index 0000000000..4df768b463 --- /dev/null +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write-empty.cexpected @@ -0,0 +1,15 @@ +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +TC_COMMIT=yes +BOOTPROTO=none +IPADDR=1.1.1.3 +PREFIX=24 +GATEWAY=1.1.1.1 +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="Test Write TC config" +UUID=${UUID} +DEVICE=eth0 +ONBOOT=yes 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 59127d0103..9d9ed62653 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 @@ -11108,6 +11108,85 @@ test_tc_read(void) g_object_unref(connection); } +static void +test_tc_write_empty(void) +{ + nmtst_auto_unlinkfile char *testfile = NULL; + gs_unref_object NMConnection *connection = NULL; + gs_unref_object NMConnection *reread = NULL; + NMSettingConnection * s_con; + NMSettingIPConfig * s_ip4; + NMSettingIPConfig * s_ip6; + NMSettingWired * s_wired; + NMSettingTCConfig * s_tc; + NMIPAddress * addr; + GError * error = NULL; + + connection = nm_simple_connection_new(); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_setting_connection_new(); + nm_connection_add_setting(connection, NM_SETTING(s_con)); + + g_object_set(s_con, + NM_SETTING_CONNECTION_ID, + "Test Write TC config", + NM_SETTING_CONNECTION_UUID, + nm_utils_uuid_generate_a(), + NM_SETTING_CONNECTION_AUTOCONNECT, + TRUE, + NM_SETTING_CONNECTION_INTERFACE_NAME, + "eth0", + NM_SETTING_CONNECTION_TYPE, + NM_SETTING_WIRED_SETTING_NAME, + NULL); + + /* Wired setting */ + s_wired = (NMSettingWired *) nm_setting_wired_new(); + nm_connection_add_setting(connection, NM_SETTING(s_wired)); + + /* IP4 setting */ + s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new(); + nm_connection_add_setting(connection, NM_SETTING(s_ip4)); + + g_object_set(s_ip4, + NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + NM_SETTING_IP_CONFIG_GATEWAY, + "1.1.1.1", + NM_SETTING_IP_CONFIG_MAY_FAIL, + TRUE, + NULL); + + addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error); + g_assert_no_error(error); + nm_setting_ip_config_add_address(s_ip4, addr); + nm_ip_address_unref(addr); + + /* IP6 setting */ + s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new(); + nm_connection_add_setting(connection, NM_SETTING(s_ip6)); + + g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); + + /* TC setting */ + s_tc = (NMSettingTCConfig *) nm_setting_tc_config_new(); + nm_connection_add_setting(connection, NM_SETTING(s_tc)); + + nm_connection_add_setting(connection, nm_setting_proxy_new()); + + nmtst_assert_connection_verifies_without_normalization(connection); + + _writer_new_connec_exp(connection, + TEST_SCRATCH_DIR, + TEST_IFCFG_DIR "/ifcfg-test-tc-write-empty.cexpected", + &testfile); + + reread = _connection_from_file(testfile, NULL, TYPE_BOND, NULL); + + nmtst_assert_connection_equals(connection, FALSE, reread, FALSE); +} + static void test_tc_write(void) { @@ -11848,6 +11927,7 @@ main(int argc, char **argv) g_test_add_func(TPATH "tc/read", test_tc_read); g_test_add_func(TPATH "tc/write", test_tc_write); + g_test_add_func(TPATH "tc/write_empty", test_tc_write_empty); g_test_add_func(TPATH "utils/test_well_known_keys", test_well_known_keys); g_test_add_func(TPATH "utils/test_utils_has_route_file_new_syntax", test_utils_has_route_file_new_syntax); diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-utils.c b/src/core/settings/plugins/keyfile/nms-keyfile-utils.c index f3dffdae49..ca1233f580 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-utils.c +++ b/src/core/settings/plugins/keyfile/nms-keyfile-utils.c @@ -137,7 +137,11 @@ nms_keyfile_nmmeta_read(const char * dirname, NMMETA_KF_GROUP_NAME_NMMETA, NMMETA_KF_KEY_NAME_NMMETA_UUID, NULL); - if (!nm_streq0(v_uuid, uuid)) + if (!v_uuid) + return FALSE; + if (strncmp(v_uuid, uuid, uuid_len) != 0) + return FALSE; + if (v_uuid[uuid_len] != '\0') return FALSE; loaded_path = g_key_file_get_string(kf, diff --git a/src/core/supplicant/nm-supplicant-config.c b/src/core/supplicant/nm-supplicant-config.c index eab494b022..bc2a692ee5 100644 --- a/src/core/supplicant/nm-supplicant-config.c +++ b/src/core/supplicant/nm-supplicant-config.c @@ -841,6 +841,11 @@ nm_supplicant_config_add_setting_wireless_security(NMSupplicantConfig * g_string_append(key_mgmt_conf, " wpa-psk-sha256"); if (_get_capability(priv, NM_SUPPL_CAP_TYPE_FT)) g_string_append(key_mgmt_conf, " ft-psk"); + if (_get_capability(priv, NM_SUPPL_CAP_TYPE_SAE)) { + g_string_append(key_mgmt_conf, " sae"); + if (_get_capability(priv, NM_SUPPL_CAP_TYPE_FT)) + g_string_append(key_mgmt_conf, " ft-sae"); + } } else if (nm_streq(key_mgmt, "wpa-eap")) { if (_get_capability(priv, NM_SUPPL_CAP_TYPE_PMF)) { g_string_append(key_mgmt_conf, " wpa-eap-sha256"); diff --git a/src/core/supplicant/nm-supplicant-interface.c b/src/core/supplicant/nm-supplicant-interface.c index 6d9c604f80..a38ebf1888 100644 --- a/src/core/supplicant/nm-supplicant-interface.c +++ b/src/core/supplicant/nm-supplicant-interface.c @@ -586,7 +586,7 @@ _bss_info_properties_changed(NMSupplicantInterface *self, if (v_v) { if (g_variant_lookup(v_v, "Type", "&s", &v_s)) { f = NM_802_11_AP_FLAGS_WPS; - if (nm_streq(v_s, "pcb")) + if (nm_streq(v_s, "pbc")) f |= NM_802_11_AP_FLAGS_WPS_PBC; else if (nm_streq(v_s, "pin")) f |= NM_802_11_AP_FLAGS_WPS_PIN; @@ -1171,19 +1171,24 @@ parse_capabilities(NMSupplicantInterface *self, GVariant *capabilities) const gboolean old_prop_scan_ssid = priv->prop_scan_ssid; const guint32 old_max_scan_ssids = priv->max_scan_ssids; gboolean have_ft = FALSE; + gboolean have_sae = FALSE; gint32 max_scan_ssids; const char ** array; nm_assert(capabilities && g_variant_is_of_type(capabilities, G_VARIANT_TYPE_VARDICT)); if (g_variant_lookup(capabilities, "KeyMgmt", "^a&s", &array)) { - have_ft = g_strv_contains(array, "wpa-ft-psk"); + have_ft = g_strv_contains(array, "wpa-ft-psk"); + have_sae = g_strv_contains(array, "sae"); g_free(array); } priv->iface_capabilities = NM_SUPPL_CAP_MASK_SET(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_FT, have_ft ? NM_TERNARY_TRUE : NM_TERNARY_FALSE); + priv->iface_capabilities = NM_SUPPL_CAP_MASK_SET(priv->iface_capabilities, + NM_SUPPL_CAP_TYPE_SAE, + have_sae ? NM_TERNARY_TRUE : NM_TERNARY_FALSE); if (g_variant_lookup(capabilities, "Modes", "^a&s", &array)) { /* Setting p2p_capable might toggle _prop_p2p_available_get(). However, @@ -1255,6 +1260,15 @@ _starting_check_ready(NMSupplicantInterface *self) return; } + _LOGD("interface supported features:" + " AP%c" + " FT%c" + " SAE%c" + "", + NM_SUPPL_CAP_TO_CHAR(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_AP), + NM_SUPPL_CAP_TO_CHAR(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_FT), + NM_SUPPL_CAP_TO_CHAR(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_SAE)); + set_state(self, priv->supp_state); } @@ -1278,6 +1292,10 @@ _get_capability(NMSupplicantInterfacePrivate *priv, NMSupplCapType type) value = iface_value; } break; + case NM_SUPPL_CAP_TYPE_SAE: + nm_assert(NM_SUPPL_CAP_MASK_GET(priv->global_capabilities, type) == NM_TERNARY_DEFAULT); + value = NM_SUPPL_CAP_MASK_GET(priv->iface_capabilities, type); + break; default: nm_assert(NM_SUPPL_CAP_MASK_GET(priv->iface_capabilities, type) == NM_TERNARY_DEFAULT); value = NM_SUPPL_CAP_MASK_GET(priv->global_capabilities, type); @@ -1305,9 +1323,13 @@ nm_supplicant_interface_get_capabilities(NMSupplicantInterface *self) caps = NM_SUPPL_CAP_MASK_SET(caps, NM_SUPPL_CAP_TYPE_FT, _get_capability(priv, NM_SUPPL_CAP_TYPE_FT)); + caps = NM_SUPPL_CAP_MASK_SET(caps, + NM_SUPPL_CAP_TYPE_SAE, + _get_capability(priv, NM_SUPPL_CAP_TYPE_SAE)); nm_assert(!NM_FLAGS_ANY(priv->iface_capabilities, - ~(NM_SUPPL_CAP_MASK_T_AP_MASK | NM_SUPPL_CAP_MASK_T_FT_MASK))); + ~(NM_SUPPL_CAP_MASK_T_AP_MASK | NM_SUPPL_CAP_MASK_T_FT_MASK + | NM_SUPPL_CAP_MASK_T_SAE_MASK))); #if NM_MORE_ASSERTS > 10 { diff --git a/src/core/supplicant/nm-supplicant-manager.c b/src/core/supplicant/nm-supplicant-manager.c index 325541876c..7cf1a2bbd1 100644 --- a/src/core/supplicant/nm-supplicant-manager.c +++ b/src/core/supplicant/nm-supplicant-manager.c @@ -168,19 +168,6 @@ _caps_set(NMSupplicantManagerPrivate *priv, NMSupplCapType type, NMTernary value priv->capabilities = NM_SUPPL_CAP_MASK_SET(priv->capabilities, type, value); } -static char -_caps_to_char(NMSupplicantManagerPrivate *priv, NMSupplCapType type) -{ - NMTernary val; - - val = NM_SUPPL_CAP_MASK_GET(priv->capabilities, type); - if (val == NM_TERNARY_TRUE) - return '+'; - if (val == NM_TERNARY_FALSE) - return '-'; - return '?'; -} - /*****************************************************************************/ static void @@ -395,7 +382,7 @@ _create_iface_complete(NMSupplMgrCreateIfaceHandle *handle, nm_clear_g_cancellable(&handle->cancellable); nm_ref_string_unref(handle->name_owner); - nm_g_slice_free_fcn(handle); + nm_g_slice_free(handle); } static void @@ -1008,15 +995,15 @@ _dbus_get_capabilities_cb(GVariant *res, GError *error, gpointer user_data) " FAST%c" " WFD%c" "", - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_AP), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_PMF), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_FILS), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_P2P), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_FT), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_SHA384), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_MESH), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_FAST), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_WFD)); + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_AP), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_PMF), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_FILS), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_P2P), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_FT), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_SHA384), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_MESH), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_FAST), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_WFD)); nm_assert(g_hash_table_size(priv->supp_ifaces) == 0); nm_assert(c_list_is_empty(&priv->supp_lst_head)); diff --git a/src/core/supplicant/nm-supplicant-types.h b/src/core/supplicant/nm-supplicant-types.h index adcf02db8b..ae2db3f6eb 100644 --- a/src/core/supplicant/nm-supplicant-types.h +++ b/src/core/supplicant/nm-supplicant-types.h @@ -41,6 +41,7 @@ typedef enum { NM_SUPPL_CAP_TYPE_FILS, NM_SUPPL_CAP_TYPE_P2P, NM_SUPPL_CAP_TYPE_FT, + NM_SUPPL_CAP_TYPE_SAE, NM_SUPPL_CAP_TYPE_SHA384, NM_SUPPL_CAP_TYPE_MESH, NM_SUPPL_CAP_TYPE_FAST, @@ -71,6 +72,7 @@ typedef enum { _NM_SUPPL_CAP_MASK_DEFINE(MESH), _NM_SUPPL_CAP_MASK_DEFINE(WFD), _NM_SUPPL_CAP_MASK_DEFINE(FT), + _NM_SUPPL_CAP_MASK_DEFINE(SAE), _NM_SUPPL_CAP_MASK_DEFINE(SHA384), #undef _NM_SUPPL_CAP_MASK_DEFINE } NMSupplCapMask; @@ -114,6 +116,19 @@ NM_SUPPL_CAP_MASK_GET(NMSupplCapMask features, NMSupplCapType type) return (NMTernary)(f - 1); } +static inline char +NM_SUPPL_CAP_TO_CHAR(NMSupplCapMask features, NMSupplCapType type) +{ + NMTernary val; + + val = NM_SUPPL_CAP_MASK_GET(features, type); + if (val == NM_TERNARY_TRUE) + return '+'; + if (val == NM_TERNARY_FALSE) + return '-'; + return '?'; +} + /*****************************************************************************/ /** diff --git a/src/core/tests/test-systemd.c b/src/core/tests/test-systemd.c index 03576c133c..fa510366f7 100644 --- a/src/core/tests/test-systemd.c +++ b/src/core/tests/test-systemd.c @@ -247,11 +247,11 @@ _test_unbase64mem_mem(const char *base64, const guint8 *expected_arr, gsize expe { gs_free char *expected_base64 = NULL; int r; - gs_free guint8 *exp2_arr = NULL; - gs_free guint8 *exp3_arr = NULL; - gsize exp2_len; - gsize exp3_len; - gsize i; + 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);
Attachment:
OpenPGP_signature
Description: OpenPGP digital signature