diff options
| author | Michael Biebl <biebl@debian.org> | 2024-01-25 09:46:18 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2024-01-25 09:46:18 +0100 |
| commit | 70e18d99b8e3e77bb37e218d7ac582130156f8ef (patch) | |
| tree | d40c587e6d3f0e094ff558e415f1bb9803643214 /src/core | |
| parent | d4d8b2b91f7ba000d97a8b2aab48c85000c11314 (diff) | |
New upstream version 1.45.90 upstream/1.45.90
Diffstat (limited to 'src/core')
91 files changed, 2626 insertions, 1010 deletions
diff --git a/src/core/NetworkManagerUtils.c b/src/core/NetworkManagerUtils.c index 8606082c..cced1717 100644 --- a/src/core/NetworkManagerUtils.c +++ b/src/core/NetworkManagerUtils.c @@ -120,7 +120,7 @@ get_new_connection_name(NMConnection *const *existing_connections, * connection id. */ temp = g_strdup_printf(C_("connection id fallback", "%s %u"), fallback_prefix, i); - if (nm_strv_find_first(existing_names, existing_len, temp) < 0) + if (!nm_strv_contains(existing_names, existing_len, temp)) return temp; g_free(temp); @@ -670,9 +670,9 @@ check_connection_cloned_mac_address(NMConnection *orig, cand_mac = nm_setting_wired_get_cloned_mac_address(s_wired_cand); /* special cloned mac address entries are accepted. */ - if (NM_CLONED_MAC_IS_SPECIAL(orig_mac)) + if (NM_CLONED_MAC_IS_SPECIAL(orig_mac, FALSE)) orig_mac = NULL; - if (NM_CLONED_MAC_IS_SPECIAL(cand_mac)) + if (NM_CLONED_MAC_IS_SPECIAL(cand_mac, FALSE)) cand_mac = NULL; if (!orig_mac || !cand_mac) { @@ -695,7 +695,8 @@ check_connection_controller(NMConnection *orig, NMConnection *candidate, GHashTa props = check_property_in_hash(settings, NM_SETTING_CONNECTION_SETTING_NAME, - NM_SETTING_CONNECTION_MASTER); + NM_SETTING_CONNECTION_CONTROLLER); + if (!props) return TRUE; @@ -722,6 +723,10 @@ check_connection_controller(NMConnection *orig, NMConnection *candidate, GHashTa props, NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_MASTER); + remove_from_hash(settings, + props, + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_CONTROLLER); return TRUE; } else { return FALSE; @@ -892,8 +897,8 @@ nm_utils_match_connection(NMConnection *const *connections, if (!nm_streq0(nm_setting_connection_get_connection_type(s_orig), nm_setting_connection_get_connection_type(s_cand))) continue; - if (!nm_streq0(nm_setting_connection_get_slave_type(s_orig), - nm_setting_connection_get_slave_type(s_cand))) + if (!nm_streq0(nm_setting_connection_get_port_type(s_orig), + nm_setting_connection_get_port_type(s_cand))) continue; /* this is good enough for a match */ @@ -1558,7 +1563,8 @@ nm_utils_ip_addresses_to_dbus(int addr_family, char addr_str[NM_INET_ADDRSTRLEN]; NMDedupMultiIter iter; const NMPObject *obj; - guint i; + const gsize MAX_ADDRESSES = 100; + gsize i; nm_assert_addr_family(addr_family); @@ -1580,6 +1586,11 @@ nm_utils_ip_addresses_to_dbus(int addr_family, nm_platform_dedup_multi_iter_next_obj(&iter, &obj, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4))) { const NMPlatformIPXAddress *address = NMP_OBJECT_CAST_IPX_ADDRESS(obj); + if (i > MAX_ADDRESSES) { + /* Limited. The rest is hidden. */ + break; + } + if (out_address_data) { GVariantBuilder addr_builder; gconstpointer p; @@ -1669,6 +1680,8 @@ nm_utils_ip_routes_to_dbus(int addr_family, GVariantBuilder builder_data; GVariantBuilder builder_legacy; char addr_str[NM_INET_ADDRSTRLEN]; + const gsize MAX_ROUTES = 100; + gsize i; nm_assert_addr_family(addr_family); @@ -1681,6 +1694,7 @@ nm_utils_ip_routes_to_dbus(int addr_family, g_variant_builder_init(&builder_legacy, G_VARIANT_TYPE("a(ayuayu)")); } + i = 0; nm_dedup_multi_iter_init(&iter, head_entry); while (nm_platform_dedup_multi_iter_next_obj(&iter, &obj, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4))) { const NMPlatformIPXRoute *r = NMP_OBJECT_CAST_IPX_ROUTE(obj); @@ -1699,6 +1713,13 @@ nm_utils_ip_routes_to_dbus(int addr_family, if (r->rx.type_coerced != nm_platform_route_type_coerce(RTN_UNICAST)) continue; + if (i >= MAX_ROUTES) { + /* Limited. The rest is hidden. */ + break; + } + + i++; + if (out_route_data) { GVariantBuilder route_builder; gconstpointer gateway; diff --git a/src/core/devices/adsl/nm-device-adsl.c b/src/core/devices/adsl/nm-device-adsl.c index 89bc84d8..ba605077 100644 --- a/src/core/devices/adsl/nm-device-adsl.c +++ b/src/core/devices/adsl/nm-device-adsl.c @@ -683,7 +683,11 @@ static const NMDBusInterfaceInfoExtended interface_info_device_adsl = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_ADSL, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Carrier", "b", NM_DEVICE_CARRIER), ), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Carrier", + "b", + NM_DEVICE_CARRIER, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), ), ), }; static void diff --git a/src/core/devices/bluetooth/nm-device-bt.c b/src/core/devices/bluetooth/nm-device-bt.c index 8b13e97d..ce110aa0 100644 --- a/src/core/devices/bluetooth/nm-device-bt.c +++ b/src/core/devices/bluetooth/nm-device-bt.c @@ -1306,7 +1306,11 @@ static const NMDBusInterfaceInfoExtended interface_info_device_bluetooth = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_BLUETOOTH, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Name", "s", NM_DEVICE_BT_NAME), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("BtCapabilities", "u", diff --git a/src/core/devices/nm-device-6lowpan.c b/src/core/devices/nm-device-6lowpan.c index f3386ddb..78ec634c 100644 --- a/src/core/devices/nm-device-6lowpan.c +++ b/src/core/devices/nm-device-6lowpan.c @@ -212,7 +212,11 @@ static const NMDBusInterfaceInfoExtended interface_info_device_6lowpan = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_6LOWPAN, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Parent", "o", NM_DEVICE_PARENT), ), ), }; diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 10fe8092..a3467930 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -248,9 +248,9 @@ controller_update_port_connection(NMDevice *self, NULL); g_object_set(nm_connection_get_setting_connection(connection), - NM_SETTING_CONNECTION_MASTER, + NM_SETTING_CONNECTION_CONTROLLER, nm_connection_get_uuid(applied_connection), - NM_SETTING_CONNECTION_SLAVE_TYPE, + NM_SETTING_CONNECTION_PORT_TYPE, NM_SETTING_BOND_SETTING_NAME, NULL); return TRUE; @@ -292,7 +292,7 @@ set_arp_targets(NMDevice *device, const char *cur_arp_ip_target, const char *new } } - if (nm_strv_find_first(new_strv, i, s) < 0) + if (!nm_strv_contains(new_strv, i, s)) new_strv[j++] = s; } new_strv[j] = NULL; @@ -683,6 +683,7 @@ commit_port_options(NMDevice *bond_device, NMDevice *port, NMSettingBondPort *s_ .prio = prio_has ? prio : 0, .prio_has = prio_has, }), + NULL, 0); } @@ -928,9 +929,21 @@ static const NMDBusInterfaceInfoExtended interface_info_device_bond = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_BOND, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), ), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Carrier", + "b", + NM_DEVICE_CARRIER, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Slaves", + "ao", + NM_DEVICE_SLAVES, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), ), ), }; static void diff --git a/src/core/devices/nm-device-bridge.c b/src/core/devices/nm-device-bridge.c index 9a45dbf3..193b655c 100644 --- a/src/core/devices/nm-device-bridge.c +++ b/src/core/devices/nm-device-bridge.c @@ -421,22 +421,6 @@ static const Option master_options[] = { 0, }}; -static const Option slave_options[] = { - OPTION(NM_SETTING_BRIDGE_PORT_PRIORITY, - "priority", - OPTION_TYPE_INT(NM_BRIDGE_PORT_PRIORITY_MIN, - NM_BRIDGE_PORT_PRIORITY_MAX, - NM_BRIDGE_PORT_PRIORITY_DEF), - .default_if_zero = TRUE, ), - OPTION(NM_SETTING_BRIDGE_PORT_PATH_COST, - "path_cost", - OPTION_TYPE_INT(NM_BRIDGE_PORT_PATH_COST_MIN, - NM_BRIDGE_PORT_PATH_COST_MAX, - NM_BRIDGE_PORT_PATH_COST_DEF), - .default_if_zero = TRUE, ), - OPTION(NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "hairpin_mode", OPTION_TYPE_BOOL(FALSE), ), - {0}}; - static const NMPlatformBridgeVlan ** setting_vlans_to_platform(GPtrArray *array) { @@ -473,90 +457,26 @@ setting_vlans_to_platform(GPtrArray *array) static void commit_port_options(NMDevice *device, NMSettingBridgePort *setting) { - const Option *option; - NMSetting *s; - gs_unref_object NMSetting *s_clear = NULL; - int ifindex = nm_device_get_ifindex(device); - - if (setting) - s = NM_SETTING(setting); - else - s = s_clear = nm_setting_bridge_port_new(); - - for (option = slave_options; option->name; option++) { - nm_auto_unset_gvalue GValue val = G_VALUE_INIT; - GParamSpec *pspec; - const char *value; - char value_buf[100]; - - pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(s), option->name); - nm_assert(pspec); - - g_value_init(&val, G_PARAM_SPEC_VALUE_TYPE(pspec)); - g_object_get_property((GObject *) s, option->name, &val); - - if (option->to_sysfs) { - value = option->to_sysfs(&val); - goto out; - } - - switch (pspec->value_type) { - case G_TYPE_BOOLEAN: - value = g_value_get_boolean(&val) ? "1" : "0"; - break; - case G_TYPE_UINT64: - case G_TYPE_UINT: - { - guint64 uval; - - if (pspec->value_type == G_TYPE_UINT64) - uval = g_value_get_uint64(&val); - else - uval = (guint) g_value_get_uint(&val); - - /* zero means "unspecified" for some NM properties but isn't in the - * allowed kernel range, so reset the property to the default value. - */ - if (option->default_if_zero && uval == 0) { - if (pspec->value_type == G_TYPE_UINT64) - uval = NM_G_PARAM_SPEC_GET_DEFAULT_UINT64(pspec); - else - uval = NM_G_PARAM_SPEC_GET_DEFAULT_UINT(pspec); - } - - /* Linux kernel bridge interfaces use 'centiseconds' for time-based values. - * In reality it's not centiseconds, but depends on HZ and USER_HZ, which - * is almost always works out to be a multiplier of 100, so we can assume - * centiseconds. See clock_t_to_jiffies(). - */ - if (option->user_hz_compensate) - uval *= 100; - - if (pspec->value_type == G_TYPE_UINT64) - nm_sprintf_buf(value_buf, "%" G_GUINT64_FORMAT, uval); - else - nm_sprintf_buf(value_buf, "%u", (guint) uval); - - value = value_buf; - } break; - case G_TYPE_STRING: - value = g_value_get_string(&val); - break; - default: - nm_assert_not_reached(); - value = NULL; - break; - } - -out: - if (!value) - return; - - nm_platform_sysctl_slave_set_option(nm_device_get_platform(device), - ifindex, - option->sysname, - value); - } + guint32 path_cost, priority; + + path_cost = nm_setting_bridge_port_get_path_cost(setting); + if (path_cost == 0) + path_cost = NM_BRIDGE_PORT_PATH_COST_DEF; + + priority = nm_setting_bridge_port_get_priority(setting); + if (priority == 0) + priority = NM_BRIDGE_PORT_PRIORITY_DEF; + + nm_platform_link_change(nm_device_get_platform(device), + nm_device_get_ifindex(device), + NULL, + NULL, + &((NMPlatformLinkBridgePort){ + .path_cost = path_cost, + .priority = priority, + .hairpin = nm_setting_bridge_port_get_hairpin_mode(setting), + }), + 0); } static void @@ -662,50 +582,37 @@ master_update_slave_connection(NMDevice *device, NMConnection *connection, GError **error) { - NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); - NMSettingConnection *s_con; - NMSettingBridgePort *s_port; - int ifindex_slave = nm_device_get_ifindex(slave); - NMConnection *applied_connection = nm_device_get_applied_connection(device); - - const Option *option; + NMSettingConnection *s_con; + NMSettingBridgePort *s_port; + int ifindex_slave = nm_device_get_ifindex(slave); + NMConnection *applied_connection = nm_device_get_applied_connection(device); + const NMPlatformLink *pllink; g_return_val_if_fail(ifindex_slave > 0, FALSE); s_con = nm_connection_get_setting_connection(connection); s_port = _nm_connection_ensure_setting(connection, NM_TYPE_SETTING_BRIDGE_PORT); - - for (option = slave_options; option->name; option++) { - gs_free char *str = nm_platform_sysctl_slave_get_option(nm_device_get_platform(device), - ifindex_slave, - option->sysname); - uint value; - - if (str) { - /* See comments in set_sysfs_uint() about centiseconds. */ - if (option->user_hz_compensate) { - value = _nm_utils_ascii_str_to_int64(str, - 10, - option->nm_min * 100, - option->nm_max * 100, - option->nm_default * 100); - value /= 100; - } else { - value = _nm_utils_ascii_str_to_int64(str, - 10, - option->nm_min, - option->nm_max, - option->nm_default); - } - g_object_set(s_port, option->name, value, NULL); - } else - _LOGW(LOGD_BRIDGE, "failed to read bridge port setting '%s'", option->sysname); + pllink = nm_platform_link_get(nm_device_get_platform(slave), ifindex_slave); + + if (pllink && pllink->port_kind == NM_PORT_KIND_BRIDGE) { + g_object_set(s_port, + NM_SETTING_BRIDGE_PORT_PATH_COST, + pllink->port_data.bridge.path_cost, + NULL); + g_object_set(s_port, + NM_SETTING_BRIDGE_PORT_PRIORITY, + pllink->port_data.bridge.priority, + NULL); + g_object_set(s_port, + NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, + pllink->port_data.bridge.hairpin, + NULL); } g_object_set(s_con, - NM_SETTING_CONNECTION_MASTER, + NM_SETTING_CONNECTION_CONTROLLER, nm_connection_get_uuid(applied_connection), - NM_SETTING_CONNECTION_SLAVE_TYPE, + NM_SETTING_CONNECTION_PORT_TYPE, NM_SETTING_BRIDGE_SETTING_NAME, NULL); return TRUE; @@ -1234,9 +1141,21 @@ static const NMDBusInterfaceInfoExtended interface_info_device_bridge = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_BRIDGE, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), ), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Carrier", + "b", + NM_DEVICE_CARRIER, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Slaves", + "ao", + NM_DEVICE_SLAVES, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), ), ), }; static void diff --git a/src/core/devices/nm-device-dummy.c b/src/core/devices/nm-device-dummy.c index 36a0ee6f..b7c4106a 100644 --- a/src/core/devices/nm-device-dummy.c +++ b/src/core/devices/nm-device-dummy.c @@ -107,9 +107,11 @@ static const NMDBusInterfaceInfoExtended interface_info_device_dummy = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_DUMMY, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), ), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), ), ), }; static void diff --git a/src/core/devices/nm-device-ethernet.c b/src/core/devices/nm-device-ethernet.c index aedacc24..0f7f9d65 100644 --- a/src/core/devices/nm-device-ethernet.c +++ b/src/core/devices/nm-device-ethernet.c @@ -1431,7 +1431,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) mtu = nm_setting_ppp_get_mtu(s_ppp); mru = nm_setting_ppp_get_mru(s_ppp); - mxu = MAX(mru, mtu); + mxu = NM_MAX(mru, mtu); if (mxu) { _LOGD(LOGD_PPP, "set MTU to %u (PPP interface MRU %u, MTU %u)", @@ -1711,10 +1711,8 @@ new_default_connection(NMDevice *self) NMSettingsConnection *const *connections; NMSetting *setting; gs_unref_hashtable GHashTable *existing_ids = NULL; - struct udev_device *dev; const char *perm_hw_addr; const char *iface; - const char *uprop = "0"; gs_free char *defname = NULL; gs_free char *uuid = NULL; guint i, n_connections; @@ -1760,30 +1758,6 @@ new_default_connection(NMDevice *self) iface, NULL); - /* Check if we should create a Link-Local only connection */ - dev = nm_platform_link_get_udev_device(nm_device_get_platform(NM_DEVICE(self)), - nm_device_get_ip_ifindex(self)); - if (dev) - uprop = udev_device_get_property_value(dev, "NM_AUTO_DEFAULT_LINK_LOCAL_ONLY"); - - if (_nm_utils_ascii_str_to_bool(uprop, FALSE)) { - setting = nm_setting_ip4_config_new(); - g_object_set(setting, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL, - NULL); - nm_connection_add_setting(connection, setting); - - setting = nm_setting_ip6_config_new(); - g_object_set(setting, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL, - NM_SETTING_IP_CONFIG_MAY_FAIL, - TRUE, - NULL); - nm_connection_add_setting(connection, setting); - } - return connection; } @@ -2043,14 +2017,20 @@ static const NMDBusInterfaceInfoExtended interface_info_device_wired = { NM_DBUS_INTERFACE_DEVICE_WIRED, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("PermHwAddress", - "s", - NM_DEVICE_PERM_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "PermHwAddress", + "s", + NM_DEVICE_PERM_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Speed", "u", NM_DEVICE_ETHERNET_SPEED), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("S390Subchannels", "as", NM_DEVICE_ETHERNET_S390_SUBCHANNELS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Carrier", "b", NM_DEVICE_CARRIER), ), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Carrier", + "b", + NM_DEVICE_CARRIER, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), ), ), }; static void diff --git a/src/core/devices/nm-device-factory.c b/src/core/devices/nm-device-factory.c index 2f0ae2e8..c97fbb57 100644 --- a/src/core/devices/nm-device-factory.c +++ b/src/core/devices/nm-device-factory.c @@ -396,6 +396,7 @@ nm_device_factory_manager_load_factories(NMDeviceFactoryManagerFactoryFunc callb _ADD_INTERNAL(nm_bridge_device_factory_get_type); _ADD_INTERNAL(nm_dummy_device_factory_get_type); _ADD_INTERNAL(nm_ethernet_device_factory_get_type); + _ADD_INTERNAL(nm_hsr_device_factory_get_type); _ADD_INTERNAL(nm_infiniband_device_factory_get_type); _ADD_INTERNAL(nm_ip_tunnel_device_factory_get_type); _ADD_INTERNAL(nm_loopback_device_factory_get_type); diff --git a/src/core/devices/nm-device-generic.c b/src/core/devices/nm-device-generic.c index c0dcf0de..ead671d4 100644 --- a/src/core/devices/nm-device-generic.c +++ b/src/core/devices/nm-device-generic.c @@ -168,7 +168,11 @@ static const NMDBusInterfaceInfoExtended interface_info_device_generic = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_GENERIC, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( "TypeDescription", "s", diff --git a/src/core/devices/nm-device-hsr.c b/src/core/devices/nm-device-hsr.c new file mode 100644 index 00000000..8156fa77 --- /dev/null +++ b/src/core/devices/nm-device-hsr.c @@ -0,0 +1,287 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023 Red Hat, Inc. + */ + +#include "src/core/nm-default-daemon.h" + +#include "nm-manager.h" +#include "nm-device-hsr.h" + +#include <linux/if_ether.h> + +#include "libnm-core-intern/nm-core-internal.h" +#include "nm-act-request.h" +#include "nm-device-private.h" +#include "nm-setting-hsr.h" +#include "libnm-platform/nm-platform.h" +#include "nm-device-factory.h" + +#define _NMLOG_DEVICE_TYPE NMDeviceHsr +#include "nm-device-logging.h" + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceHsr, + PROP_PORT1, + PROP_PORT2, + PROP_SUPERVISION_ADDRESS, + PROP_MULTICAST_SPEC, + PROP_PRP, ); + +typedef struct { + NMPlatformLnkHsr props; +} NMDeviceHsrPrivate; + +struct _NMDeviceHsr { + NMDevice parent; + NMDeviceHsrPrivate _priv; +}; + +struct _NMDeviceHsrClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE(NMDeviceHsr, nm_device_hsr, NM_TYPE_DEVICE) + +#define NM_DEVICE_HSR_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMDeviceHsr, NM_IS_DEVICE_HSR, NMDevice) + +/*****************************************************************************/ + +static NMDeviceCapabilities +get_generic_capabilities(NMDevice *dev) +{ + return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; +} + +static void +update_properties(NMDevice *device) +{ + NMDeviceHsr *self; + NMDeviceHsrPrivate *priv; + const NMPlatformLink *plink; + const NMPlatformLnkHsr *props; + int ifindex; + + g_return_if_fail(NM_IS_DEVICE_HSR(device)); + self = NM_DEVICE_HSR(device); + priv = NM_DEVICE_HSR_GET_PRIVATE(self); + + ifindex = nm_device_get_ifindex(device); + g_return_if_fail(ifindex > 0); + props = nm_platform_link_get_lnk_hsr(nm_device_get_platform(device), ifindex, &plink); + + if (!props) { + _LOGW(LOGD_PLATFORM, "could not get HSR properties"); + return; + } + + g_object_freeze_notify((GObject *) device); + +#define CHECK_PROPERTY_CHANGED(field, prop) \ + G_STMT_START \ + { \ + if (priv->props.field != props->field) { \ + priv->props.field = props->field; \ + _notify(self, prop); \ + } \ + } \ + G_STMT_END + + CHECK_PROPERTY_CHANGED(port1, PROP_PORT1); + CHECK_PROPERTY_CHANGED(port2, PROP_PORT2); + CHECK_PROPERTY_CHANGED(multicast_spec, PROP_MULTICAST_SPEC); + CHECK_PROPERTY_CHANGED(prp, PROP_PRP); + + if (!nm_ether_addr_equal(&priv->props.supervision_address, &props->supervision_address)) + _notify(self, PROP_SUPERVISION_ADDRESS); + + g_object_thaw_notify((GObject *) device); +} + +static void +link_changed(NMDevice *device, const NMPlatformLink *pllink) +{ + NM_DEVICE_CLASS(nm_device_hsr_parent_class)->link_changed(device, pllink); + update_properties(device); +} + +static gboolean +create_and_realize(NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + const char *iface = nm_device_get_iface(device); + NMSettingHsr *s_hsr; + NMPlatformLnkHsr lnk = {}; + int r; + + s_hsr = _nm_connection_get_setting(connection, NM_TYPE_SETTING_HSR); + nm_assert(s_hsr); + + if (nm_setting_hsr_get_port1(s_hsr) != NULL) + lnk.port1 = nm_platform_link_get_ifindex(NM_PLATFORM_GET, nm_setting_hsr_get_port1(s_hsr)); + if (nm_setting_hsr_get_port2(s_hsr) != NULL) + lnk.port2 = nm_platform_link_get_ifindex(NM_PLATFORM_GET, nm_setting_hsr_get_port2(s_hsr)); + lnk.multicast_spec = nm_setting_hsr_get_multicast_spec(s_hsr); + lnk.prp = nm_setting_hsr_get_prp(s_hsr); + r = nm_platform_link_hsr_add(nm_device_get_platform(device), iface, &lnk, out_plink); + if (r < 0) { + g_set_error(error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create HSR interface '%s' for '%s': %s", + iface, + nm_connection_get_id(connection), + nm_strerror(r)); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +static void +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMDeviceHsr *self = NM_DEVICE_HSR(object); + NMDeviceHsrPrivate *priv = NM_DEVICE_HSR_GET_PRIVATE(self); + NMDevice *port; + + switch (prop_id) { + case PROP_PORT1: + port = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, priv->props.port1); + nm_dbus_utils_g_value_set_object_path(value, port); + break; + case PROP_PORT2: + port = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, priv->props.port2); + nm_dbus_utils_g_value_set_object_path(value, port); + break; + case PROP_SUPERVISION_ADDRESS: + g_value_take_string(value, nm_ether_addr_to_string_dup(&priv->props.supervision_address)); + break; + case PROP_MULTICAST_SPEC: + g_value_set_uchar(value, priv->props.multicast_spec); + break; + case PROP_PRP: + g_value_set_boolean(value, priv->props.prp); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +nm_device_hsr_init(NMDeviceHsr *self) +{} + +/*****************************************************************************/ + +static const NMDBusInterfaceInfoExtended interface_info_device_hsr = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( + NM_DBUS_INTERFACE_DEVICE_HSR, + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Port1", "o", NM_DEVICE_HSR_PORT1), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Port2", "o", NM_DEVICE_HSR_PORT2), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("SupervisionAddress", + "s", + NM_DEVICE_HSR_SUPERVISION_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("MulticastSpec", + "y", + NM_DEVICE_HSR_MULTICAST_SPEC), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Prp", "b", NM_DEVICE_HSR_PRP), ), ), +}; + +static void +nm_device_hsr_class_init(NMDeviceHsrClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS(klass); + + object_class->get_property = get_property; + + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_hsr); + + device_class->connection_type_supported = NM_SETTING_HSR_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_HSR_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_HSR); + + device_class->link_changed = link_changed; + device_class->create_and_realize = create_and_realize; + device_class->get_generic_capabilities = get_generic_capabilities; + + obj_properties[PROP_PORT1] = g_param_spec_string(NM_DEVICE_HSR_PORT1, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_PORT2] = g_param_spec_string(NM_DEVICE_HSR_PORT2, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_SUPERVISION_ADDRESS] = + g_param_spec_string(NM_DEVICE_HSR_SUPERVISION_ADDRESS, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_MULTICAST_SPEC] = + g_param_spec_uchar(NM_DEVICE_HSR_MULTICAST_SPEC, + "", + "", + 0, + G_MAXUINT8, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_PRP] = g_param_spec_boolean(NM_DEVICE_HSR_PRP, + "", + "", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); +} + +/*****************************************************************************/ + +#define NM_TYPE_HSR_DEVICE_FACTORY (nm_hsr_device_factory_get_type()) +#define NM_HSR_DEVICE_FACTORY(obj) \ + (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_HSR_DEVICE_FACTORY, NMHsrDeviceFactory)) + +static NMDevice * +create_device(NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + return g_object_new(NM_TYPE_DEVICE_HSR, + NM_DEVICE_IFACE, + iface, + NM_DEVICE_TYPE_DESC, + "hsr", + NM_DEVICE_DEVICE_TYPE, + NM_DEVICE_TYPE_HSR, + NM_DEVICE_LINK_TYPE, + NM_LINK_TYPE_HSR, + NULL); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL( + HSR, + Hsr, + hsr, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_HSR) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_HSR_SETTING_NAME), + factory_class->create_device = create_device;) diff --git a/src/core/devices/nm-device-hsr.h b/src/core/devices/nm-device-hsr.h new file mode 100644 index 00000000..1da90358 --- /dev/null +++ b/src/core/devices/nm-device-hsr.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2023 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DEVICE_HSR_H__ +#define __NETWORKMANAGER_DEVICE_HSR_H__ + +#include "nm-device.h" + +#define NM_TYPE_DEVICE_HSR (nm_device_hsr_get_type()) +#define NM_DEVICE_HSR(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_HSR, NMDeviceHsr)) +#define NM_DEVICE_HSR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_HSR, NMDeviceHsrClass)) +#define NM_IS_DEVICE_HSR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_HSR)) +#define NM_IS_DEVICE_HSR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_HSR)) +#define NM_DEVICE_HSR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_HSR, NMDeviceHsrClass)) + +#define NM_DEVICE_HSR_PORT1 "port1" +#define NM_DEVICE_HSR_PORT2 "port2" +#define NM_DEVICE_HSR_SUPERVISION_ADDRESS "supervision-address" +#define NM_DEVICE_HSR_MULTICAST_SPEC "multicast-spec" +#define NM_DEVICE_HSR_PRP "prp" + +typedef struct _NMDeviceHsr NMDeviceHsr; +typedef struct _NMDeviceHsrClass NMDeviceHsrClass; + +GType nm_device_hsr_get_type(void); + +#endif /* __NETWORKMANAGER_DEVICE_HSR_H__ */ diff --git a/src/core/devices/nm-device-infiniband.c b/src/core/devices/nm-device-infiniband.c index 6ce61d0b..c974696c 100644 --- a/src/core/devices/nm-device-infiniband.c +++ b/src/core/devices/nm-device-infiniband.c @@ -362,8 +362,16 @@ static const NMDBusInterfaceInfoExtended interface_info_device_infiniband = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_INFINIBAND, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Carrier", "b", NM_DEVICE_CARRIER), ), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Carrier", + "b", + NM_DEVICE_CARRIER, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), ), ), }; static void diff --git a/src/core/devices/nm-device-tun.c b/src/core/devices/nm-device-tun.c index 430e62aa..28b03cec 100644 --- a/src/core/devices/nm-device-tun.c +++ b/src/core/devices/nm-device-tun.c @@ -452,9 +452,11 @@ static const NMDBusInterfaceInfoExtended interface_info_device_tun = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("MultiQueue", "b", NM_DEVICE_TUN_MULTI_QUEUE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), ), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), ), ), }; static void diff --git a/src/core/devices/nm-device-vlan.c b/src/core/devices/nm-device-vlan.c index 7849e724..cc649ec9 100644 --- a/src/core/devices/nm-device-vlan.c +++ b/src/core/devices/nm-device-vlan.c @@ -525,8 +525,16 @@ static const NMDBusInterfaceInfoExtended interface_info_device_vlan = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_VLAN, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Carrier", "b", NM_DEVICE_CARRIER), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Carrier", + "b", + NM_DEVICE_CARRIER, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Parent", "o", NM_DEVICE_PARENT), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("VlanId", "u", NM_DEVICE_VLAN_ID), ), ), }; diff --git a/src/core/devices/nm-device-vxlan.c b/src/core/devices/nm-device-vxlan.c index 061ee3f2..6a23d51e 100644 --- a/src/core/devices/nm-device-vxlan.c +++ b/src/core/devices/nm-device-vxlan.c @@ -576,7 +576,11 @@ static const NMDBusInterfaceInfoExtended interface_info_device_vxlan = { NM_DBUS_INTERFACE_DEVICE_VXLAN, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Id", "u", NM_DEVICE_VXLAN_ID), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Group", "s", NM_DEVICE_VXLAN_GROUP), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Local", "s", NM_DEVICE_VXLAN_LOCAL), diff --git a/src/core/devices/nm-device-wireguard.c b/src/core/devices/nm-device-wireguard.c index db02033d..dd40d11e 100644 --- a/src/core/devices/nm-device-wireguard.c +++ b/src/core/devices/nm-device-wireguard.c @@ -598,7 +598,7 @@ _peers_add(NMDeviceWireGuard *self, NMWireGuardPeer *peer) }; c_list_link_tail(&priv->lst_peers_head, &peer_data->lst_peers); - if (!nm_g_hash_table_add(priv->peers, peer_data)) + if (!g_hash_table_add(priv->peers, peer_data)) nm_assert_not_reached(); return peer_data; } @@ -720,7 +720,7 @@ _peers_retry_in_msec(PeerData *peer_data, gboolean after_failure) return RETRY_IN_MSEC_MAX; /* double the retry-time, starting with one second. */ - return NM_MIN(RETRY_IN_MSEC_MAX, (1u << peer_data->ep_resolv.resolv_fail_count) * 500); + return NM_MIN(RETRY_IN_MSEC_MAX, (1l << peer_data->ep_resolv.resolv_fail_count) * 500); } static void diff --git a/src/core/devices/nm-device-wpan.c b/src/core/devices/nm-device-wpan.c index 282eea87..7885355d 100644 --- a/src/core/devices/nm-device-wpan.c +++ b/src/core/devices/nm-device-wpan.c @@ -197,9 +197,11 @@ static const NMDBusInterfaceInfoExtended interface_info_device_wpan = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_WPAN, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), ), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), ), ), }; static void diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index d1212560..16f8e1f2 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -22,6 +22,7 @@ #include <linux/rtnetlink.h> #include <linux/if_ether.h> #include <linux/if_infiniband.h> +#include <libudev.h> #include "libnm-std-aux/unaligned.h" #include "libnm-glib-aux/nm-uuid.h" @@ -303,6 +304,8 @@ typedef struct { NMEthtoolCoalesceState *coalesce; NMEthtoolRingState *ring; NMEthtoolPauseState *pause; + NMEthtoolChannelsState *channels; + NMEthtoolEEEState *eee; } EthtoolState; typedef enum { @@ -1030,12 +1033,14 @@ _prop_get_connection_stable_id(NMDevice *self, gs_free char *generated = NULL; NMUtilsStableType stable_type; NMSettingConnection *s_con; + NMSettingWireless *s_wifi; gboolean hwaddr_is_fake; const char *hwaddr; const char *stable_id; const char *uuid; - s_con = nm_connection_get_setting_connection(connection); + s_con = nm_connection_get_setting_connection(connection); + s_wifi = nm_connection_get_setting_wireless(connection); stable_id = nm_setting_connection_get_stable_id(s_con); @@ -1058,6 +1063,7 @@ _prop_get_connection_stable_id(NMDevice *self, !hwaddr_is_fake ? hwaddr : NULL, nm_utils_boot_id_str(), uuid, + s_wifi ? nm_setting_wireless_get_ssid(s_wifi) : NULL, &generated); /* current_stable_id_type is a bitfield! */ @@ -1517,7 +1523,7 @@ _prop_get_ipvx_route_table(NMDevice *self, int addr_family) if (route_table == 0u && connection && (s_con = nm_connection_get_setting_connection(connection)) - && (nm_streq0(nm_setting_connection_get_slave_type(s_con), NM_SETTING_VRF_SETTING_NAME) + && (nm_streq0(nm_setting_connection_get_port_type(s_con), NM_SETTING_VRF_SETTING_NAME) && priv->master && nm_device_get_device_type(priv->master) == NM_DEVICE_TYPE_VRF)) { const NMPlatformLnkVrf *lnk; @@ -1655,7 +1661,7 @@ _prop_get_ipv4_dad_timeout(NMDevice *self) self, 0, NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, - 0); + 200); } static guint32 @@ -2017,7 +2023,10 @@ _prop_get_connection_mud_url(NMDevice *self, NMSettingConnection *s_con) } static GBytes * -_prop_get_ipv4_dhcp_client_id(NMDevice *self, NMConnection *connection, GBytes *hwaddr) +_prop_get_ipv4_dhcp_client_id(NMDevice *self, + NMConnection *connection, + GBytes *hwaddr, + gboolean *out_send_client_id) { NMSettingIPConfig *s_ip4; const char *client_id; @@ -2030,6 +2039,8 @@ _prop_get_ipv4_dhcp_client_id(NMDevice *self, NMConnection *connection, GBytes * GBytes *result; gs_free char *logstr1 = NULL; + NM_SET_OUT(out_send_client_id, TRUE); + s_ip4 = nm_connection_get_setting_ip4_config(connection); client_id = nm_setting_ip4_config_get_dhcp_client_id(NM_SETTING_IP4_CONFIG(s_ip4)); @@ -2049,6 +2060,12 @@ _prop_get_ipv4_dhcp_client_id(NMDevice *self, NMConnection *connection, GBytes * return NULL; } + if (nm_streq(client_id, "none")) { + _LOGD(LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, "ipv4.dhcp-client-id: set to \"none\""); + NM_SET_OUT(out_send_client_id, FALSE); + return NULL; + } + if (nm_streq(client_id, "mac")) { if (!hwaddr) { fail_reason = "missing link-layer address"; @@ -2335,7 +2352,7 @@ _prop_get_x_cloned_mac_address(NMDevice *self, NMConnection *connection, gboolea if (v == NM_SETTING_MAC_RANDOMIZATION_ALWAYS) addr = NM_CLONED_MAC_RANDOM; } - } else if (NM_CLONED_MAC_IS_SPECIAL(a) || nm_utils_hwaddr_valid(a, ETH_ALEN)) + } else if (NM_CLONED_MAC_IS_SPECIAL(a, is_wifi) || nm_utils_hwaddr_valid(a, ETH_ALEN)) addr = a; } @@ -2374,6 +2391,8 @@ _ethtool_features_reset(NMDevice *self, NMPlatform *platform, EthtoolState *etht gs_free NMEthtoolFeatureStates *features = NULL; features = g_steal_pointer(ðtool_state->features); + if (!features) + return; if (!nm_platform_ethtool_set_features(platform, ethtool_state->ifindex, @@ -2393,8 +2412,7 @@ _ethtool_features_set(NMDevice *self, { gs_free NMEthtoolFeatureStates *features = NULL; - if (ethtool_state->features) - _ethtool_features_reset(self, platform, ethtool_state); + _ethtool_features_reset(self, platform, ethtool_state); if (nm_setting_ethtool_init_features(s_ethtool, ethtool_state->requested) == 0) return; @@ -2592,6 +2610,104 @@ _ethtool_ring_set(NMDevice *self, } static void +_ethtool_channels_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) +{ + gs_free NMEthtoolChannelsState *channels = NULL; + + nm_assert(NM_IS_DEVICE(self)); + nm_assert(NM_IS_PLATFORM(platform)); + nm_assert(ethtool_state); + + channels = g_steal_pointer(ðtool_state->channels); + if (!channels) + return; + + if (!nm_platform_ethtool_set_channels(platform, ethtool_state->ifindex, channels)) + _LOGW(LOGD_DEVICE, "ethtool: failure resetting one or more channels settings"); + else + _LOGD(LOGD_DEVICE, "ethtool: channels settings successfully reset"); +} + +static void +_ethtool_channels_set(NMDevice *self, + NMPlatform *platform, + EthtoolState *ethtool_state, + NMSettingEthtool *s_ethtool) +{ + NMEthtoolChannelsState channels_old; + NMEthtoolChannelsState channels_new; + GHashTable *hash; + GHashTableIter iter; + const char *name; + GVariant *variant; + gboolean has_old = FALSE; + + nm_assert(NM_IS_DEVICE(self)); + nm_assert(NM_IS_PLATFORM(platform)); + nm_assert(NM_IS_SETTING_ETHTOOL(s_ethtool)); + nm_assert(ethtool_state); + nm_assert(!ethtool_state->channels); + + hash = _nm_setting_option_hash(NM_SETTING(s_ethtool), FALSE); + if (!hash) + return; + + g_hash_table_iter_init(&iter, hash); + while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &variant)) { + NMEthtoolID ethtool_id = nm_ethtool_id_get_by_name(name); + guint32 u32; + + if (!nm_ethtool_id_is_channels(ethtool_id)) + continue; + + nm_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT32)); + + if (!has_old) { + if (!nm_platform_ethtool_get_link_channels(platform, + ethtool_state->ifindex, + &channels_old)) { + _LOGW(LOGD_DEVICE, + "ethtool: failure setting channels options (cannot read existing setting)"); + return; + } + has_old = TRUE; + channels_new = channels_old; + } + + u32 = g_variant_get_uint32(variant); + + switch (ethtool_id) { + case NM_ETHTOOL_ID_CHANNELS_RX: + channels_new.rx = u32; + break; + case NM_ETHTOOL_ID_CHANNELS_TX: + channels_new.tx = u32; + break; + case NM_ETHTOOL_ID_CHANNELS_OTHER: + channels_new.other = u32; + break; + case NM_ETHTOOL_ID_CHANNELS_COMBINED: + channels_new.combined = u32; + break; + default: + nm_assert_not_reached(); + } + } + + if (!has_old) + return; + + ethtool_state->channels = nm_memdup(&channels_old, sizeof(channels_old)); + + if (!nm_platform_ethtool_set_channels(platform, ethtool_state->ifindex, &channels_new)) { + _LOGW(LOGD_DEVICE, "ethtool: failure setting channels settings"); + return; + } + + _LOGD(LOGD_DEVICE, "ethtool: channels settings successfully set"); +} + +static void _ethtool_pause_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) { gs_free NMEthtoolPauseState *pause = NULL; @@ -2611,6 +2727,25 @@ _ethtool_pause_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool } static void +_ethtool_eee_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) +{ + gs_free NMEthtoolEEEState *eee = NULL; + + nm_assert(NM_IS_DEVICE(self)); + nm_assert(NM_IS_PLATFORM(platform)); + nm_assert(ethtool_state); + + eee = g_steal_pointer(ðtool_state->eee); + if (!eee) + return; + + if (!nm_platform_ethtool_set_eee(platform, ethtool_state->ifindex, eee)) + _LOGW(LOGD_DEVICE, "ethtool: failure resetting eee settings"); + else + _LOGD(LOGD_DEVICE, "ethtool: eee settings successfully reset"); +} + +static void _ethtool_pause_set(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state, @@ -2699,6 +2834,73 @@ _ethtool_pause_set(NMDevice *self, } static void +_ethtool_eee_set(NMDevice *self, + NMPlatform *platform, + EthtoolState *ethtool_state, + NMSettingEthtool *s_ethtool) +{ + NMEthtoolEEEState eee_old; + NMEthtoolEEEState eee_new; + GHashTable *hash; + GHashTableIter iter; + const char *name; + GVariant *variant; + gboolean has_old = FALSE; + NMTernary eee = NM_TERNARY_DEFAULT; + + nm_assert(NM_IS_DEVICE(self)); + nm_assert(NM_IS_PLATFORM(platform)); + nm_assert(NM_IS_SETTING_ETHTOOL(s_ethtool)); + nm_assert(ethtool_state); + nm_assert(!ethtool_state->eee); + + hash = _nm_setting_option_hash(NM_SETTING(s_ethtool), FALSE); + if (!hash) + return; + + g_hash_table_iter_init(&iter, hash); + while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &variant)) { + NMEthtoolID ethtool_id = nm_ethtool_id_get_by_name(name); + + if (!nm_ethtool_id_is_eee(ethtool_id)) + continue; + + nm_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN)); + + if (!has_old) { + if (!nm_platform_ethtool_get_link_eee(platform, ethtool_state->ifindex, &eee_old)) { + _LOGW(LOGD_DEVICE, + "ethtool: failure setting eee options (cannot read " + "existing setting)"); + return; + } + has_old = TRUE; + } + + if (ethtool_id == NM_ETHTOOL_ID_EEE_ENABLED) + eee = g_variant_get_boolean(variant); + else + nm_assert_not_reached(); + } + + if (!has_old) + return; + + eee_new = eee_old; + if (eee != NM_TERNARY_DEFAULT) + eee_new.enabled = !!eee; + + ethtool_state->eee = nm_memdup(&eee_old, sizeof(eee_old)); + + if (!nm_platform_ethtool_set_eee(platform, ethtool_state->ifindex, &eee_new)) { + _LOGW(LOGD_DEVICE, "ethtool: failure setting eee settings"); + return; + } + + _LOGD(LOGD_DEVICE, "ethtool: eee settings successfully set"); +} + +static void _ethtool_state_reset(NMDevice *self) { NMPlatform *platform = nm_device_get_platform(self); @@ -2708,14 +2910,12 @@ _ethtool_state_reset(NMDevice *self) if (!ethtool_state) return; - if (ethtool_state->features) - _ethtool_features_reset(self, platform, ethtool_state); - if (ethtool_state->coalesce) - _ethtool_coalesce_reset(self, platform, ethtool_state); - if (ethtool_state->ring) - _ethtool_ring_reset(self, platform, ethtool_state); - if (ethtool_state->pause) - _ethtool_pause_reset(self, platform, ethtool_state); + _ethtool_features_reset(self, platform, ethtool_state); + _ethtool_coalesce_reset(self, platform, ethtool_state); + _ethtool_ring_reset(self, platform, ethtool_state); + _ethtool_pause_reset(self, platform, ethtool_state); + _ethtool_channels_reset(self, platform, ethtool_state); + _ethtool_eee_reset(self, platform, ethtool_state); } static void @@ -2750,9 +2950,11 @@ _ethtool_state_set(NMDevice *self) _ethtool_coalesce_set(self, platform, ethtool_state, s_ethtool); _ethtool_ring_set(self, platform, ethtool_state, s_ethtool); _ethtool_pause_set(self, platform, ethtool_state, s_ethtool); + _ethtool_channels_set(self, platform, ethtool_state, s_ethtool); + _ethtool_eee_set(self, platform, ethtool_state, s_ethtool); if (ethtool_state->features || ethtool_state->coalesce || ethtool_state->ring - || ethtool_state->pause) + || ethtool_state->pause || ethtool_state->channels || ethtool_state->eee) priv->ethtool_state = g_steal_pointer(ðtool_state); } @@ -2863,7 +3065,7 @@ nm_device_link_properties_set(NMDevice *self, gboolean reapply) _RESET(NM_PLATFORM_LINK_CHANGE_GSO_MAX_SEGMENTS, gso_max_segments); _RESET(NM_PLATFORM_LINK_CHANGE_GRO_MAX_SIZE, gro_max_size); - if (nm_platform_link_change(platform, ifindex, &props, NULL, flags)) { + if (nm_platform_link_change(platform, ifindex, &props, NULL, NULL, flags)) { _LOGD(LOGD_DEVICE, "link properties successfully set"); } else { _LOGW(LOGD_DEVICE, "failure setting link properties"); @@ -2891,6 +3093,7 @@ link_properties_reset(NMDevice *self) ifindex, &priv->link_props_state.props, NULL, + NULL, priv->link_props_state.flags)) { _LOGD(LOGD_DEVICE, "link properties successfully reset"); } else { @@ -4228,6 +4431,19 @@ update_external_connection(NMDevice *self) } static void +_dev_ipv6_log_conflicts(NMDevice *self, GArray *conflicts) +{ + guint i; + char sbuf[NM_INET_ADDRSTRLEN]; + + for (i = 0; i < conflicts->len; i++) { + const struct in6_addr *addr = &nm_g_array_index(conflicts, const struct in6_addr, i); + + _LOGI(LOGD_DEVICE, "Conflict detected for IPv6 address: %s", nm_inet6_ntop(addr, sbuf)); + } +} + +static void _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); @@ -4250,7 +4466,7 @@ _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, N char buf_addr[NM_INET_ADDRSTRLEN]; if (addr_info->state == NM_L3_ACD_ADDR_STATE_USED) { - _LOGI(LOGD_DEVICE, + _LOGW(LOGD_DEVICE, "IP address %s cannot be configured because it is already in use in the " "network by host %s", nm_inet4_ntop(addr_info->addr, buf_addr), @@ -4284,7 +4500,6 @@ _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, N if (priv->ipshared_data_4.state == NM_DEVICE_IP_STATE_PENDING && !priv->ipshared_data_4.v4.dnsmasq_manager && priv->ipshared_data_4.v4.l3cd) { _dev_ipshared4_spawn_dnsmasq(self); - nm_clear_l3cd(&priv->ipshared_data_4.v4.l3cd); } _dev_ip_state_check_async(self, AF_UNSPEC); _dev_ipmanual_check_ready(self); @@ -4322,6 +4537,10 @@ _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, N NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY, &conflicts); if (conflicts) { + if (_NMLOG_ENABLED(LOGL_INFO, LOGD_DEVICE)) { + _dev_ipv6_log_conflicts(self, conflicts); + } + /* nm_ndisc_dad_failed() will emit a new "NDisc:config-received" * signal; _dev_ipac6_ndisc_config_changed() will be called * synchronously to update the current state and schedule a commit. */ @@ -5231,6 +5450,8 @@ nm_device_get_route_metric_default(NMDeviceType device_type) return 200; case NM_DEVICE_TYPE_WIMAX: return 250; + case NM_DEVICE_TYPE_HSR: + return 275; case NM_DEVICE_TYPE_BOND: return 300; case NM_DEVICE_TYPE_TEAM: @@ -5715,7 +5936,7 @@ out: return FALSE; } -#define CONCHECK_P_PROBE_INTERVAL 1 +#define CONCHECK_P_PROBE_INTERVAL 1u static void concheck_periodic_schedule_set(NMDevice *self, int addr_family, ConcheckScheduleMode mode) @@ -5887,7 +6108,7 @@ concheck_update_interval(NMDevice *self, int addr_family, gboolean check_now) new_interval = nm_connectivity_get_interval(concheck_get_mgr(self)); - new_interval = NM_MIN(new_interval, 7 * 24 * 3600); + new_interval = NM_MIN(new_interval, 7u * 24u * 3600u); if (new_interval != priv->concheck_x[IS_IPv4].p_max_interval) { _LOGT(LOGD_CONCHECK, @@ -7133,7 +7354,7 @@ device_ip_link_changed(gpointer user_data) ip_iface = pllink->name; if (!ip_iface[0]) - return FALSE; + return G_SOURCE_REMOVE; if (!nm_streq(priv->ip_iface, ip_iface)) { _LOGI(LOGD_DEVICE, @@ -7989,6 +8210,40 @@ nm_device_owns_iface(NMDevice *self, const char *iface) return FALSE; } +static void +apply_udev_auto_default_configs(NMDevice *self, NMConnection *connection) +{ + struct udev_device *dev; + const char *uprop; + NMSetting *setting; + + dev = nm_platform_link_get_udev_device(nm_device_get_platform(NM_DEVICE(self)), + nm_device_get_ip_ifindex(self)); + if (!dev) + return; + + uprop = udev_device_get_property_value(dev, "NM_AUTO_DEFAULT_LINK_LOCAL_ONLY"); + uprop = uprop ?: udev_device_get_property_value(dev, "ID_NET_AUTO_LINK_LOCAL_ONLY"); + + if (_nm_utils_ascii_str_to_bool(uprop, FALSE)) { + setting = nm_setting_ip4_config_new(); + g_object_set(setting, + NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL, + NULL); + nm_connection_add_setting(connection, setting); + + setting = nm_setting_ip6_config_new(); + g_object_set(setting, + NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL, + NM_SETTING_IP_CONFIG_MAY_FAIL, + TRUE, + NULL); + nm_connection_add_setting(connection, setting); + } +} + NMConnection * nm_device_new_default_connection(NMDevice *self) { @@ -8002,6 +8257,8 @@ nm_device_new_default_connection(NMDevice *self) if (!connection) return NULL; + apply_udev_auto_default_configs(self, connection); + if (!nm_connection_normalize(connection, NULL, NULL, &error)) { _LOGD(LOGD_DEVICE, "device generated an invalid default connection: %s", error->message); g_error_free(error); @@ -8323,7 +8580,7 @@ nm_device_slave_notify_release(NMDevice *self, master_status = "failed"; break; case NM_DEVICE_STATE_REASON_USER_REQUESTED: - reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; + reason = NM_DEVICE_STATE_REASON_USER_REQUESTED; master_status = "deactivated by user request"; break; case NM_DEVICE_STATE_REASON_CONNECTION_REMOVED: @@ -9184,7 +9441,7 @@ nm_device_check_slave_connection_compatible(NMDevice *self, NMConnection *slave) s_con = nm_connection_get_setting_connection(slave); g_assert(s_con); - slave_type = nm_setting_connection_get_slave_type(s_con); + slave_type = nm_setting_connection_get_port_type(s_con); if (!slave_type) return FALSE; @@ -9746,10 +10003,16 @@ activate_stage1_device_prepare(NMDevice *self) master = nm_active_connection_get_master(active); if (master) { if (nm_active_connection_get_state(master) >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) { + NMDevice *master_device = nm_active_connection_get_device(master); + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; + _LOGD(LOGD_DEVICE, "master connection is deactivating"); - nm_device_state_changed(self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED); + + if (master_device && NM_DEVICE_GET_PRIVATE(master_device)->queued_act_request) { + /* if the controller is going to activate again, don't block this device */ + failure_reason = NM_DEVICE_STATE_REASON_NONE; + } + nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason); return; } /* If the master connection is ready for slaves, attach ourselves */ @@ -10363,7 +10626,6 @@ _dev_ipmanual_check_ready(NMDevice *self) gboolean has_carrier; NML3CfgCheckReadyFlags flags; gboolean ready; - gs_unref_array GArray *conflicts = NULL; int IS_IPv4; if (priv->ipmanual_data.state_4 != NM_DEVICE_IP_STATE_PENDING @@ -10393,26 +10655,41 @@ _dev_ipmanual_check_ready(NMDevice *self) } } - flags = NM_L3CFG_CHECK_READY_FLAGS_NONE; - if (has_carrier) { - flags |= NM_L3CFG_CHECK_READY_FLAGS_IP4_ACD_READY; - flags |= NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY; - } + flags = NM_L3CFG_CHECK_READY_FLAGS_IP4_ACD_READY; + flags |= NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY; for (IS_IPv4 = 0; IS_IPv4 < 2; IS_IPv4++) { - const int addr_family = IS_IPv4 ? AF_INET : AF_INET6; + const int addr_family = IS_IPv4 ? AF_INET : AF_INET6; + gs_unref_array GArray *conflicts = NULL; ready = nm_l3cfg_check_ready(priv->l3cfg, priv->l3cds[L3_CONFIG_DATA_TYPE_MANUALIP].d, addr_family, flags, &conflicts); - if (conflicts) { - _dev_ipmanual_set_state(self, addr_family, NM_DEVICE_IP_STATE_FAILED); - _dev_ip_state_check_async(self, AF_UNSPEC); - } else if (ready) { - _dev_ipmanual_set_state(self, addr_family, NM_DEVICE_IP_STATE_READY); - _dev_ip_state_check_async(self, AF_UNSPEC); + + if (_NMLOG_ENABLED(LOGL_INFO, LOGD_DEVICE) && conflicts && !IS_IPv4) { + _dev_ipv6_log_conflicts(self, conflicts); + } + + if (ready) { + guint num_addrs = 0; + + num_addrs = + nm_l3_config_data_get_num_addresses(priv->l3cds[L3_CONFIG_DATA_TYPE_MANUALIP].d, + addr_family); + + if (conflicts && conflicts->len == num_addrs) { + _LOGD_ipmanual(addr_family, "all manual addresses failed DAD, failing"); + _dev_ipmanual_set_state(self, addr_family, NM_DEVICE_IP_STATE_FAILED); + _dev_ip_state_check_async(self, AF_UNSPEC); + } else { + if (conflicts) { + _LOGD_ipmanual(addr_family, "some manual addresses passed DAD, continuing"); + } + _dev_ipmanual_set_state(self, addr_family, NM_DEVICE_IP_STATE_READY); + _dev_ip_state_check_async(self, AF_UNSPEC); + } } } } @@ -10692,8 +10969,10 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) const char *const *reject_servers; const char *hostname; gboolean hostname_is_fqdn; + gboolean send_client_id; + + client_id = _prop_get_ipv4_dhcp_client_id(self, connection, hwaddr, &send_client_id); - client_id = _prop_get_ipv4_dhcp_client_id(self, connection, hwaddr); vendor_class_identifier = _prop_get_ipv4_dhcp_vendor_class_identifier(self, NM_SETTING_IP4_CONFIG(s_ip)); reject_servers = nm_setting_ip_config_get_dhcp_reject_servers(s_ip, NULL); @@ -10730,6 +11009,7 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family) { .request_broadcast = request_broadcast, .acd_timeout_msec = _prop_get_ipv4_dad_timeout(self), + .send_client_id = send_client_id, }, .previous_lease = priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4)].d, }; @@ -11560,13 +11840,13 @@ _commit_mtu(NMDevice *self) mtu_plat = nm_platform_link_get_mtu(nm_device_get_platform(self), ifindex); if (ip6_mtu) { - ip6_mtu = NM_MAX(1280, ip6_mtu); + ip6_mtu = NM_MAX(1280u, ip6_mtu); if (!mtu_desired) mtu_desired = mtu_plat; if (mtu_desired) { - mtu_desired = NM_MAX(1280, mtu_desired); + mtu_desired = NM_MAX(1280u, mtu_desired); if (mtu_desired < ip6_mtu) ip6_mtu = mtu_desired; @@ -11736,8 +12016,9 @@ _dev_ipac6_ndisc_config_changed(NMNDisc *ndisc, const NML3ConfigData *l3cd, NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gboolean ready; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean ready; + gs_unref_array GArray *conflicts = NULL; /* The ndisc configuration changes when we receive a new RA or * when a lifetime expires; but also when DAD fails for a @@ -11754,7 +12035,12 @@ _dev_ipac6_ndisc_config_changed(NMNDisc *ndisc, l3cd, AF_INET6, NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY, - NULL); + &conflicts); + + if (_NMLOG_ENABLED(LOGL_INFO, LOGD_DEVICE) && conflicts) { + _dev_ipv6_log_conflicts(self, conflicts); + } + if (ready) { _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY); } else { @@ -11856,16 +12142,8 @@ _dev_ipac6_start(NMDevice *self) NMUtilsIPv6IfaceId iid; gboolean is_token; - if (priv->ipac6_data.state == NM_DEVICE_IP_STATE_NONE) { - if (!g_file_test("/proc/sys/net/ipv6", G_FILE_TEST_IS_DIR)) { - _LOGI_ipac6("addrconf6: kernel does not support IPv6"); - _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_FAILED); - _dev_ip_state_check_async(self, AF_INET6); - return; - } - + if (priv->ipac6_data.state == NM_DEVICE_IP_STATE_NONE) _dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_PENDING); - } if (NM_IN_SET(priv->ipll_data_6.state, NM_DEVICE_IP_STATE_NONE, NM_DEVICE_IP_STATE_PENDING)) { _dev_ipac6_grace_period_start(self, 30, TRUE); @@ -12406,6 +12684,30 @@ activate_stage3_ip_config(NMDevice *self) ifindex = nm_device_get_ip_ifindex(self); + /* Add the interface to the specified firewall zone */ + switch (priv->fw_state) { + case FIREWALL_STATE_UNMANAGED: + if (nm_device_sys_iface_state_is_external(self)) { + /* fake success */ + priv->fw_state = FIREWALL_STATE_INITIALIZED; + } else if (ifindex > 0) { + priv->fw_state = FIREWALL_STATE_WAIT_STAGE_3; + fw_change_zone(self); + return; + } + /* no ifindex, nothing to do for now */ + break; + case FIREWALL_STATE_WAIT_STAGE_3: + /* a firewall call for stage3 is pending. Return and wait. */ + return; + default: + nm_assert(NM_IN_SET((FirewallState) priv->fw_state, + FIREWALL_STATE_INITIALIZED, + FIREWALL_STATE_WAIT_IP_CONFIG)); + break; + } + nm_assert(ifindex <= 0 || priv->fw_state == FIREWALL_STATE_INITIALIZED); + ipv4_method = nm_device_get_effective_ip_config_method(self, AF_INET); if (nm_streq(ipv4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { /* "auto" usually means DHCPv4 or autoconf6, but it doesn't have to be. Subclasses @@ -12414,8 +12716,18 @@ activate_stage3_ip_config(NMDevice *self) } ipv6_method = nm_device_get_effective_ip_config_method(self, AF_INET6); - - if (nm_streq(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { + if (!g_file_test("/proc/sys/net/ipv6", G_FILE_TEST_IS_DIR)) { + _NMLOG_ip((nm_device_sys_iface_state_is_external(self) + || NM_IN_STRSET(ipv6_method, + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED, + NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) + ? LOGL_DEBUG + : LOGL_WARN, + AF_INET6, + "IPv6 not supported by kernel resulting in \"ipv6.method=disabled\""); + ipv6_method = NM_SETTING_IP6_CONFIG_METHOD_DISABLED; + } else if (nm_streq(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { ipv6_method = klass->get_ip_method_auto(self, AF_INET6); } @@ -12436,30 +12748,6 @@ activate_stage3_ip_config(NMDevice *self) nm_streq(ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)); } - /* Add the interface to the specified firewall zone */ - switch (priv->fw_state) { - case FIREWALL_STATE_UNMANAGED: - if (nm_device_sys_iface_state_is_external(self)) { - /* fake success */ - priv->fw_state = FIREWALL_STATE_INITIALIZED; - } else if (ifindex > 0) { - priv->fw_state = FIREWALL_STATE_WAIT_STAGE_3; - fw_change_zone(self); - return; - } - /* no ifindex, nothing to do for now */ - break; - case FIREWALL_STATE_WAIT_STAGE_3: - /* a firewall call for stage3 is pending. Return and wait. */ - return; - default: - nm_assert(NM_IN_SET((FirewallState) priv->fw_state, - FIREWALL_STATE_INITIALIZED, - FIREWALL_STATE_WAIT_IP_CONFIG)); - break; - } - nm_assert(ifindex <= 0 || priv->fw_state == FIREWALL_STATE_INITIALIZED); - if (priv->state < NM_DEVICE_STATE_IP_CONFIG) { _dev_ip_state_req_timeout_schedule(self, AF_INET); _dev_ip_state_req_timeout_schedule(self, AF_INET6); @@ -12726,18 +13014,32 @@ out_fail: static void _dev_ipshared4_spawn_dnsmasq(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const char *ip_iface; - gs_free_error GError *error = NULL; - NMSettingConnection *s_con; - gboolean announce_android_metered; - NMConnection *applied; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const char *ip_iface; + gs_free_error GError *error = NULL; + NMSettingConnection *s_con; + gboolean announce_android_metered; + NMConnection *applied; + gs_unref_array GArray *conflicts = NULL; + gboolean ready; nm_assert(priv->ipshared_data_4.v4.firewall_config); nm_assert(priv->ipshared_data_4.v4.dnsmasq_state_id == 0); nm_assert(!priv->ipshared_data_4.v4.dnsmasq_manager); nm_assert(priv->ipshared_data_4.v4.l3cd); + ready = nm_l3cfg_check_ready(priv->l3cfg, + priv->l3cds[L3_CONFIG_DATA_TYPE_SHARED_4].d, + AF_INET, + NM_L3CFG_CHECK_READY_FLAGS_IP4_ACD_READY, + &conflicts); + if (!ready) { + _LOGT_ipshared(AF_INET, "address not ready, wait"); + return; + } + if (conflicts) + goto out_fail; + ip_iface = nm_device_get_ip_iface(self); g_return_if_fail(ip_iface); @@ -12782,9 +13084,11 @@ _dev_ipshared4_spawn_dnsmasq(NMDevice *self) _dev_ipsharedx_set_state(self, AF_INET, NM_DEVICE_IP_STATE_READY); _dev_ip_state_check_async(self, AF_INET); + nm_clear_l3cd(&priv->ipshared_data_4.v4.l3cd); return; out_fail: + nm_clear_l3cd(&priv->ipshared_data_4.v4.l3cd); _dev_ipsharedx_set_state(self, AF_INET, NM_DEVICE_IP_STATE_FAILED); _dev_ip_state_check_async(self, AF_INET); } @@ -12993,7 +13297,7 @@ _nm_device_hash_check_invalid_keys(GHashTable *hash, g_hash_table_iter_init(&iter, hash); while (g_hash_table_iter_next(&iter, (gpointer *) &k, NULL)) { - if (nm_strv_find_first(whitelist, -1, k) < 0) { + if (!nm_strv_contains(whitelist, -1, k)) { first_invalid_key = k; break; } @@ -14952,20 +15256,23 @@ nm_device_set_unmanaged_by_user_settings(NMDevice *self, gboolean now) void nm_device_set_unmanaged_by_user_udev(NMDevice *self) { - int ifindex; - gboolean platform_unmanaged = FALSE; + NMOptionBool platform_unmanaged; + int ifindex; ifindex = self->_priv->ifindex; - if (ifindex <= 0 - || !nm_platform_link_get_unmanaged(nm_device_get_platform(self), - ifindex, - &platform_unmanaged)) + if (ifindex <= 0) + return; + + platform_unmanaged = nm_platform_link_get_unmanaged(nm_device_get_platform(self), ifindex); + if (platform_unmanaged == NM_OPTION_BOOL_DEFAULT) return; nm_device_set_unmanaged_by_flags(self, NM_UNMANAGED_USER_UDEV, - platform_unmanaged, + platform_unmanaged == NM_OPTION_BOOL_TRUE + ? NM_UNMAN_FLAG_OP_SET_UNMANAGED + : NM_UNMAN_FLAG_OP_SET_MANAGED, NM_DEVICE_STATE_REASON_USER_REQUESTED); } @@ -17128,9 +17435,12 @@ _hw_addr_get_cloned(NMDevice *self, addr_out = g_steal_pointer(&hw_addr_generated); type_out = HW_ADDR_TYPE_GENERATED; - } else if (NM_IN_STRSET(addr, NM_CLONED_MAC_STABLE)) { + } else if (nm_streq(addr, NM_CLONED_MAC_STABLE) + || (is_wifi && nm_streq(addr, NM_CLONED_MAC_STABLE_SSID))) { + gs_free char *stable_id_free = NULL; NMUtilsStableType stable_type; const char *stable_id; + GBytes *ssid = NULL; if (priv->hw_addr_type == HW_ADDR_TYPE_GENERATED) { /* hm, we already use a generate MAC address. Most certainly, that is from the same @@ -17138,7 +17448,28 @@ _hw_addr_get_cloned(NMDevice *self, goto out_no_action; } - stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); + if (!nm_streq(addr, NM_CLONED_MAC_STABLE)) { + NMSettingWireless *s_wifi; + + s_wifi = nm_connection_get_setting_wireless(connection); + if (s_wifi) + ssid = nm_setting_wireless_get_ssid(s_wifi); + } + + if (G_UNLIKELY(ssid)) { + stable_type = nm_utils_stable_id_parse_network_ssid(ssid, + nm_connection_get_uuid(connection), + TRUE, + &stable_id_free); + stable_id = stable_id_free; + } else { + /* If @addr is NM_CLONED_MAC_STABLE_SSID, and this is not a Wi-Fi + * profile, the behavior is the same as NM_CLONED_MAC_STABLE. Note + * that this really shouldn't happen, because we have a Wi-Fi + * profile at hand, and an SSID should be set. */ + stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); + } + hw_addr_generated = nm_utils_hw_addr_gen_stable_eth( stable_type, stable_id, @@ -17982,7 +18313,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps nm_assert(priv->type == NM_DEVICE_TYPE_UNKNOWN); priv->type = g_value_get_uint(value); nm_assert(priv->type > NM_DEVICE_TYPE_UNKNOWN); - nm_assert(priv->type <= NM_DEVICE_TYPE_LOOPBACK); + nm_assert(priv->type <= NM_DEVICE_TYPE_HSR); break; case PROP_LINK_TYPE: /* construct-only */ @@ -18331,9 +18662,11 @@ static const NMDBusInterfaceInfoExtended interface_info_device = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Capabilities", "u", NM_DEVICE_CAPABILITIES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ip4Address", - "u", - NM_DEVICE_IP4_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Ip4Address", + "u", + NM_DEVICE_IP4_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("State", "u", NM_DEVICE_STATE), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("StateReason", "(uu)", diff --git a/src/core/devices/ovs/nm-device-ovs-bridge.c b/src/core/devices/ovs/nm-device-ovs-bridge.c index ff1917b1..3bc03ac1 100644 --- a/src/core/devices/ovs/nm-device-ovs-bridge.c +++ b/src/core/devices/ovs/nm-device-ovs-bridge.c @@ -152,7 +152,11 @@ static const NMDBusInterfaceInfoExtended interface_info_device_ovs_bridge = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_OVS_BRIDGE, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), ), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Slaves", + "ao", + NM_DEVICE_SLAVES, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), ), ), }; static void diff --git a/src/core/devices/ovs/nm-device-ovs-interface.c b/src/core/devices/ovs/nm-device-ovs-interface.c index fd48c2fd..17eb2c2d 100644 --- a/src/core/devices/ovs/nm-device-ovs-interface.c +++ b/src/core/devices/ovs/nm-device-ovs-interface.c @@ -24,10 +24,21 @@ typedef struct { NMOvsdb *ovsdb; - GSource *wait_link_idle_source; - gulong wait_link_signal_id; - int wait_link_ifindex; - bool wait_link_is_waiting : 1; + + struct { + /* The source for the idle handler to set the TUN ifindex */ + GSource *tun_set_ifindex_idle_source; + /* The cloned MAC to set */ + char *cloned_mac; + /* The id for the signal watching the TUN link to appear/change */ + gulong tun_link_signal_id; + /* The TUN ifindex to set in the idle handler */ + int tun_ifindex; + /* Whether we have determined the cloned MAC */ + bool cloned_mac_evaluated : 1; + /* Whether we are waiting for the kernel link */ + bool waiting : 1; + } wait_link; } NMDeviceOvsInterfacePrivate; struct _NMDeviceOvsInterface { @@ -46,6 +57,13 @@ G_DEFINE_TYPE(NMDeviceOvsInterface, nm_device_ovs_interface, NM_TYPE_DEVICE) /*****************************************************************************/ +static void _netdev_tun_link_cb(NMPlatform *platform, + int obj_type_i, + int ifindex, + NMPlatformLink *pllink, + int change_type_i, + NMDevice *device); + static const char * get_type_description(NMDevice *device) { @@ -117,35 +135,65 @@ check_connection_compatible(NMDevice *device, return TRUE; } +static gboolean +check_waiting_for_link(NMDevice *device, const char *from) +{ + NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); + NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); + NMPlatform *platform = nm_device_get_platform(device); + const NMPlatformLink *pllink; + int ip_ifindex; + const char *reason = NULL; + + if (!priv->wait_link.waiting) + return FALSE; + + nm_assert(priv->wait_link.cloned_mac_evaluated); + ip_ifindex = nm_device_get_ip_ifindex(device); + + if (ip_ifindex <= 0) { + reason = "no ifindex"; + } else if (!(pllink = nm_platform_link_get(platform, ip_ifindex))) { + reason = "platform link not found"; + } else if (priv->wait_link.cloned_mac + && !nm_utils_hwaddr_matches(priv->wait_link.cloned_mac, + -1, + pllink->l_address.data, + pllink->l_address.len)) { + reason = "cloned MAC address is not set yet"; + } else { + priv->wait_link.waiting = FALSE; + } + + if (priv->wait_link.waiting) + _LOGT(LOGD_DEVICE, "ovs-wait-link(%s): not ready: %s", from, reason); + + return priv->wait_link.waiting; +} + static void link_changed(NMDevice *device, const NMPlatformLink *pllink) { - NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(device); + NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); + NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); - if (!pllink || !priv->wait_link_is_waiting) + if (!pllink || !priv->wait_link.waiting) return; - priv->wait_link_is_waiting = FALSE; + if (nm_device_get_state(device) != NM_DEVICE_STATE_IP_CONFIG) + return; - if (nm_device_get_state(device) == NM_DEVICE_STATE_IP_CONFIG) { - if (!nm_device_hw_addr_set_cloned(device, - nm_device_get_applied_connection(device), - FALSE)) { - nm_device_devip_set_failed(device, AF_INET, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - nm_device_devip_set_failed(device, AF_INET6, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return; - } + if (check_waiting_for_link(device, "link-changed")) + return; - nm_device_link_properties_set(device, FALSE); - nm_device_bring_up(device); + _LOGT(LOGD_CORE, "ovs-wait-link: link is ready after link changed event"); - nm_device_devip_set_state(device, AF_INET, NM_DEVICE_IP_STATE_PENDING, NULL); - nm_device_devip_set_state(device, AF_INET6, NM_DEVICE_IP_STATE_PENDING, NULL); - nm_device_activate_schedule_stage3_ip_config(device, FALSE); - return; - } + nm_device_link_properties_set(device, FALSE); + nm_device_bring_up(device); - nm_device_activate_schedule_stage2_device_config(device, FALSE); + nm_device_devip_set_state(device, AF_INET, NM_DEVICE_IP_STATE_PENDING, NULL); + nm_device_devip_set_state(device, AF_INET6, NM_DEVICE_IP_STATE_PENDING, NULL); + nm_device_activate_schedule_stage3_ip_config(device, FALSE); } static gboolean @@ -205,7 +253,9 @@ set_platform_mtu(NMDevice *device, guint32 mtu) static gboolean ready_for_ip_config(NMDevice *device, gboolean is_manual) { - return nm_device_get_ip_ifindex(device) > 0; + NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(device); + + return nm_device_get_ip_ifindex(device) > 0 && !priv->wait_link.waiting; } static gboolean @@ -215,10 +265,28 @@ _set_ip_ifindex_tun(gpointer user_data) NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); - nm_clear_g_source_inst(&priv->wait_link_idle_source); + _LOGT(LOGD_CORE, + "ovs-wait-link: setting ip-ifindex %d from tun interface", + priv->wait_link.tun_ifindex); + + nm_clear_g_source_inst(&priv->wait_link.tun_set_ifindex_idle_source); + + nm_device_set_ip_ifindex(device, priv->wait_link.tun_ifindex); + + if (check_waiting_for_link(device, "set-ip-ifindex-tun")) { + /* If the link is not ready, it means the MAC is not set yet. We don't have + * a convenient way to monitor for ip-ifindex changes other than listening + * for platform events again.*/ + nm_assert(!priv->wait_link.tun_link_signal_id); + priv->wait_link.tun_link_signal_id = g_signal_connect(nm_device_get_platform(device), + NM_PLATFORM_SIGNAL_LINK_CHANGED, + G_CALLBACK(_netdev_tun_link_cb), + self); + return G_SOURCE_CONTINUE; + } + + _LOGT(LOGD_CORE, "tun link is ready"); - priv->wait_link_is_waiting = FALSE; - nm_device_set_ip_ifindex(device, priv->wait_link_ifindex); nm_device_link_properties_set(device, FALSE); nm_device_devip_set_state(device, AF_INET, NM_DEVICE_IP_STATE_PENDING, NULL); @@ -239,75 +307,149 @@ _netdev_tun_link_cb(NMPlatform *platform, const NMPlatformSignalChangeType change_type = change_type_i; NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); + int ip_ifindex; - if (change_type == NM_PLATFORM_SIGNAL_ADDED) { - if (pllink->type == NM_LINK_TYPE_TUN - && nm_streq0(pllink->name, nm_device_get_iface(device))) { - nm_clear_g_signal_handler(platform, &priv->wait_link_signal_id); + if (pllink->type != NM_LINK_TYPE_TUN || !nm_streq0(pllink->name, nm_device_get_iface(device))) + return; - priv->wait_link_ifindex = ifindex; + ip_ifindex = nm_device_get_ip_ifindex(device); + if (ip_ifindex > 0) { + /* When we have an ifindex, we are only waiting for the MAC to settle */ + if (change_type != NM_PLATFORM_SIGNAL_CHANGED) + return; - priv->wait_link_idle_source = nm_g_idle_add_source(_set_ip_ifindex_tun, device); + if (!check_waiting_for_link(device, "tun-link-changed")) { + _LOGT(LOGD_CORE, "ovs-wait-link: tun link is ready, cloned MAC is set"); + + nm_clear_g_signal_handler(platform, &priv->wait_link.tun_link_signal_id); + nm_device_link_properties_set(device, FALSE); + + nm_device_devip_set_state(device, AF_INET, NM_DEVICE_IP_STATE_PENDING, NULL); + nm_device_devip_set_state(device, AF_INET6, NM_DEVICE_IP_STATE_PENDING, NULL); + nm_device_activate_schedule_stage3_ip_config(device, FALSE); } + return; } + + /* No ip-ifindex on the device, set it when the link appears */ + if (change_type != NM_PLATFORM_SIGNAL_ADDED) + return; + + _LOGT(LOGD_CORE, + "ovs-wait-link: found matching tun interface, schedule set-ip-ifindex(%d)", + ifindex); + nm_clear_g_signal_handler(platform, &priv->wait_link.tun_link_signal_id); + priv->wait_link.tun_ifindex = ifindex; + priv->wait_link.tun_set_ifindex_idle_source = nm_g_idle_add_source(_set_ip_ifindex_tun, device); +} + +static gboolean +ovs_interface_is_netdev_datapath(NMDeviceOvsInterface *self) +{ + NMDevice *device = NM_DEVICE(self); + NMActiveConnection *ac = NULL; + NMSettingOvsBridge *s_ovs_bridge = NULL; + + ac = NM_ACTIVE_CONNECTION(nm_device_get_act_request(device)); + if (!ac) + return FALSE; + + /* get ovs-port active-connection */ + ac = nm_active_connection_get_master(ac); + if (!ac) + return FALSE; + + /* get ovs-bridge active-connection */ + ac = nm_active_connection_get_master(ac); + if (!ac) + return FALSE; + + s_ovs_bridge = + nm_connection_get_setting_ovs_bridge(nm_active_connection_get_applied_connection(ac)); + if (!s_ovs_bridge) + return FALSE; + + return nm_streq0(nm_setting_ovs_bridge_get_datapath_type(s_ovs_bridge), "netdev"); } static void act_stage3_ip_config(NMDevice *device, int addr_family) { - NMActiveConnection *controller_act = NULL; - NMSettingOvsBridge *s_ovs_bridge = NULL; - NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); - NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); + NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); + NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); + + /* + * When the ovs-interface device enters stage3, it becomes eligible to be attached to + * its controller (a ovs-port). If also the ovs-bridge is ready, an entry is created + * in the ovsdb in NMDeviceOvsPort->attach_port(). + * FIXME(l3cfg): we should create the IP ifindex before stage3 start. + * + * NMDeviceOvsInterface->act_stage3_ip_config() is supposed to perform device-specific + * IP configuration on the device. An ovs-interface can be of different types, that + * require different handling: + * + * - "patch" and "dpdk" interfaces don't have any kernel link associated and thus + * NetworkManager completely skips any kind of IP configuration on them, by returning + * FALSE to ->ready_for_ip_config(). + * + * - "system" interfaces represent other interface types with kernel link (for + * example, ethernet, bond, etc.) that get attached to a ovs bridge. Once they are + * attached, NetworkManager can start the IP configuration right away. + * + * - "internal" interfaces are virtual interfaces created by openvswitch. Once the + * entry is created in the ovsdb, the kernel will create a link for the + * interface. When using the system datapath (the default), the link is of type + * "openvswitch", while when using the netdev (userspace) datapath, the link is a tun + * (tap) one. For both datapath types, we use this method to delay the IP + * configuration until the link appears. Note that ready_for_ip_config() returns FALSE + * when there is no ifindex, and so all the regular IP methods (static, auto, etc.) + * can't proceed. + */ if (!_is_internal_interface(device)) { nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, NULL); return; } - /* When the ovs-bridge controller is using netdev datapath, the interface - * link created is a tun device instead of a ovs-interface. NetworkManager must - * detect the creation of the tun link and attach the ifindex to the - * ovs-interface device. */ - controller_act = NM_ACTIVE_CONNECTION(nm_device_get_act_request(device)); - if (controller_act && nm_device_get_ip_ifindex(device) <= 0 && priv->wait_link_signal_id == 0) { - controller_act = nm_active_connection_get_master(controller_act); - if (controller_act) { - controller_act = nm_active_connection_get_master(controller_act); - if (controller_act) - s_ovs_bridge = nm_connection_get_setting_ovs_bridge( - nm_active_connection_get_applied_connection(controller_act)); - if (s_ovs_bridge - && nm_streq0(nm_setting_ovs_bridge_get_datapath_type(s_ovs_bridge), "netdev")) - priv->wait_link_signal_id = g_signal_connect(nm_device_get_platform(device), - NM_PLATFORM_SIGNAL_LINK_CHANGED, - G_CALLBACK(_netdev_tun_link_cb), - self); - } + /* + * If a ovs interface has the cloned-mac-address property set, we pass the desired MAC + * to ovsdb when creating the db entry, and openvswitch will eventually assign it to + * the interface. Note that usually the link will not have the desired MAC when it's + * created, and so we need to also monitor link changes to detect when the MAC is + * ready; only after that we can start IP configuration. Otherwise, the ARP + * announcements, the DHCP client-id, etc will use the wrong MAC. + */ + if (!priv->wait_link.cloned_mac_evaluated) { + nm_assert(!priv->wait_link.cloned_mac); + nm_device_hw_addr_get_cloned(device, + nm_device_get_applied_connection(device), + FALSE, + &priv->wait_link.cloned_mac, + NULL, + NULL); + priv->wait_link.cloned_mac_evaluated = TRUE; } - /* FIXME(l3cfg): we should create the IP ifindex before stage3 start. - * - * For now it's here because when the ovs-interface enters stage3, then it's added to the - * controller (ovs-port) and the entry is create in the ovsdb. Only after that the kernel - * link appears. - * - * This should change. */ - if (nm_device_get_ip_ifindex(device) <= 0) { - _LOGT(LOGD_DEVICE, "waiting for link to appear"); - priv->wait_link_is_waiting = TRUE; + priv->wait_link.waiting = TRUE; + if (check_waiting_for_link(device, addr_family == AF_INET ? "stage3-ipv4" : "stage3-ipv6")) { nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_PENDING, NULL); + if (nm_device_get_ip_ifindex(device) <= 0 && priv->wait_link.tun_link_signal_id == 0 + && ovs_interface_is_netdev_datapath(self)) { + priv->wait_link.tun_link_signal_id = g_signal_connect(nm_device_get_platform(device), + NM_PLATFORM_SIGNAL_LINK_CHANGED, + G_CALLBACK(_netdev_tun_link_cb), + self); + } return; } - priv->wait_link_is_waiting = FALSE; - nm_clear_g_source_inst(&priv->wait_link_idle_source); - nm_clear_g_signal_handler(nm_device_get_platform(device), &priv->wait_link_signal_id); + _LOGT(LOGD_DEVICE, + "ovs-wait-link: link is ready, IPv%c can proceed", + nm_utils_addr_family_to_char(addr_family)); - if (!nm_device_hw_addr_set_cloned(device, nm_device_get_applied_connection(device), FALSE)) { - nm_device_devip_set_failed(device, addr_family, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return; - } + priv->wait_link.waiting = FALSE; + nm_clear_g_source_inst(&priv->wait_link.tun_set_ifindex_idle_source); + nm_clear_g_signal_handler(nm_device_get_platform(device), &priv->wait_link.tun_link_signal_id); nm_device_link_properties_set(device, FALSE); nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, NULL); @@ -325,8 +467,11 @@ deactivate(NMDevice *device) NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); - priv->wait_link_is_waiting = FALSE; - nm_clear_g_source_inst(&priv->wait_link_idle_source); + priv->wait_link.waiting = FALSE; + priv->wait_link.cloned_mac_evaluated = FALSE; + nm_clear_g_free(&priv->wait_link.cloned_mac); + nm_clear_g_signal_handler(nm_device_get_platform(device), &priv->wait_link.tun_link_signal_id); + nm_clear_g_source_inst(&priv->wait_link.tun_set_ifindex_idle_source); } typedef struct { @@ -418,13 +563,27 @@ deactivate_async(NMDevice *device, _LOGT(LOGD_CORE, "deactivate: start async"); - /* We want to ensure that the kernel link for this device is - * removed upon disconnection so that it will not interfere with - * later activations of the same device. Unfortunately there is - * no synchronization mechanism with vswitchd, we only update - * ovsdb and wait that changes are picked up. - */ + nm_clear_g_signal_handler(nm_device_get_platform(device), &priv->wait_link.tun_link_signal_id); + nm_clear_g_source_inst(&priv->wait_link.tun_set_ifindex_idle_source); + priv->wait_link.cloned_mac_evaluated = FALSE; + nm_clear_g_free(&priv->wait_link.cloned_mac); + /* We want to ensure that the kernel link for this device is removed upon + * disconnection, so that it will not interfere with later activations of the same + * device. + * + * To do so, we need to be very careful, because unfortunately there is no + * synchronization mechanism with vswitchd: we only update ovsdb, wait that changes + * are picked up and we see the effects on the kernel interface (appearing or going + * away). + * + * That means for example that if the ovs interface entered stage3 and the entry was + * added to the ovsdb, we expect a link to appear. If we disconnect at this point, we + * delete the entry from the ovsdb. Now we don't know if ovs-vswitchd will see two + * updates or only one. In other words, we don't know if the interface will appear and + * go away, or if it will not appear ever. In this situation, the solution is to wait + * with a timeout. + */ data = g_slice_new(DeactivateData); *data = (DeactivateData){ .self = g_object_ref(self), @@ -433,7 +592,7 @@ deactivate_async(NMDevice *device, .callback_user_data = callback_user_data, }; - if (!priv->wait_link_is_waiting + if (!priv->wait_link.waiting && !nm_platform_link_get_by_ifname(nm_device_get_platform(device), nm_device_get_iface(device))) { _LOGT(LOGD_CORE, "deactivate: link not present, proceeding"); @@ -442,20 +601,15 @@ deactivate_async(NMDevice *device, return; } - nm_clear_g_source_inst(&priv->wait_link_idle_source); - - if (priv->wait_link_is_waiting) { - /* At this point we have issued an INSERT and a DELETE - * command for the interface to ovsdb. We don't know if - * vswitchd will see the two updates or only one. We - * must add a timeout to avoid waiting forever in case - * the link doesn't appear. - */ + if (priv->wait_link.waiting) { + /* Here we have issued an INSERT and a DELETE command for the interface to ovsdb, + * and must wait with a timeout. */ data->link_timeout_id = g_timeout_add(6000, deactivate_link_timeout, data); _LOGT(LOGD_DEVICE, "deactivate: waiting for link to disappear in 6 seconds"); } else _LOGT(LOGD_DEVICE, "deactivate: waiting for link to disappear"); + priv->wait_link.waiting = FALSE; data->cancelled_id = g_cancellable_connect(cancellable, G_CALLBACK(deactivate_cancelled_cb), data, NULL); data->link_changed_id = g_signal_connect(nm_device_get_platform(device), @@ -506,6 +660,10 @@ dispose(GObject *object) NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(object); NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); + nm_assert(!priv->wait_link.waiting); + nm_assert(priv->wait_link.tun_link_signal_id == 0); + nm_assert(!priv->wait_link.tun_set_ifindex_idle_source); + if (priv->ovsdb) { g_signal_handlers_disconnect_by_func(priv->ovsdb, G_CALLBACK(ovsdb_ready), self); g_clear_object(&priv->ovsdb); diff --git a/src/core/devices/ovs/nm-device-ovs-port.c b/src/core/devices/ovs/nm-device-ovs-port.c index 5ede46e9..258c72f2 100644 --- a/src/core/devices/ovs/nm-device-ovs-port.c +++ b/src/core/devices/ovs/nm-device-ovs-port.c @@ -266,7 +266,11 @@ static const NMDBusInterfaceInfoExtended interface_info_device_ovs_port = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_OVS_PORT, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), ), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Slaves", + "ao", + NM_DEVICE_SLAVES, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), ), ), }; static void diff --git a/src/core/devices/team/nm-device-team.c b/src/core/devices/team/nm-device-team.c index 4d748362..d8c3c2c2 100644 --- a/src/core/devices/team/nm-device-team.c +++ b/src/core/devices/team/nm-device-team.c @@ -290,9 +290,9 @@ master_update_slave_connection(NMDevice *device, g_free(port_config); g_object_set(nm_connection_get_setting_connection(connection), - NM_SETTING_CONNECTION_MASTER, + NM_SETTING_CONNECTION_CONTROLLER, nm_connection_get_uuid(applied_connection), - NM_SETTING_CONNECTION_SLAVE_TYPE, + NM_SETTING_CONNECTION_PORT_TYPE, NM_SETTING_TEAM_SETTING_NAME, NULL); return TRUE; @@ -1090,9 +1090,21 @@ static const NMDBusInterfaceInfoExtended interface_info_device_team = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_TEAM, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Carrier", + "b", + NM_DEVICE_CARRIER, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Slaves", + "ao", + NM_DEVICE_SLAVES, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Config", "s", NM_DEVICE_TEAM_CONFIG), ), ), diff --git a/src/core/devices/wifi/nm-device-iwd-p2p.c b/src/core/devices/wifi/nm-device-iwd-p2p.c index 73fd4716..fadc6722 100644 --- a/src/core/devices/wifi/nm-device-iwd-p2p.c +++ b/src/core/devices/wifi/nm-device-iwd-p2p.c @@ -1144,7 +1144,11 @@ static const NMDBusInterfaceInfoExtended interface_info_device_wifi_p2p = { .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_wifi_p2p_peer_added, &nm_signal_info_wifi_p2p_peer_removed, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Peers", "ao", NM_DEVICE_IWD_P2P_PEERS), ), ), diff --git a/src/core/devices/wifi/nm-device-olpc-mesh.c b/src/core/devices/wifi/nm-device-olpc-mesh.c index 436c7847..8e1e779b 100644 --- a/src/core/devices/wifi/nm-device-olpc-mesh.c +++ b/src/core/devices/wifi/nm-device-olpc-mesh.c @@ -497,7 +497,11 @@ static const NMDBusInterfaceInfoExtended interface_info_device_olpc_mesh = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_OLPC_MESH, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Companion", "o", NM_DEVICE_OLPC_MESH_COMPANION), diff --git a/src/core/devices/wifi/nm-device-wifi-p2p.c b/src/core/devices/wifi/nm-device-wifi-p2p.c index fa8cb8fa..981811a3 100644 --- a/src/core/devices/wifi/nm-device-wifi-p2p.c +++ b/src/core/devices/wifi/nm-device-wifi-p2p.c @@ -15,6 +15,7 @@ #include "NetworkManagerUtils.h" #include "devices/nm-device-private.h" #include "libnm-core-aux-intern/nm-libnm-core-utils.h" +#include "libnm-core-aux-intern/nm-common-macros.h" #include "libnm-core-intern/nm-core-internal.h" #include "libnm-glib-aux/nm-ref-string.h" #include "libnm-platform/nm-platform.h" @@ -982,23 +983,24 @@ device_state_changed(NMDevice *device, } static void -impl_device_wifi_p2p_start_find(NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +p2p_start_find_auth_cb(NMDevice *device, + GDBusMethodInvocation *invocation, + NMAuthSubject *subject, + GError *error, + gpointer user_data) { - NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P(obj); + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P(device); NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - gs_unref_variant GVariant *options = NULL; + gs_unref_variant GVariant *options = user_data; const char *opts_key; GVariant *opts_val; GVariantIter iter; gint32 timeout = 30; - g_variant_get(parameters, "(@a{sv})", &options); + if (error) { + g_dbus_method_invocation_return_gerror(invocation, error); + return; + } g_variant_iter_init(&iter, options); while (g_variant_iter_next(&iter, "{&sv}", &opts_key, &opts_val)) { @@ -1050,17 +1052,43 @@ impl_device_wifi_p2p_start_find(NMDBusObject *obj, } static void -impl_device_wifi_p2p_stop_find(NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended *method_info, - GDBusConnection *connection, - const char *sender, - GDBusMethodInvocation *invocation, - GVariant *parameters) +impl_device_wifi_p2p_start_find(NMDBusObject *obj, + const NMDBusInterfaceInfoExtended *interface_info, + const NMDBusMethodInfoExtended *method_info, + GDBusConnection *connection, + const char *sender, + GDBusMethodInvocation *invocation, + GVariant *parameters) +{ + gs_unref_variant GVariant *options = NULL; + + g_variant_get(parameters, "(@a{sv})", &options); + + nm_device_auth_request(NM_DEVICE(obj), + invocation, + NULL, + NM_AUTH_PERMISSION_WIFI_SCAN, + TRUE, + NULL, + p2p_start_find_auth_cb, + g_steal_pointer(&options)); +} + +static void +p2p_stop_find_auth_cb(NMDevice *device, + GDBusMethodInvocation *invocation, + NMAuthSubject *subject, + GError *error, + gpointer user_data) { - NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P(obj); + NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P(device); NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); + if (error) { + g_dbus_method_invocation_return_gerror(invocation, error); + return; + } + if (!priv->mgmt_iface) { g_dbus_method_invocation_return_error_literal( invocation, @@ -1075,6 +1103,25 @@ impl_device_wifi_p2p_stop_find(NMDBusObject *obj, g_dbus_method_invocation_return_value(invocation, NULL); } +static void +impl_device_wifi_p2p_stop_find(NMDBusObject *obj, + const NMDBusInterfaceInfoExtended *interface_info, + const NMDBusMethodInfoExtended *method_info, + GDBusConnection *connection, + const char *sender, + GDBusMethodInvocation *invocation, + GVariant *parameters) +{ + nm_device_auth_request(NM_DEVICE(obj), + invocation, + NULL, + NM_AUTH_PERMISSION_WIFI_SCAN, + TRUE, + NULL, + p2p_stop_find_auth_cb, + NULL); +} + /*****************************************************************************/ NMSupplicantInterface * @@ -1171,7 +1218,11 @@ static const NMDBusInterfaceInfoExtended interface_info_device_wifi_p2p = { .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_wifi_p2p_peer_added, &nm_signal_info_wifi_p2p_peer_removed, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "HwAddress", + "s", + NM_DEVICE_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Peers", "ao", NM_DEVICE_WIFI_P2P_PEERS), ), ), diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c index 43772834..2cd41b27 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -3191,27 +3191,28 @@ ensure_hotspot_frequency(NMDeviceWifi *self, NMSettingWireless *s_wifi, NMWifiAP GBytes *ssid; gsize ssid_len; const guint8 *ssid_data; - const guint8 random_seed[16] = {0x9a, - 0xdc, - 0x86, - 0x9a, - 0xa8, - 0xa2, - 0x07, - 0x97, - 0xbe, - 0x6d, - 0xe6, - 0x99, - 0x9f, - 0xa8, - 0x09, - 0x2b}; /* Calculate a stable "random" number based on the SSID. */ ssid = nm_setting_wireless_get_ssid(s_wifi); ssid_data = g_bytes_get_data(ssid, &ssid_len); - rnd = c_siphash_hash(random_seed, ssid_data, ssid_len); + rnd = c_siphash_hash(NM_HASH_SEED_16(0x9a, + 0xdc, + 0x86, + 0x9a, + 0xa8, + 0xa2, + 0x07, + 0x97, + 0xbe, + 0x6d, + 0xe6, + 0x99, + 0x9f, + 0xa8, + 0x09, + 0x2b), + ssid_data, + ssid_len); } if (nm_streq0(band, "a")) { diff --git a/src/core/devices/wifi/nm-iwd-manager.c b/src/core/devices/wifi/nm-iwd-manager.c index 0d4daf21..76a342e2 100644 --- a/src/core/devices/wifi/nm-iwd-manager.c +++ b/src/core/devices/wifi/nm-iwd-manager.c @@ -810,7 +810,7 @@ sett_conn_changed(NMSettingsConnection *sett_conn, nm_log_dbg(LOGD_WIFI, "iwd: profile at %s not removed: %s (%i)", orig_full_path, - strerror(errno), + nm_strerror_native(errno), errno); removed = TRUE; @@ -1431,7 +1431,10 @@ try_delete_file: if (g_remove(full_path) == 0) _LOGD("IWD profile at %s removed", full_path); else if (errno != ENOENT) - _LOGD("IWD profile at %s not removed: %s (%i)", full_path, strerror(errno), errno); + _LOGD("IWD profile at %s not removed: %s (%i)", + full_path, + nm_strerror_native(errno), + errno); } static void @@ -1899,7 +1902,7 @@ nm_iwd_manager_get_ap_mirror_connection(NMIwdManager *self, NMWifiAP *ap) NM80211ApSecurityFlags sec_flags = nm_wifi_ap_get_wpa_flags(ap) | nm_wifi_ap_get_rsn_flags(ap); ssid_bytes = g_bytes_get_data(nm_wifi_ap_get_ssid(ap), &ssid_len); - ssid_len = MIN(ssid_len, 32); + ssid_len = NM_MIN(ssid_len, 32u); memcpy(name_buf, ssid_bytes, ssid_len); name_buf[ssid_len] = '\0'; diff --git a/src/core/devices/wifi/nm-wifi-ap.c b/src/core/devices/wifi/nm-wifi-ap.c index 825a5aa8..d4d3815e 100644 --- a/src/core/devices/wifi/nm-wifi-ap.c +++ b/src/core/devices/wifi/nm-wifi-ap.c @@ -36,6 +36,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMWifiAP, PROP_HW_ADDRESS, PROP_MODE, PROP_MAX_BITRATE, + PROP_BANDWIDTH, PROP_STRENGTH, PROP_LAST_SEEN, ); @@ -47,6 +48,7 @@ struct _NMWifiAPPrivate { guint8 strength; guint32 freq; /* Frequency in MHz; ie 2412 (== 2.412 GHz) */ guint32 max_bitrate; /* Maximum bitrate of the AP in Kbit/s (ie 54000 Kb/s == 54Mbit/s) */ + guint32 bandwidth; /* Bandwidth of the AP in MHz */ gint64 last_seen_msec; /* Timestamp when the AP was seen lastly (in nm_utils_get_monotonic_timestamp_*() scale). @@ -277,6 +279,32 @@ nm_wifi_ap_get_max_bitrate(NMWifiAP *ap) return NM_WIFI_AP_GET_PRIVATE(ap)->max_bitrate; } +guint32 +nm_wifi_ap_get_bandwidth(NMWifiAP *ap) +{ + g_return_val_if_fail(NM_IS_WIFI_AP(ap), 0); + g_return_val_if_fail(nm_dbus_object_is_exported(NM_DBUS_OBJECT(ap)), 0); + + return NM_WIFI_AP_GET_PRIVATE(ap)->bandwidth; +} + +gboolean +nm_wifi_ap_set_bandwidth(NMWifiAP *ap, guint32 bandwidth) +{ + NMWifiAPPrivate *priv; + + g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); + + priv = NM_WIFI_AP_GET_PRIVATE(ap); + + if (priv->bandwidth != bandwidth) { + priv->bandwidth = bandwidth; + _notify(ap, PROP_BANDWIDTH); + return TRUE; + } + return FALSE; +} + gboolean nm_wifi_ap_set_max_bitrate(NMWifiAP *ap, guint32 bitrate) { @@ -393,6 +421,7 @@ nm_wifi_ap_update_from_properties(NMWifiAP *ap, const NMSupplicantBssInfo *bss_i } changed |= nm_wifi_ap_set_max_bitrate(ap, bss_info->max_rate); + changed |= nm_wifi_ap_set_bandwidth(ap, bss_info->bandwidth); if (priv->metered != bss_info->metered) { priv->metered = bss_info->metered; @@ -683,6 +712,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) case PROP_MAX_BITRATE: g_value_set_uint(value, priv->max_bitrate); break; + case PROP_BANDWIDTH: + g_value_set_uint(value, priv->bandwidth); + break; case PROP_STRENGTH: g_value_set_uchar(value, priv->strength); break; @@ -873,6 +905,7 @@ static const NMDBusInterfaceInfoExtended interface_info_access_point = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("MaxBitrate", "u", NM_WIFI_AP_MAX_BITRATE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Bandwidth", "u", NM_WIFI_AP_BANDWIDTH), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Strength", "y", NM_WIFI_AP_STRENGTH), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("LastSeen", "i", @@ -979,6 +1012,14 @@ nm_wifi_ap_class_init(NMWifiAPClass *ap_class) -1, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_BANDWIDTH] = g_param_spec_uint(NM_WIFI_AP_BANDWIDTH, + "", + "", + 0, + G_MAXUINT32, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); } diff --git a/src/core/devices/wifi/nm-wifi-ap.h b/src/core/devices/wifi/nm-wifi-ap.h index 93dc8edf..0f229640 100644 --- a/src/core/devices/wifi/nm-wifi-ap.h +++ b/src/core/devices/wifi/nm-wifi-ap.h @@ -27,6 +27,7 @@ #define NM_WIFI_AP_HW_ADDRESS "hw-address" #define NM_WIFI_AP_MODE "mode" #define NM_WIFI_AP_MAX_BITRATE "max-bitrate" +#define NM_WIFI_AP_BANDWIDTH "bandwidth" #define NM_WIFI_AP_STRENGTH "strength" #define NM_WIFI_AP_LAST_SEEN "last-seen" @@ -78,6 +79,8 @@ guint32 nm_wifi_ap_get_freq(NMWifiAP *ap); gboolean nm_wifi_ap_set_freq(NMWifiAP *ap, guint32 freq); guint32 nm_wifi_ap_get_max_bitrate(NMWifiAP *ap); gboolean nm_wifi_ap_set_max_bitrate(NMWifiAP *ap, guint32 bitrate); +guint32 nm_wifi_ap_get_bandwidth(NMWifiAP *ap); +gboolean nm_wifi_ap_set_bandwidth(NMWifiAP *ap, guint32 bandwidth); gboolean nm_wifi_ap_get_fake(const NMWifiAP *ap); gboolean nm_wifi_ap_set_fake(NMWifiAP *ap, gboolean fake); NM80211ApFlags nm_wifi_ap_get_flags(const NMWifiAP *self); diff --git a/src/core/devices/wifi/nm-wifi-common.c b/src/core/devices/wifi/nm-wifi-common.c index 681d9cb5..e3639ec5 100644 --- a/src/core/devices/wifi/nm-wifi-common.c +++ b/src/core/devices/wifi/nm-wifi-common.c @@ -132,7 +132,8 @@ const NMDBusInterfaceInfoExtended nm_interface_info_device_wireless = { NM_DEFINE_GDBUS_METHOD_INFO_INIT( "GetAccessPoints", .out_args = NM_DEFINE_GDBUS_ARG_INFOS( - NM_DEFINE_GDBUS_ARG_INFO("access_points", "ao"), ), ), + NM_DEFINE_GDBUS_ARG_INFO("access_points", "ao"), ), + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), .handle = impl_device_wifi_get_access_points, ), NM_DEFINE_DBUS_METHOD_INFO_EXTENDED( NM_DEFINE_GDBUS_METHOD_INFO_INIT( @@ -150,9 +151,11 @@ const NMDBusInterfaceInfoExtended nm_interface_info_device_wireless = { &nm_signal_info_wireless_access_point_removed, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("PermHwAddress", - "s", - NM_DEVICE_PERM_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "PermHwAddress", + "s", + NM_DEVICE_PERM_HW_ADDRESS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Mode", "u", NM_DEVICE_WIFI_MODE), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Bitrate", "u", NM_DEVICE_WIFI_BITRATE), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AccessPoints", diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index 6978bd3c..4be03f4b 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -527,7 +527,7 @@ _acd_reglist_data_remove(NMDhcpClient *self, guint idx, gboolean do_log) nm_clear_l3cd(®list_data->l3cd); - nm_l3cfg_commit_on_idle_schedule(priv->config.l3cfg, NM_L3_CFG_COMMIT_TYPE_UPDATE); + nm_l3cfg_commit_on_idle_schedule(priv->config.l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO); g_array_remove_index(priv->v4.acd.reglist, idx); diff --git a/src/core/dhcp/nm-dhcp-client.h b/src/core/dhcp/nm-dhcp-client.h index 903ea6ac..4dd2c4fd 100644 --- a/src/core/dhcp/nm-dhcp-client.h +++ b/src/core/dhcp/nm-dhcp-client.h @@ -162,6 +162,9 @@ typedef struct { * will always broadcast replies. */ bool request_broadcast : 1; + /* Whether to send or not the client identifier */ + bool send_client_id : 1; + } v4; struct { /* If set, the DUID from the connection is used; otherwise diff --git a/src/core/dhcp/nm-dhcp-dhclient-utils.c b/src/core/dhcp/nm-dhcp-dhclient-utils.c index ea8943fa..286f7aa1 100644 --- a/src/core/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/core/dhcp/nm-dhcp-dhclient-utils.c @@ -120,7 +120,10 @@ add_ip4_config(GString *str, } g_string_append(str, CLIENTID_TAG " "); - if (i < l) { + if (l == 0) { + /* An empty value effectively unsets the client-id to avoid sending it */ + g_string_append(str, "\"\""); + } else if (i < l) { /* Unprintable; convert to a hex string */ for (i = 0; i < l; i++) { if (i > 0) @@ -293,6 +296,7 @@ char * nm_dhcp_dhclient_create_config(const char *interface, int addr_family, GBytes *client_id, + gboolean send_client_id, const char *anycast_address, const char *hostname, guint32 timeout, @@ -391,8 +395,8 @@ nm_dhcp_dhclient_create_config(const char *interface, continue; if (NM_STR_HAS_PREFIX(p, CLIENTID_TAG)) { - /* Override config file "dhcp-client-id" and use one from the connection */ - if (client_id) + /* Skip "dhcp-client-id" if the connection has defined a custom one or "none" */ + if (client_id || !send_client_id) continue; /* Otherwise, capture and return the existing client id */ @@ -477,6 +481,8 @@ nm_dhcp_dhclient_create_config(const char *interface, } if (addr_family == AF_INET) { + nm_auto_unref_bytes GBytes *client_id_none = NULL; + client_id = send_client_id ? client_id : (client_id_none = g_bytes_new_static("", 0)); add_ip4_config(new_contents, client_id, hostname, use_fqdn, hostname_flags); add_request(reqs, "rfc3442-classless-static-routes"); add_request(reqs, "ms-classless-static-routes"); diff --git a/src/core/dhcp/nm-dhcp-dhclient-utils.h b/src/core/dhcp/nm-dhcp-dhclient-utils.h index 6187cce0..34b26175 100644 --- a/src/core/dhcp/nm-dhcp-dhclient-utils.h +++ b/src/core/dhcp/nm-dhcp-dhclient-utils.h @@ -12,6 +12,7 @@ char *nm_dhcp_dhclient_create_config(const char *interface, int addr_family, GBytes *client_id, + gboolean send_client_id, const char *anycast_addr, const char *hostname, guint32 timeout, diff --git a/src/core/dhcp/nm-dhcp-dhclient.c b/src/core/dhcp/nm-dhcp-dhclient.c index 4aab4b1e..2a3af10a 100644 --- a/src/core/dhcp/nm-dhcp-dhclient.c +++ b/src/core/dhcp/nm-dhcp-dhclient.c @@ -148,56 +148,6 @@ get_dhclient_leasefile(int addr_family, return NULL; } -static gboolean -merge_dhclient_config(NMDhcpDhclient *self, - int addr_family, - const char *iface, - const char *conf_file, - GBytes *client_id, - const char *anycast_address, - const char *hostname, - guint32 timeout, - gboolean use_fqdn, - NMDhcpHostnameFlags hostname_flags, - const char *mud_url, - const char *const *reject_servers, - const char *orig_path, - GBytes **out_new_client_id, - GError **error) -{ - gs_free char *orig = NULL; - gs_free char *new = NULL; - - g_return_val_if_fail(iface, FALSE); - g_return_val_if_fail(conf_file, FALSE); - - if (orig_path && g_file_test(orig_path, G_FILE_TEST_EXISTS)) { - GError *read_error = NULL; - - if (!g_file_get_contents(orig_path, &orig, NULL, &read_error)) { - _LOGW("error reading dhclient configuration %s: %s", orig_path, read_error->message); - g_error_free(read_error); - } - } - - new = nm_dhcp_dhclient_create_config(iface, - addr_family, - client_id, - anycast_address, - hostname, - timeout, - use_fqdn, - hostname_flags, - mud_url, - reject_servers, - orig_path, - orig, - out_new_client_id); - nm_assert(new); - - return g_file_set_contents(conf_file, new, -1, error); -} - static char * find_existing_config(NMDhcpDhclient *self, int addr_family, const char *iface, const char *uuid) { @@ -283,6 +233,7 @@ create_dhclient_config(NMDhcpDhclient *self, const char *iface, const char *uuid, GBytes *client_id, + gboolean send_client_id, const char *anycast_address, const char *hostname, guint32 timeout, @@ -292,44 +243,56 @@ create_dhclient_config(NMDhcpDhclient *self, const char *const *reject_servers, GBytes **out_new_client_id) { - gs_free char *orig = NULL; - char *new = NULL; - GError *error = NULL; + gs_free char *orig_path = NULL; + gs_free char *orig_content = NULL; + char *new_path = NULL; + gs_free char *new_content = NULL; + GError *error = NULL; g_return_val_if_fail(iface != NULL, NULL); - new = g_strdup_printf(NMSTATEDIR "/dhclient%s-%s.conf", - _addr_family_to_path_part(addr_family), - iface); - - _LOGD("creating composite dhclient config %s", new); + new_path = g_strdup_printf(NMSTATEDIR "/dhclient%s-%s.conf", + _addr_family_to_path_part(addr_family), + iface); + _LOGD("creating composite dhclient config %s", new_path); - orig = find_existing_config(self, addr_family, iface, uuid); - if (orig) - _LOGD("merging existing dhclient config %s", orig); + orig_path = find_existing_config(self, addr_family, iface, uuid); + if (orig_path) + _LOGD("merging existing dhclient config %s", orig_path); else _LOGD("no existing dhclient configuration to merge"); - if (!merge_dhclient_config(self, - addr_family, - iface, - new, - client_id, - anycast_address, - hostname, - timeout, - use_fqdn, - hostname_flags, - mud_url, - reject_servers, - orig, - out_new_client_id, - &error)) { + if (orig_path && g_file_test(orig_path, G_FILE_TEST_EXISTS)) { + if (!g_file_get_contents(orig_path, &orig_content, NULL, &error)) { + _LOGW("error reading dhclient configuration %s: %s", orig_path, error->message); + g_error_free(error); + } + } + + new_content = nm_dhcp_dhclient_create_config(iface, + addr_family, + client_id, + send_client_id, + anycast_address, + hostname, + timeout, + use_fqdn, + hostname_flags, + mud_url, + reject_servers, + orig_path, + orig_content, + out_new_client_id); + nm_assert(new_content); + + if (!g_file_set_contents(new_path, new_content, -1, &error)) { _LOGW("error creating dhclient configuration: %s", error->message); - g_clear_error(&error); + g_error_free(error); + g_free(new_path); + return NULL; } - return new; + return new_path; } static gboolean @@ -547,11 +510,14 @@ ip4_start(NMDhcpClient *client, GError **error) client_config = nm_dhcp_client_get_config(client); + nm_assert(client_config->addr_family == AF_INET); + priv->conf_file = create_dhclient_config(self, AF_INET, client_config->iface, client_config->uuid, client_config->client_id, + client_config->v4.send_client_id, client_config->anycast_address, client_config->hostname, client_config->timeout, @@ -584,6 +550,8 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error) config = nm_dhcp_client_get_config(client); + nm_assert(config->addr_family == AF_INET6); + if (config->v6.iaid_explicit) _LOGW("dhclient does not support specifying an IAID for DHCPv6, it will be ignored"); @@ -592,6 +560,7 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error) config->iface, config->uuid, NULL, + TRUE, config->anycast_address, config->hostname, config->timeout, diff --git a/src/core/dhcp/nm-dhcp-dhcpcd.c b/src/core/dhcp/nm-dhcp-dhcpcd.c index 8d2f928b..7c95994a 100644 --- a/src/core/dhcp/nm-dhcp-dhcpcd.c +++ b/src/core/dhcp/nm-dhcp-dhcpcd.c @@ -174,7 +174,7 @@ stop(NMDhcpClient *client, gboolean release) */ if (kill(pid, sig) == -1) { errsv = errno; - _LOGE("failed to kill dhcpcd %d:%s", errsv, strerror(errsv)); + _LOGE("failed to kill dhcpcd %d:%s", errsv, nm_strerror_native(errsv)); } /* When this function exits NM expects the PID to be -1. diff --git a/src/core/dhcp/nm-dhcp-helper.c b/src/core/dhcp/nm-dhcp-helper.c index ee95abb7..9e4cedf2 100644 --- a/src/core/dhcp/nm-dhcp-helper.c +++ b/src/core/dhcp/nm-dhcp-helper.c @@ -159,7 +159,7 @@ do_connect: error->message, try_count, (long long) (time_end - remaining_time - time_start) / 1000); - interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31))), 5000, 100000); + interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31u))), 5000, 100000); g_usleep(NM_MIN(interval, remaining_time)); g_clear_error(&error); goto do_connect; @@ -222,7 +222,7 @@ do_notify: gint64 interval; _LOGi("failure to call notify: %s (retry %u)", error->message, try_count); - interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31))), 5000, 25000); + interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31u))), 5000, 25000); g_usleep(NM_MIN(interval, remaining_time)); g_clear_error(&error); goto do_notify; diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c index f36dfb4d..fc468d4c 100644 --- a/src/core/dhcp/nm-dhcp-nettools.c +++ b/src/core/dhcp/nm-dhcp-nettools.c @@ -1119,6 +1119,7 @@ nettools_create(NMDhcpNettools *self, GBytes **out_effective_client_id, GError * gs_unref_bytes GBytes *client_id_new = NULL; const uint8_t *client_id_arr; size_t client_id_len; + bool send_client_id; int r, fd, arp_type, transport; const NMDhcpClientConfig *client_config; @@ -1150,20 +1151,37 @@ nettools_create(NMDhcpNettools *self, GBytes **out_effective_client_id, GError * return FALSE; } - /* Note that we always set a client-id. In particular for infiniband that is necessary, - * see https://tools.ietf.org/html/rfc4390#section-2.1 . */ - client_id = client_config->client_id; - if (!client_id) { + client_id = client_config->client_id; + send_client_id = client_config->v4.send_client_id; + + if (!send_client_id && transport == N_DHCP4_TRANSPORT_INFINIBAND) { + /* Client-id is mandatory for infiniband: https://tools.ietf.org/html/rfc4390#section-2.1 */ + _LOGI("ipv4.client-id is set to \"none\", but it's mandatory for Infiniband. Setting a " + "default one."); + send_client_id = TRUE; + } + + if (send_client_id && !client_id) { client_id_new = nm_utils_dhcp_client_id_mac(arp_type, hwaddr_arr, hwaddr_len); client_id = client_id_new; } - if (!(client_id_arr = g_bytes_get_data(client_id, &client_id_len)) || client_id_len < 2) { - /* invalid client-ids are not expected. */ - nm_assert_not_reached(); + g_return_val_if_fail(client_id || !send_client_id, FALSE); - nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "no valid IPv4 client-id"); - return FALSE; + if (send_client_id) { + client_id_arr = g_bytes_get_data(client_id, &client_id_len); + client_id_len = NM_MIN(client_id_len, 1 + _NM_MAX_CLIENT_ID_LEN); + + if (!client_id_arr || client_id_len < 2) { + /* invalid client-ids are not expected. */ + nm_assert_not_reached(); + nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "no valid IPv4 client-id"); + return FALSE; + } + } else { + client_id_arr = NULL; + /* This will unset the client-id and prevent it from being sent */ + client_id_len = 0; } r = n_dhcp4_client_config_new(&config); @@ -1177,9 +1195,7 @@ nettools_create(NMDhcpNettools *self, GBytes **out_effective_client_id, GError * n_dhcp4_client_config_set_mac(config, hwaddr_arr, hwaddr_len); n_dhcp4_client_config_set_broadcast_mac(config, bcast_hwaddr_arr, bcast_hwaddr_len); n_dhcp4_client_config_set_request_broadcast(config, client_config->v4.request_broadcast); - r = n_dhcp4_client_config_set_client_id(config, - client_id_arr, - NM_MIN(client_id_len, 1 + _NM_MAX_CLIENT_ID_LEN)); + r = n_dhcp4_client_config_set_client_id(config, client_id_arr, client_id_len); if (r) { set_error_nettools(error, r, "failed to set client-id"); return FALSE; diff --git a/src/core/dhcp/tests/test-dhcp-dhclient.c b/src/core/dhcp/tests/test-dhcp-dhclient.c index e95f218e..0edcc296 100644 --- a/src/core/dhcp/tests/test-dhcp-dhclient.c +++ b/src/core/dhcp/tests/test-dhcp-dhclient.c @@ -36,11 +36,14 @@ test_config(const char *orig, const char *anycast_addr, const char *mud_url) { - gs_free char *new = NULL; - gs_unref_bytes GBytes *client_id = NULL; - gs_unref_bytes GBytes *new_client_id = NULL; - - if (dhcp_client_id) { + gs_free char *new = NULL; + gs_unref_bytes GBytes *client_id = NULL; + gs_unref_bytes GBytes *new_client_id = NULL; + gboolean send_client_id = TRUE; + + if (nm_streq0(dhcp_client_id, "none")) { + send_client_id = FALSE; + } else if (dhcp_client_id) { client_id = nm_dhcp_utils_client_id_string_to_bytes(dhcp_client_id); g_assert(client_id); } @@ -48,6 +51,7 @@ test_config(const char *orig, new = nm_dhcp_dhclient_create_config(iface, addr_family, client_id, + send_client_id, anycast_addr, hostname, timeout, @@ -502,6 +506,90 @@ test_existing_ascii_client_id(void) NULL, NULL); } + +/*****************************************************************************/ + +static const char *none_client_id_orig = "send dhcp-client-identifier 10:30:04:20:7A:08;\n"; + +static const char *none_client_id_expected = + "# Created by NetworkManager\n" + "# Merged from /path/to/dhclient.conf\n" + "\n" + "send dhcp-client-identifier \"\"; # added by NetworkManager\n" + "\n" + "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" + "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" + "option wpad code 252 = string;\n" + "\n" + "also request rfc3442-classless-static-routes;\n" + "also request ms-classless-static-routes;\n" + "also request static-routes;\n" + "also request wpad;\n" + "also request ntp-servers;\n" + "also request root-path;\n" + "\n"; + +static void +test_none_client_id(void) +{ + const char *connection_client_id = "none"; + gs_unref_bytes GBytes *expected_client_id = NULL; + + test_config(none_client_id_orig, + none_client_id_expected, + AF_INET, + NULL, + 0, + FALSE, + NM_DHCP_HOSTNAME_FLAG_NONE, + connection_client_id, + expected_client_id, + "eth0", + NULL, + NULL); +} + +/*****************************************************************************/ + +static const char *missing_client_id_orig = ""; + +static const char *missing_client_id_expected = + "# Created by NetworkManager\n" + "# Merged from /path/to/dhclient.conf\n" + "\n" + "\n" + "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" + "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" + "option wpad code 252 = string;\n" + "\n" + "also request rfc3442-classless-static-routes;\n" + "also request ms-classless-static-routes;\n" + "also request static-routes;\n" + "also request wpad;\n" + "also request ntp-servers;\n" + "also request root-path;\n" + "\n"; + +static void +test_missing_client_id(void) +{ + const char *connection_client_id = NULL; + gs_unref_bytes GBytes *expected_client_id = NULL; + + test_config(missing_client_id_orig, + missing_client_id_expected, + AF_INET, + NULL, + 0, + FALSE, + NM_DHCP_HOSTNAME_FLAG_NONE, + connection_client_id, + expected_client_id, + "eth0", + NULL, + NULL); +} + /*****************************************************************************/ static const char *fqdn_expected = @@ -1364,6 +1452,8 @@ main(int argc, char **argv) g_test_add_func("/dhcp/dhclient/existing-hex-client-id", test_existing_hex_client_id); g_test_add_func("/dhcp/dhclient/existing-client-id", test_existing_escaped_client_id); g_test_add_func("/dhcp/dhclient/existing-ascii-client-id", test_existing_ascii_client_id); + g_test_add_func("/dhcp/dhclient/none-client-id", test_none_client_id); + g_test_add_func("/dhcp/dhclient/missing-client-id", test_missing_client_id); g_test_add_func("/dhcp/dhclient/fqdn", test_fqdn); g_test_add_func("/dhcp/dhclient/fqdn_options_override", test_fqdn_options_override); g_test_add_func("/dhcp/dhclient/override_hostname", test_override_hostname); diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c index 53564693..8f87fec1 100644 --- a/src/core/dns/nm-dns-manager.c +++ b/src/core/dns/nm-dns-manager.c @@ -543,7 +543,7 @@ add_string_item(GPtrArray *array, const char *str, gboolean dup) static void add_dns_option_item(GPtrArray *array, const char *str) { - if (_nm_utils_dns_option_find_idx(array, str) < 0) + if (_nm_utils_dns_option_find_idx((const char *const *) array->pdata, array->len, str) < 0) g_ptr_array_add(array, g_strdup(str)); } @@ -1876,8 +1876,11 @@ plugin_skip:; nameservers = g_new0(char *, 2); nameservers[0] = g_strdup(lladdr); - need_edns0 = nm_strv_find_first(options, -1, NM_SETTING_DNS_OPTION_EDNS0) < 0; - need_trust = nm_strv_find_first(options, -1, NM_SETTING_DNS_OPTION_TRUST_AD) < 0; + need_edns0 = !nm_strv_contains(options, -1, NM_SETTING_DNS_OPTION_EDNS0) + && !nm_strv_contains(options, -1, NM_SETTING_DNS_OPTION_INTERNAL_NO_ADD_EDNS0); + need_trust = + !nm_strv_contains(options, -1, NM_SETTING_DNS_OPTION_TRUST_AD) + && !nm_strv_contains(options, -1, NM_SETTING_DNS_OPTION_INTERNAL_NO_ADD_TRUST_AD); if (need_edns0 || need_trust) { gsize len; @@ -1892,6 +1895,23 @@ plugin_skip:; } } + if (options) { + guint i; + guint j; + + /* Skip internal options, those starting with '_' */ + for (i = 0, j = 0; options[i]; i++) { + if (options[i][0] == '_') { + g_free(options[i]); + continue; + } + if (i != j) + options[j] = options[i]; + j++; + } + options[j] = NULL; + } + if (do_update) { switch (priv->rc_manager) { case NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK: @@ -1948,7 +1968,7 @@ plugin_skip:; } /* signal that DNS resolution configs were changed */ - if ((do_update || caching || force_emit) && result == SR_SUCCESS) + if ((caching || force_emit) && result == SR_SUCCESS) g_signal_emit(self, signals[CONFIG_CHANGED], 0); nm_clear_pointer(&priv->config_variant, g_variant_unref); @@ -1964,6 +1984,16 @@ plugin_skip:; return TRUE; } +gboolean +nm_dns_manager_is_unmanaged(NMDnsManager *self) +{ + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self); + + return NM_IN_SET(priv->rc_manager, + NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED, + NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE); +} + /*****************************************************************************/ gboolean @@ -2391,7 +2421,7 @@ _resolvconf_resolved_managed(void) * We want to handle that, because systemd-resolved might not * have started yet. */ full_path = g_file_read_link(_PATH_RESCONF, NULL); - if (nm_strv_find_first(RESOLVED_PATHS, G_N_ELEMENTS(RESOLVED_PATHS), full_path) >= 0) + if (nm_strv_contains(RESOLVED_PATHS, G_N_ELEMENTS(RESOLVED_PATHS), full_path)) return TRUE; /* see if resolv.conf is a symlink that resolves exactly one @@ -2403,7 +2433,7 @@ _resolvconf_resolved_managed(void) * We want to handle that, because systemd-resolved might not * have started yet. */ real_path = realpath(_PATH_RESCONF, NULL); - if (nm_strv_find_first(RESOLVED_PATHS, G_N_ELEMENTS(RESOLVED_PATHS), real_path) >= 0) + if (nm_strv_contains(RESOLVED_PATHS, G_N_ELEMENTS(RESOLVED_PATHS), real_path)) return TRUE; /* fall-through and resolve the symlink, to check the file diff --git a/src/core/dns/nm-dns-manager.h b/src/core/dns/nm-dns-manager.h index 42f9dec5..9b8c2972 100644 --- a/src/core/dns/nm-dns-manager.h +++ b/src/core/dns/nm-dns-manager.h @@ -148,4 +148,6 @@ char *nmtst_dns_create_resolv_conf(const char *const *searches, const char *const *nameservers, const char *const *options); +gboolean nm_dns_manager_is_unmanaged(NMDnsManager *self); + #endif /* __NETWORKMANAGER_DNS_MANAGER_H__ */ diff --git a/src/core/dnsmasq/nm-dnsmasq-utils.c b/src/core/dnsmasq/nm-dnsmasq-utils.c index 69424d74..8d15c2e3 100644 --- a/src/core/dnsmasq/nm-dnsmasq-utils.c +++ b/src/core/dnsmasq/nm-dnsmasq-utils.c @@ -83,12 +83,12 @@ nm_dnsmasq_utils_get_range(const NMPlatformIP4Address *addr, mid = (host & netmask) | (((first + last) / 2) & ~netmask); if (host > mid) { /* use lower range */ - reserved = NM_MIN(((host - first) / 10), 8); + reserved = NM_MIN(((host - first) / 10u), 8u); last = host - 1 - reserved; first = NM_MAX(first, last > NUM ? last - NUM : 0); } else { /* use upper range */ - reserved = NM_MIN(((last - host) / 10), 8); + reserved = NM_MIN(((last - host) / 10u), 8u); first = host + 1 + reserved; last = NM_MIN(last, first < 0xFFFFFFFF - NUM ? first + NUM : 0xFFFFFFFF); } diff --git a/src/core/main-utils.c b/src/core/main-utils.c index 9360d688..0f62da29 100644 --- a/src/core/main-utils.c +++ b/src/core/main-utils.c @@ -192,10 +192,7 @@ nm_main_utils_ensure_not_running_pidfile(const char *pidfile) if (strcmp(process_name, prgname) == 0) { /* Check that the process exists */ if (kill(pid, 0) == 0) { - fprintf(stderr, - _("%s is already running (pid %" G_GINT64_FORMAT ")\n"), - prgname, - (gint64) pid); + fprintf(stderr, _("%s is already running (pid %lld)\n"), prgname, (long long) pid); exit(1); } } diff --git a/src/core/meson.build b/src/core/meson.build index 6c1d463e..45b068a6 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -102,6 +102,7 @@ libNetworkManager = static_library( 'devices/nm-device-ethernet-utils.c', 'devices/nm-device-factory.c', 'devices/nm-device-generic.c', + 'devices/nm-device-hsr.c', 'devices/nm-device-infiniband.c', 'devices/nm-device-ip-tunnel.c', 'devices/nm-device-loopback.c', diff --git a/src/core/ndisc/nm-fake-ndisc.c b/src/core/ndisc/nm-fake-ndisc.c index f305e771..f0b6dcf6 100644 --- a/src/core/ndisc/nm-fake-ndisc.c +++ b/src/core/ndisc/nm-fake-ndisc.c @@ -239,7 +239,7 @@ receive_ra(gpointer user_data) priv->receive_ra_id = 0; /* preserve the "most managed" level on updates. */ - dhcp_level = MAX(rdata->public.dhcp_level, ra->dhcp_level); + dhcp_level = NM_MAX(rdata->public.dhcp_level, ra->dhcp_level); if (rdata->public.dhcp_level != dhcp_level) { rdata->public.dhcp_level = dhcp_level; diff --git a/src/core/ndisc/nm-lndp-ndisc.c b/src/core/ndisc/nm-lndp-ndisc.c index 63dde5a5..932366ff 100644 --- a/src/core/ndisc/nm-lndp-ndisc.c +++ b/src/core/ndisc/nm-lndp-ndisc.c @@ -161,7 +161,7 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) * let's keep the "most managed" level. */ G_STATIC_ASSERT_EXPR(NM_NDISC_DHCP_LEVEL_MANAGED > NM_NDISC_DHCP_LEVEL_OTHERCONF); G_STATIC_ASSERT_EXPR(NM_NDISC_DHCP_LEVEL_OTHERCONF > NM_NDISC_DHCP_LEVEL_NONE); - dhcp_level = MAX(dhcp_level, rdata->public.dhcp_level); + dhcp_level = NM_MAX(dhcp_level, rdata->public.dhcp_level); if (dhcp_level != rdata->public.dhcp_level) { rdata->public.dhcp_level = dhcp_level; diff --git a/src/core/ndisc/nm-ndisc.c b/src/core/ndisc/nm-ndisc.c index 20dd2121..c8f7ed0c 100644 --- a/src/core/ndisc/nm-ndisc.c +++ b/src/core/ndisc/nm-ndisc.c @@ -1293,10 +1293,8 @@ nm_ndisc_dad_failed(NMNDisc *ndisc, GArray *addresses, gboolean emit_changed_sig NMNDiscAddress *item = &nm_g_array_index(rdata->addresses, NMNDiscAddress, j); if (IN6_ARE_ADDR_EQUAL(&item->address, addr)) { - char sbuf[NM_INET_ADDRSTRLEN]; - - _LOGI("DAD failed for discovered address %s", nm_inet6_ntop(addr, sbuf)); changed = TRUE; + if (!complete_address(ndisc, item)) { g_array_remove_index(rdata->addresses, j); continue; diff --git a/src/core/nm-act-request.c b/src/core/nm-act-request.c index dce18ba4..bed7ffde 100644 --- a/src/core/nm-act-request.c +++ b/src/core/nm-act-request.c @@ -259,7 +259,8 @@ static void device_state_changed(NMActiveConnection *active, NMDevice *device, NMDeviceState new_state, - NMDeviceState old_state) + NMDeviceState old_state, + NMDeviceStateReason reason) { NMActiveConnectionState cur_ac_state = nm_active_connection_get_state(active); NMActiveConnectionState ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; @@ -319,14 +320,20 @@ device_state_changed(NMActiveConnection *active, active); break; case NM_DEVICE_STATE_DEACTIVATING: + if (reason == NM_DEVICE_STATE_REASON_USER_REQUESTED) + ac_state_reason = NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED; + ac_state = NM_ACTIVE_CONNECTION_STATE_DEACTIVATING; break; case NM_DEVICE_STATE_FAILED: case NM_DEVICE_STATE_DISCONNECTED: case NM_DEVICE_STATE_UNMANAGED: case NM_DEVICE_STATE_UNAVAILABLE: - ac_state = NM_ACTIVE_CONNECTION_STATE_DEACTIVATED; - ac_state_reason = NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED; + ac_state = NM_ACTIVE_CONNECTION_STATE_DEACTIVATED; + if (reason == NM_DEVICE_STATE_REASON_USER_REQUESTED) + ac_state_reason = NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED; + else + ac_state_reason = NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED; g_signal_handlers_disconnect_by_func(device, G_CALLBACK(device_notify), active); break; diff --git a/src/core/nm-active-connection.c b/src/core/nm-active-connection.c index 36a11f71..eb7b1cca 100644 --- a/src/core/nm-active-connection.c +++ b/src/core/nm-active-connection.c @@ -636,7 +636,8 @@ device_state_changed(NMDevice *device, NM_ACTIVE_CONNECTION_GET_CLASS(self)->device_state_changed(self, device, new_state, - old_state); + old_state, + reason); } static void @@ -1604,9 +1605,11 @@ static const NMDBusInterfaceInfoExtended interface_info_active_connection = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Controller", "o", NM_ACTIVE_CONNECTION_CONTROLLER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Master", - "o", - NM_ACTIVE_CONNECTION_MASTER), ), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Master", + "o", + NM_ACTIVE_CONNECTION_MASTER, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), ), ), }; static void diff --git a/src/core/nm-active-connection.h b/src/core/nm-active-connection.h index 15db68c3..8032294f 100644 --- a/src/core/nm-active-connection.h +++ b/src/core/nm-active-connection.h @@ -78,7 +78,8 @@ typedef struct { void (*device_state_changed)(NMActiveConnection *connection, NMDevice *device, NMDeviceState new_state, - NMDeviceState old_state); + NMDeviceState old_state, + NMDeviceStateReason reason); void (*master_failed)(NMActiveConnection *connection); void (*device_changed)(NMActiveConnection *connection, diff --git a/src/core/nm-auth-utils.c b/src/core/nm-auth-utils.c index 7739f443..aa2547b3 100644 --- a/src/core/nm-auth-utils.c +++ b/src/core/nm-auth-utils.c @@ -8,6 +8,7 @@ #include "nm-auth-utils.h" #include "libnm-glib-aux/nm-c-list.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-setting-connection.h" #include "libnm-core-aux-intern/nm-auth-subject.h" #include "nm-auth-manager.h" @@ -603,7 +604,6 @@ gboolean nm_auth_is_subject_in_acl(NMConnection *connection, NMAuthSubject *subject, char **out_error_desc) { NMSettingConnection *s_con; - gs_free char *user = NULL; gulong uid; g_return_val_if_fail(connection, FALSE); @@ -621,13 +621,6 @@ nm_auth_is_subject_in_acl(NMConnection *connection, NMAuthSubject *subject, char if (0 == uid) return TRUE; - user = nm_utils_uid_to_name(uid); - if (!user) { - NM_SET_OUT(out_error_desc, - g_strdup_printf("Could not determine username for uid %lu", uid)); - return FALSE; - } - s_con = nm_connection_get_setting_connection(connection); if (!s_con) { /* This can only happen when called from AddAndActivate, so we know @@ -637,7 +630,7 @@ nm_auth_is_subject_in_acl(NMConnection *connection, NMAuthSubject *subject, char } /* Match the username returned by the session check to a user in the ACL */ - if (!nm_setting_connection_permissions_user_allowed(s_con, user)) { + if (!nm_setting_connection_permissions_user_allowed_by_uid(s_con, uid)) { NM_SET_OUT(out_error_desc, g_strdup_printf("uid %lu has no permission to perform this operation", uid)); return FALSE; diff --git a/src/core/nm-config-data.c b/src/core/nm-config-data.c index ed6d8381..468e56b8 100644 --- a/src/core/nm-config-data.c +++ b/src/core/nm-config-data.c @@ -1219,7 +1219,7 @@ load_global_dns(GKeyFile *keyfile, gboolean internal) if (strv) { nm_strv_cleanup(strv, TRUE, TRUE, TRUE); for (i = 0, j = 0; strv[i]; i++) { - if (_nm_utils_dns_option_validate(strv[i], NULL, NULL, TRUE, NULL)) + if (_nm_utils_dns_option_validate(strv[i], NULL, NULL, AF_UNSPEC, NULL)) strv[j++] = strv[i]; else g_free(strv[i]); @@ -1453,7 +1453,7 @@ nm_global_dns_config_from_dbus(const GValue *value, GError **error) nm_strv_cleanup(strv, TRUE, TRUE, TRUE); for (i = 0, j = 0; strv && strv[i]; i++) { - if (_nm_utils_dns_option_validate(strv[i], NULL, NULL, TRUE, NULL)) + if (_nm_utils_dns_option_validate(strv[i], NULL, NULL, AF_UNSPEC, NULL)) strv[j++] = strv[i]; else g_free(strv[i]); diff --git a/src/core/nm-config.c b/src/core/nm-config.c index b8df41b7..5db4a92a 100644 --- a/src/core/nm-config.c +++ b/src/core/nm-config.c @@ -858,7 +858,6 @@ static const ConfigGroup config_groups[] = { NM_CONFIG_KEYFILE_KEY_MAIN_NO_AUTO_DEFAULT, NM_CONFIG_KEYFILE_KEY_MAIN_PLUGINS, NM_CONFIG_KEYFILE_KEY_MAIN_RC_MANAGER, - NM_CONFIG_KEYFILE_KEY_MAIN_SLAVES_ORDER, NM_CONFIG_KEYFILE_KEY_MAIN_SYSTEMD_RESOLVED, ), }, { @@ -1129,12 +1128,12 @@ read_config(GKeyFile *keyfile, /* merge the string lists, by omitting duplicates. */ for (iter_val = old_val; iter_val && *iter_val; iter_val++) { - if (last_char != '-' || nm_strv_find_first(new_val, -1, *iter_val) < 0) + if (last_char != '-' || !nm_strv_contains(new_val, -1, *iter_val)) g_ptr_array_add(new, g_strdup(*iter_val)); } for (iter_val = new_val; iter_val && *iter_val; iter_val++) { /* don't add duplicates. That means an "option=a,b"; "option+=a,c" results in "option=a,b,c" */ - if (last_char == '+' && nm_strv_find_first(old_val, -1, *iter_val) < 0) + if (last_char == '+' && !nm_strv_contains(old_val, -1, *iter_val)) g_ptr_array_add(new, *iter_val); else g_free(*iter_val); @@ -3019,8 +3018,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps gboolean nm_config_kernel_command_line_nm_debug(void) { - return (nm_strv_find_first(nm_utils_proc_cmdline_split(), -1, NM_CONFIG_KERNEL_CMDLINE_NM_DEBUG) - >= 0); + return nm_strv_contains(nm_utils_proc_cmdline_split(), -1, NM_CONFIG_KERNEL_CMDLINE_NM_DEBUG); } /*****************************************************************************/ diff --git a/src/core/nm-connectivity.c b/src/core/nm-connectivity.c index 92de44f1..15dc31aa 100644 --- a/src/core/nm-connectivity.c +++ b/src/core/nm-connectivity.c @@ -79,9 +79,9 @@ struct _NMConnectivityCheckHandle { struct curl_slist *request_headers; struct curl_slist *hosts; - gsize response_good_cnt; + GSource *curl_timer; - guint curl_timer; + gsize response_good_cnt; } concheck; #endif @@ -241,7 +241,7 @@ cb_data_complete(NMConnectivityCheckHandle *cb_data, curl_slist_free_all(cb_data->concheck.request_headers); curl_slist_free_all(cb_data->concheck.hosts); } - nm_clear_g_source(&cb_data->concheck.curl_timer); + nm_clear_g_source_inst(&cb_data->concheck.curl_timer); nm_clear_g_cancellable(&cb_data->concheck.resolve_cancellable); #endif @@ -406,6 +406,7 @@ _con_curl_timeout_cb(gpointer user_data) { NMConnectivityCheckHandle *cb_data = user_data; + nm_clear_g_source_inst(&cb_data->concheck.curl_timer); _con_curl_check_connectivity(cb_data->concheck.curl_mhandle, CURL_SOCKET_TIMEOUT, 0); _complete_queued(cb_data->self); return G_SOURCE_CONTINUE; @@ -416,9 +417,11 @@ multi_timer_cb(CURLM *multi, long timeout_msec, void *userdata) { NMConnectivityCheckHandle *cb_data = userdata; - nm_clear_g_source(&cb_data->concheck.curl_timer); - if (timeout_msec != -1) - cb_data->concheck.curl_timer = g_timeout_add(timeout_msec, _con_curl_timeout_cb, cb_data); + nm_clear_g_source_inst(&cb_data->concheck.curl_timer); + if (timeout_msec != -1) { + cb_data->concheck.curl_timer = + nm_g_timeout_add_source(timeout_msec, _con_curl_timeout_cb, cb_data); + } return 0; } @@ -1292,7 +1295,7 @@ update_config(NMConnectivity *self, NMConfigData *config_data) priv->uri_valid = new_uri_valid; interval = nm_config_data_get_connectivity_interval(config_data); - interval = MIN(interval, (7 * 24 * 3600)); + interval = NM_MIN(interval, (7u * 24 * 3600)); if (priv->interval != interval) { priv->interval = interval; changed = TRUE; diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index 5442efbf..178ea3c4 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -738,19 +738,20 @@ nm_utils_kill_child_sync(pid_t pid, if (!was_waiting) { nm_log_dbg(log_domain, - LOG_NAME_FMT ": waiting up to %ld milliseconds for process to terminate " + LOG_NAME_FMT ": waiting up to %lu milliseconds for process to terminate " "normally after sending %s...", LOG_NAME_ARGS, - (long) MAX(wait_before_kill_msec, 0), + (unsigned long) wait_before_kill_msec, _kc_signal_to_string(sig)); was_waiting = TRUE; } - sleep_time = MIN(wait_until - now, sleep_duration_usec); + sleep_time = NM_MIN(wait_until - now, (gint64) sleep_duration_usec); if (loop_count < 20) { /* At the beginning we expect the process to die fast. * Limit the sleep time, the limit doubles with every iteration. */ - sleep_time = MIN(sleep_time, (((guint64) 1) << loop_count) * G_USEC_PER_SEC / 2000); + sleep_time = + NM_MIN(sleep_time, (((guint64) 1) << loop_count) * G_USEC_PER_SEC / 2000); loop_count++; } g_usleep(sleep_time); @@ -1031,17 +1032,17 @@ nm_utils_kill_process_sync(pid_t pid, loop_count = 0; /* reset the loop_count. Now we really expect the process to die quickly. */ } else - sleep_time = MIN(wait_until_sigkill - now, sleep_duration_usec); + sleep_time = NM_MIN(wait_until_sigkill - now, (gint64) sleep_duration_usec); } if (!was_waiting) { if (wait_until_sigkill != 0) { nm_log_dbg(log_domain, LOG_NAME_PROCESS_FMT - ": waiting up to %ld milliseconds for process to disappear before " + ": waiting up to %lu milliseconds for process to disappear before " "sending KILL signal after sending %s...", LOG_NAME_ARGS, - (long) wait_before_kill_msec, + (unsigned long) wait_before_kill_msec, _kc_signal_to_string(sig)); } else if (max_wait_until != 0) { nm_log_dbg( @@ -1064,7 +1065,7 @@ nm_utils_kill_process_sync(pid_t pid, if (loop_count < 20) { /* At the beginning we expect the process to die fast. * Limit the sleep time, the limit doubles with every iteration. */ - sleep_time = MIN(sleep_time, (((guint64) 1) << loop_count) * G_USEC_PER_SEC / 2000); + sleep_time = NM_MIN(sleep_time, (((guint64) 1) << loop_count) * G_USEC_PER_SEC / 2000); loop_count++; } g_usleep(sleep_time); @@ -2711,7 +2712,7 @@ _host_id_read_timestamp(gboolean use_secret_key_file, #define EPOCH_TWO_YEARS (G_GINT64_CONSTANT(2 * 365 * 24 * 3600) * NM_UTILS_NSEC_PER_SEC) - v = nm_hash_siphash42(1156657133u, host_id, host_id_len); + v = c_siphash_hash(NM_HASH_SEED_16_U64(1156657133u), host_id, host_id_len); now = time(NULL); *out_timestamp_ns = @@ -3396,6 +3397,7 @@ nm_utils_stable_id_parse(const char *stable_id, const char *hwaddr, const char *bootid, const char *uuid, + GBytes *ssid, char **out_generated) { nm_auto_str_buf NMStrBuf str = NM_STR_BUF_INIT_A(NM_UTILS_GET_NEXT_REALLOC_SIZE_232, FALSE); @@ -3481,7 +3483,29 @@ nm_utils_stable_id_parse(const char *stable_id, _stable_id_append(&str, deviceid); else if (CHECK_PREFIX("${MAC}")) _stable_id_append(&str, hwaddr); - else if (g_str_has_prefix(&stable_id[i], "${RANDOM}")) { + else if (CHECK_PREFIX("${NETWORK_SSID}")) { + gs_free char *value_free = NULL; + gs_free char *s = NULL; + const char *value; + const char *type_id; + + if (ssid) { + type_id = "s:"; + value = nm_utils_buf_utf8safe_escape_bytes(ssid, + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, + &value_free); + } else { + /* If we have no SSID, we fallback to the connection's UUID. + * + * Give a separate prefix (@type_id), so that an SSID and a UUID + * fallback never result in the same output. */ + type_id = "c:"; + value = uuid ?: ""; + } + + s = g_strjoin("", type_id, value, NULL); + _stable_id_append(&str, s); + } else if (g_str_has_prefix(&stable_id[i], "${RANDOM}")) { /* RANDOM makes not so much sense for cloned-mac-address * as the result is similar to specifying "cloned-mac-address=random". * It makes however sense for RFC 7217 Stable Privacy IPv6 addresses @@ -3522,6 +3546,29 @@ nm_utils_stable_id_parse(const char *stable_id, return NM_UTILS_STABLE_TYPE_GENERATED; } +NMUtilsStableType +nm_utils_stable_id_parse_network_ssid(GBytes *ssid, + const char *uuid, + gboolean complete, + char **out_stable_id) +{ + NMUtilsStableType stable_type; + + stable_type = + nm_utils_stable_id_parse("${NETWORK_SSID}", NULL, NULL, NULL, uuid, ssid, out_stable_id); + + nm_assert(stable_type == NM_UTILS_STABLE_TYPE_GENERATED); + nm_assert(!out_stable_id || nm_str_not_empty(*out_stable_id)); + + if (complete && out_stable_id) { + gs_free char *ss = g_steal_pointer(out_stable_id); + + *out_stable_id = nm_utils_stable_id_generated_complete(ss); + } + + return stable_type; +} + /*****************************************************************************/ static gboolean @@ -3567,7 +3614,7 @@ nm_utils_ipv6_addr_set_stable_privacy_with_host_id(NMUtilsStableType stable_type sum = g_checksum_new(G_CHECKSUM_SHA256); - host_id_len = MIN(host_id_len, G_MAXUINT32); + host_id_len = NM_MIN(host_id_len, G_MAXUINT32); if (stable_type != NM_UTILS_STABLE_TYPE_UUID) { guint8 stable_type_uint8; @@ -3742,7 +3789,7 @@ _hw_addr_gen_stable_eth(NMUtilsStableType stable_type, sum = g_checksum_new(G_CHECKSUM_SHA256); - host_id_len = MIN(host_id_len, G_MAXUINT32); + host_id_len = NM_MIN(host_id_len, G_MAXUINT32); nm_assert(stable_type < (NMUtilsStableType) 255); stable_type_uint8 = stable_type; @@ -3819,23 +3866,23 @@ nm_utils_dhcp_client_id_mac(int arp_type, const guint8 *hwaddr, gsize hwaddr_len return g_bytes_new_take(client_id_buf, hwaddr_len + 1); } -#define HASH_KEY \ - ((const guint8[16]){0x80, \ - 0x11, \ - 0x8c, \ - 0xc2, \ - 0xfe, \ - 0x4a, \ - 0x03, \ - 0xee, \ - 0x3e, \ - 0xd6, \ - 0x0c, \ - 0x6f, \ - 0x36, \ - 0x39, \ - 0x14, \ - 0x09}) +#define HASH_KEY \ + NM_HASH_SEED_16(0x80, \ + 0x11, \ + 0x8c, \ + 0xc2, \ + 0xfe, \ + 0x4a, \ + 0x03, \ + 0xee, \ + 0x3e, \ + 0xd6, \ + 0x0c, \ + 0x6f, \ + 0x36, \ + 0x39, \ + 0x14, \ + 0x09) /** * nm_utils_create_dhcp_iaid: @@ -4255,8 +4302,8 @@ read_device_factory_paths_sort_fcn(gconstpointer a, gconstpointer b) const struct plugin_info *db = b; time_t ta, tb; - ta = MAX(da->st.st_mtime, da->st.st_ctime); - tb = MAX(db->st.st_mtime, db->st.st_ctime); + ta = NM_MAX(da->st.st_mtime, da->st.st_ctime); + tb = NM_MAX(db->st.st_mtime, db->st.st_ctime); if (ta < tb) return 1; @@ -4779,15 +4826,91 @@ get_max_rate_vht(const guint8 *bytes, guint len, guint32 *out_maxrate) return TRUE; } +static gboolean +get_bandwidth_ht(const guint8 *bytes, guint len, guint32 *out_bandwidth) +{ + guint8 ht_op_flag_group; + + /* http://standards.ieee.org/getieee802/download/802.11-2012.pdf + * https://mrncciew.com/2014/11/04/cwap-ht-operations-ie/ + * IEEE std 802.11-2020 section 9.4.2.56 + */ + + if (len != 22) + return FALSE; + + ht_op_flag_group = bytes[1]; + + /* Check bit for 20Mhz or 40Mhz */ + if (ht_op_flag_group & (1 << 2)) + *out_bandwidth = 40; + else + *out_bandwidth = 20; + + return TRUE; +} + +static gboolean +get_bandwidth_vht(const guint8 *bytes, guint len, guint32 *out_bandwidth) +{ + guint8 sta_channel_width; + guint8 ccfs0; + guint8 ccfs1; + + /* http://chimera.labs.oreilly.com/books/1234000001739/ch03.html#management_frames + * https://community.arubanetworks.com/community-home/librarydocuments/viewdocument?DocumentKey=799aad1b-d9c4-421a-a492-a111e8680d34&CommunityKey=39a6bdf4-2376-46f9-853a-49420d2d0caa&tab=librarydocuments + * IEEE Std 802.11-2020 section 9.4.2.158 + */ + + if (len < 3) + return FALSE; + + sta_channel_width = bytes[0]; + ccfs0 = bytes[1]; + ccfs1 = bytes[2]; + switch (sta_channel_width) { + case 0: + /* we rely on HT Operation IE value*/ + return FALSE; + case 1: + if (ccfs1 == 0) + *out_bandwidth = 80; + else if (abs(ccfs1 - ccfs0) == 8) + *out_bandwidth = 160; + else if (abs(ccfs1 - ccfs0) > 16) + /* we are considering 80+80 as 160 */ + *out_bandwidth = 160; + else + /* falling back to 80 MHz */ + *out_bandwidth = 80; + break; + case 2: + /* deprecated */ + *out_bandwidth = 160; + break; + case 3: + /* deprecated */ + *out_bandwidth = 160; + break; + default: + return FALSE; + } + + return TRUE; +} + /* Management Frame Information Element IDs, ieee80211_eid */ #define WLAN_EID_HT_CAPABILITY 45 +#define WLAN_EID_HT_OPERATION 61 #define WLAN_EID_VHT_CAPABILITY 191 +#define WLAN_EID_VHT_OPERATION 192 #define WLAN_EID_VENDOR_SPECIFIC 221 void nm_wifi_utils_parse_ies(const guint8 *bytes, gsize len, guint32 *out_max_rate, + guint32 *out_bandwidth, gboolean *out_metered, gboolean *out_owe_transition_mode) { @@ -4795,6 +4918,7 @@ nm_wifi_utils_parse_ies(const guint8 *bytes, guint32 m; NM_SET_OUT(out_max_rate, 0); + NM_SET_OUT(out_bandwidth, 0); NM_SET_OUT(out_metered, FALSE); NM_SET_OUT(out_owe_transition_mode, FALSE); @@ -4816,12 +4940,20 @@ nm_wifi_utils_parse_ies(const guint8 *bytes, *out_max_rate = NM_MAX(*out_max_rate, m); } break; + case WLAN_EID_HT_OPERATION: + if (out_bandwidth) + get_bandwidth_ht(bytes, elem_len, out_bandwidth); + break; case WLAN_EID_VHT_CAPABILITY: if (out_max_rate) { if (get_max_rate_vht(bytes, elem_len, &m)) *out_max_rate = NM_MAX(*out_max_rate, m); } break; + case WLAN_EID_VHT_OPERATION: + if (out_bandwidth) + get_bandwidth_vht(bytes, elem_len, out_bandwidth); + break; case WLAN_EID_VENDOR_SPECIFIC: if (len == 8 && bytes[0] == 0x00 /* OUI: Microsoft */ && bytes[1] == 0x50 && bytes[2] == 0xf2 @@ -5333,7 +5465,7 @@ nm_utils_shorten_hostname(const char *hostname, char **shortened) l = (dot - hostname); else l = strlen(hostname); - l = MIN(l, (gsize) NM_HOST_NAME_MAX); + l = NM_MIN(l, (gsize) NM_HOST_NAME_MAX); s = g_strndup(hostname, l); diff --git a/src/core/nm-core-utils.h b/src/core/nm-core-utils.h index 55112504..f015236d 100644 --- a/src/core/nm-core-utils.h +++ b/src/core/nm-core-utils.h @@ -313,8 +313,14 @@ NMUtilsStableType nm_utils_stable_id_parse(const char *stable_id, const char *hwaddr, const char *bootid, const char *uuid, + GBytes *ssid, char **out_generated); +NMUtilsStableType nm_utils_stable_id_parse_network_ssid(GBytes *ssid, + const char *uuid, + gboolean complete, + char **out_stable_id); + char *nm_utils_stable_id_random(void); char *nm_utils_stable_id_generated_complete(const char *msg); @@ -455,6 +461,7 @@ const char *nm_utils_parse_dns_domain(const char *domain, gboolean *is_routing); void nm_wifi_utils_parse_ies(const guint8 *bytes, gsize len, guint32 *out_max_rate, + guint32 *out_bandwidth, gboolean *out_metered, gboolean *out_owe_transition_mode); diff --git a/src/core/nm-dbus-manager.c b/src/core/nm-dbus-manager.c index 0bde5971..7e6757f0 100644 --- a/src/core/nm-dbus-manager.c +++ b/src/core/nm-dbus-manager.c @@ -1644,8 +1644,8 @@ _new_unix_process(GDBusMethodInvocation *context, /* polkit glib library stores uid and pid as int. There might be some * pitfalls if the id ever happens to be larger then that. Just assert against * it here. */ - g_return_val_if_fail(uid <= MIN(G_MAXINT, G_MAXINT32), NULL); - g_return_val_if_fail(pid > 0 && pid <= MIN(G_MAXINT, G_MAXINT32), NULL); + g_return_val_if_fail(uid <= NM_MIN(G_MAXINT, G_MAXINT32), NULL); + g_return_val_if_fail(pid > 0 && pid <= NM_MIN(G_MAXINT, G_MAXINT32), NULL); self = nm_auth_subject_new_unix_process(dbus_sender, pid, uid); diff --git a/src/core/nm-dbus-utils.c b/src/core/nm-dbus-utils.c index 05eca84f..0a1be4a2 100644 --- a/src/core/nm-dbus-utils.c +++ b/src/core/nm-dbus-utils.c @@ -11,6 +11,18 @@ /*****************************************************************************/ +const GDBusAnnotationInfo _nm_gdbus_annotation_info_deprecated = { + .key = "org.freedesktop.DBus.Deprecated", + .value = "true", +}; + +const GDBusAnnotationInfo *const _nm_gdbus_annotation_info_list_deprecated[] = { + NM_GDBUS_ANNOTATION_INFO_DEPRECATED(), + NULL, +}; + +/*****************************************************************************/ + GDBusPropertyInfo * nm_dbus_utils_interface_info_lookup_property(const GDBusInterfaceInfo *interface_info, const char *property_name, diff --git a/src/core/nm-dbus-utils.h b/src/core/nm-dbus-utils.h index 54b50634..237b37d8 100644 --- a/src/core/nm-dbus-utils.h +++ b/src/core/nm-dbus-utils.h @@ -45,34 +45,55 @@ typedef struct { G_STATIC_ASSERT(G_STRUCT_OFFSET(NMDBusPropertyInfoExtended, property_name) == G_STRUCT_OFFSET(struct _NMDBusPropertyInfoExtendedBase, property_name)); -#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE(m_name, m_signature, m_property_name) \ - ((GDBusPropertyInfo *) &((const struct _NMDBusPropertyInfoExtendedBase){ \ - ._parent = \ - { \ - .ref_count = -1, \ - .name = m_name, \ - .signature = m_signature, \ - .flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE, \ - }, \ - .property_name = m_property_name, \ +extern const GDBusAnnotationInfo _nm_gdbus_annotation_info_deprecated; + +#define NM_GDBUS_ANNOTATION_INFO_DEPRECATED() \ + ((GDBusAnnotationInfo *) &_nm_gdbus_annotation_info_deprecated) + +#define NM_DEFINE_DBUS_ANNOTATION_INFO(a_key, a_value) \ + ((GDBusAnnotationInfo *) &((const GDBusAnnotationInfo){ \ + .key = (a_key), \ + .value = (a_value), \ + })) + +extern const GDBusAnnotationInfo *const _nm_gdbus_annotation_info_list_deprecated[]; + +/* This is a (NULL terminated) list of GDBusAnnotationInfo with only one entry: + * NM_GDBUS_ANNOTATION_INFO_DEPRECATED. This single instance can be reused for the + * common case where we only have one annotation (and it's the deprecation). + * + * Otherwise, NM_DEFINE_DBUS_ANNOTATION_INFOS() is for defining a new list. */ +#define NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED() \ + ((GDBusAnnotationInfo **) _nm_gdbus_annotation_info_list_deprecated) + +#define NM_DEFINE_DBUS_ANNOTATION_INFOS(...) \ + ((GDBusAnnotationInfo **) ((const GDBusAnnotationInfo *const[]){__VA_ARGS__, NULL})) + +#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE(m_name, m_signature, m_property_name, ...) \ + ((GDBusPropertyInfo *) &((const struct _NMDBusPropertyInfoExtendedBase){ \ + ._parent = {.ref_count = -1, \ + .name = m_name, \ + .signature = m_signature, \ + .flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE, \ + __VA_ARGS__}, \ + .property_name = m_property_name, \ })) #define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE(m_name, \ m_signature, \ m_property_name, \ m_permission, \ - m_audit_op) \ + m_audit_op, \ + ...) \ ((GDBusPropertyInfo *) &((const struct _NMDBusPropertyInfoExtendedReadWritable){ \ ._base = \ { \ - ._parent = \ - { \ - .ref_count = -1, \ - .name = m_name, \ - .signature = m_signature, \ - .flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE \ - | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE, \ - }, \ + ._parent = {.ref_count = -1, \ + .name = m_name, \ + .signature = m_signature, \ + .flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE \ + | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE, \ + __VA_ARGS__}, \ .property_name = m_property_name, \ }, \ .permission = m_permission, \ diff --git a/src/core/nm-dispatcher.c b/src/core/nm-dispatcher.c index cdc07dd6..9aa4194e 100644 --- a/src/core/nm-dispatcher.c +++ b/src/core/nm-dispatcher.c @@ -50,6 +50,8 @@ } \ G_STMT_END +static gboolean nm_dispatcher_need_device(NMDispatcherAction action); + /*****************************************************************************/ struct NMDispatcherCallId { @@ -469,7 +471,8 @@ static const char *action_table[] = {[NM_DISPATCHER_ACTION_HOSTNAME] = NMD_ [NM_DISPATCHER_ACTION_DHCP_CHANGE_6] = NMD_ACTION_DHCP6_CHANGE, [NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE] = NMD_ACTION_CONNECTIVITY_CHANGE, - [NM_DISPATCHER_ACTION_REAPPLY] = NMD_ACTION_REAPPLY}; + [NM_DISPATCHER_ACTION_REAPPLY] = NMD_ACTION_REAPPLY, + [NM_DISPATCHER_ACTION_DNS_CHANGE] = NMD_ACTION_DNS_CHANGE}; static const char * action_to_string(NMDispatcherAction action) @@ -530,9 +533,7 @@ _dispatcher_call(NMDispatcherAction action, if (G_UNLIKELY(!request_id)) request_id = ++gl.request_id_counter; - /* All actions except 'hostname' and 'connectivity-change' require a device */ - if (action == NM_DISPATCHER_ACTION_HOSTNAME - || action == NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE) { + if (!nm_dispatcher_need_device(action)) { _LOG2D(request_id, log_ifname, log_con_uuid, @@ -592,9 +593,8 @@ _dispatcher_call(NMDispatcherAction action, g_variant_builder_init(&vpn_ip4_props, G_VARIANT_TYPE_VARDICT); g_variant_builder_init(&vpn_ip6_props, G_VARIANT_TYPE_VARDICT); - /* hostname and connectivity-change actions don't send device data */ - if (action != NM_DISPATCHER_ACTION_HOSTNAME - && action != NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE) { + /* hostname, DNS and connectivity-change actions don't send device data */ + if (nm_dispatcher_need_device(action)) { fill_device_props(device, &device_props, &device_proxy_props, @@ -925,6 +925,30 @@ nm_dispatcher_call_connectivity(NMConnectivityState connectivity_state, out_call_id); } +/** + * nm_dispatcher_call_dns_change(): + * + * This method does not block the caller. + * + * Returns: %TRUE if the action was dispatched, %FALSE on failure + */ +gboolean +nm_dispatcher_call_dns_change(void) +{ + return _dispatcher_call(NM_DISPATCHER_ACTION_DNS_CHANGE, + FALSE, + NULL, + NULL, + NULL, + FALSE, + NM_CONNECTIVITY_UNKNOWN, + NULL, + NULL, + NULL, + NULL, + NULL); +} + void nm_dispatcher_call_cancel(NMDispatcherCallId *call_id) { @@ -937,3 +961,16 @@ nm_dispatcher_call_cancel(NMDispatcherCallId *call_id) _LOG3D(call_id, "cancelling dispatcher callback action"); call_id->callback = NULL; } + +/* All actions except 'hostname', 'connectivity-change' and 'dns-change' require + * a device */ +static gboolean +nm_dispatcher_need_device(NMDispatcherAction action) +{ + if (action == NM_DISPATCHER_ACTION_HOSTNAME + || action == NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE + || action == NM_DISPATCHER_ACTION_DNS_CHANGE) { + return FALSE; + } + return TRUE; +} diff --git a/src/core/nm-dispatcher.h b/src/core/nm-dispatcher.h index 30716399..a1cb96b7 100644 --- a/src/core/nm-dispatcher.h +++ b/src/core/nm-dispatcher.h @@ -23,6 +23,7 @@ typedef enum { NM_DISPATCHER_ACTION_DHCP_CHANGE_6, NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE, NM_DISPATCHER_ACTION_REAPPLY, + NM_DISPATCHER_ACTION_DNS_CHANGE, } NMDispatcherAction; #define NM_DISPATCHER_ACTION_DHCP_CHANGE_X(IS_IPv4) \ @@ -69,6 +70,8 @@ gboolean nm_dispatcher_call_connectivity(NMConnectivityState state, gpointer user_data, NMDispatcherCallId **out_call_id); +gboolean nm_dispatcher_call_dns_change(void); + void nm_dispatcher_call_cancel(NMDispatcherCallId *call_id); #endif /* __NM_DISPATCHER_H__ */ diff --git a/src/core/nm-ip-config.c b/src/core/nm-ip-config.c index bec67d9a..c4dc04da 100644 --- a/src/core/nm-ip-config.c +++ b/src/core/nm-ip-config.c @@ -16,6 +16,10 @@ /*****************************************************************************/ +#define NOTIFY_PLATFORM_RATELIMIT_MSEC 333 + +/*****************************************************************************/ + GType nm_ip4_config_get_type(void); GType nm_ip6_config_get_type(void); @@ -68,6 +72,73 @@ _value_set_variant_as(GValue *value, const char *const *strv, guint len) /*****************************************************************************/ static void +_notify_platform_handle(NMIPConfig *self, gint64 now_msec) +{ + NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); + guint32 obj_type_flags; + + nm_clear_g_source_inst(&priv->notify_platform_timeout_source); + + priv->notify_platform_rlimited_until_msec = now_msec + NOTIFY_PLATFORM_RATELIMIT_MSEC; + + obj_type_flags = nm_steal_int(&priv->notify_platform_obj_type_flags); + + nm_assert(obj_type_flags != 0u); + + _handle_platform_change(self, obj_type_flags, FALSE); +} + +static gboolean +_notify_platform_cb(gpointer user_data) +{ + _notify_platform_handle(user_data, nm_utils_get_monotonic_timestamp_msec()); + return G_SOURCE_CONTINUE; +} + +static void +_notify_platform(NMIPConfig *self, guint32 obj_type_flags) +{ + const int addr_family = nm_ip_config_get_addr_family(self); + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); + gint64 now_msec; + + obj_type_flags &= (nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)) + | nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4))); + + if (obj_type_flags == 0u) + return; + + priv->notify_platform_obj_type_flags |= obj_type_flags; + + if (priv->notify_platform_timeout_source) { + /* We are currently rate limited. Don't bother to check whether + * (now_msec < priv->notify_platform_rlimited_until_msec), just always + * delegate to the timeout handler. It is scheduled with a lower idle + * priority, so we want that additional backoff. */ + return; + } + + now_msec = nm_utils_get_monotonic_timestamp_msec(); + + if (now_msec < priv->notify_platform_rlimited_until_msec) { + priv->notify_platform_timeout_source = nm_g_source_attach( + /* Schedule with a low G_PRIORITY_LOW. */ + nm_g_timeout_source_new(priv->notify_platform_rlimited_until_msec - now_msec, + G_PRIORITY_LOW - 10, + _notify_platform_cb, + self, + NULL), + NULL); + return; + } + + _notify_platform_handle(self, now_msec); +} + +/*****************************************************************************/ + +static void _l3cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMIPConfig *self) { switch (notify_data->notify_type) { @@ -76,7 +147,7 @@ _l3cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMIPCo _handle_l3cd_changed(self, notify_data->l3cd_changed.l3cd_new); break; case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE: - _handle_platform_change(self, notify_data->platform_change_on_idle.obj_type_flags, FALSE); + _notify_platform(self, notify_data->platform_change_on_idle.obj_type_flags); break; default: break; @@ -207,6 +278,8 @@ finalize(GObject *object) NMIPConfig *self = NM_IP_CONFIG(object); NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); + nm_clear_g_source_inst(&priv->notify_platform_timeout_source); + nm_clear_g_signal_handler(priv->l3cfg, &priv->l3cfg_notify_id); g_object_unref(priv->l3cfg); @@ -412,23 +485,31 @@ static const NMDBusInterfaceInfoExtended interface_info_ip4_config = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_IP4_CONFIG, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Addresses", - "aau", - NM_IP4_CONFIG_ADDRESSES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Addresses", + "aau", + NM_IP4_CONFIG_ADDRESSES, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AddressData", "aa{sv}", NM_IP_CONFIG_ADDRESS_DATA), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Gateway", "s", NM_IP_CONFIG_GATEWAY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Routes", "aau", NM_IP4_CONFIG_ROUTES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Routes", + "aau", + NM_IP4_CONFIG_ROUTES, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("RouteData", "aa{sv}", NM_IP_CONFIG_ROUTE_DATA), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("NameserverData", "aa{sv}", NM_IP4_CONFIG_NAMESERVER_DATA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Nameservers", - "au", - NM_IP4_CONFIG_NAMESERVERS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Nameservers", + "au", + NM_IP4_CONFIG_NAMESERVERS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Domains", "as", NM_IP_CONFIG_DOMAINS), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Searches", "as", NM_IP_CONFIG_SEARCHES), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DnsOptions", @@ -440,9 +521,11 @@ static const NMDBusInterfaceInfoExtended interface_info_ip4_config = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WinsServerData", "as", NM_IP4_CONFIG_WINS_SERVER_DATA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WinsServers", - "au", - NM_IP4_CONFIG_WINS_SERVERS), ), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "WinsServers", + "au", + NM_IP4_CONFIG_WINS_SERVERS, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), ), ), }; static void @@ -541,16 +624,20 @@ static const NMDBusInterfaceInfoExtended interface_info_ip6_config = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_IP6_CONFIG, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Addresses", - "a(ayuay)", - NM_IP6_CONFIG_ADDRESSES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Addresses", + "a(ayuay)", + NM_IP6_CONFIG_ADDRESSES, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AddressData", "aa{sv}", NM_IP_CONFIG_ADDRESS_DATA), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Gateway", "s", NM_IP_CONFIG_GATEWAY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Routes", - "a(ayuayu)", - NM_IP6_CONFIG_ROUTES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "Routes", + "a(ayuayu)", + NM_IP6_CONFIG_ROUTES, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("RouteData", "aa{sv}", NM_IP_CONFIG_ROUTE_DATA), diff --git a/src/core/nm-ip-config.h b/src/core/nm-ip-config.h index 0dcea83b..47a40bd2 100644 --- a/src/core/nm-ip-config.h +++ b/src/core/nm-ip-config.h @@ -32,7 +32,10 @@ struct _NMIPConfigPrivate { struct { const NMPObject *best_default_route; } v_gateway; - gulong l3cfg_notify_id; + GSource *notify_platform_timeout_source; + gint64 notify_platform_rlimited_until_msec; + gulong l3cfg_notify_id; + guint32 notify_platform_obj_type_flags; }; struct _NMIPConfig { diff --git a/src/core/nm-l3-config-data.c b/src/core/nm-l3-config-data.c index 96274ba9..a4647116 100644 --- a/src/core/nm-l3-config-data.c +++ b/src/core/nm-l3-config-data.c @@ -157,6 +157,8 @@ struct _NML3ConfigData { bool has_routes_with_type_local_6_set : 1; bool has_routes_with_type_local_4_val : 1; bool has_routes_with_type_local_6_val : 1; + bool dhcp_enabled_4 : 1; + bool dhcp_enabled_6 : 1; bool ndisc_hop_limit_set : 1; bool ndisc_reachable_time_msec_set : 1; @@ -324,7 +326,7 @@ _strv_ptrarray_merge(GPtrArray **p_dst, const GPtrArray *src) const char *s = src->pdata[i]; if (dst_initial_len > 0 - && nm_strv_find_first((const char *const *) ((*p_dst)->pdata), dst_initial_len, s) >= 0) + && nm_strv_contains((const char *const *) ((*p_dst)->pdata), dst_initial_len, s)) continue; g_ptr_array_add(*p_dst, g_strdup(s)); @@ -1642,7 +1644,7 @@ nm_l3_config_data_get_dns_priority(const NML3ConfigData *self, int addr_family, case AF_UNSPEC: if (NM_FLAGS_ANY(self->flags, NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY_4)) { if (NM_FLAGS_ANY(self->flags, NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY_6)) { - NM_SET_OUT(out_prio, MIN(self->dns_priority_4, self->dns_priority_6)); + NM_SET_OUT(out_prio, NM_MIN(self->dns_priority_4, self->dns_priority_6)); return TRUE; } NM_SET_OUT(out_prio, self->dns_priority_4); @@ -1933,6 +1935,19 @@ nm_l3_config_data_set_mptcp_flags(NML3ConfigData *self, NMMptcpFlags mptcp_flags return TRUE; } +gboolean +nm_l3_config_data_get_dhcp_enabled(const NML3ConfigData *self, int addr_family) +{ + const int IS_IPv4 = NM_IS_IPv4(addr_family); + + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + if (IS_IPv4) { + return self->dhcp_enabled_4; + } else { + return self->dhcp_enabled_6; + } +} + NMProxyConfigMethod nm_l3_config_data_get_proxy_method(const NML3ConfigData *self) { @@ -2231,14 +2246,23 @@ static const NML3ConfigData * get_empty_l3cd(void) { static NML3ConfigData *empty_l3cd; + NML3ConfigData *l3cd; + +again: + l3cd = g_atomic_pointer_get(&empty_l3cd); + if (G_UNLIKELY(!l3cd)) { + l3cd = nm_l3_config_data_new(nm_dedup_multi_index_new(), 1, NM_IP_CONFIG_SOURCE_UNKNOWN); + l3cd->ifindex = 0; - if (!empty_l3cd) { - empty_l3cd = - nm_l3_config_data_new(nm_dedup_multi_index_new(), 1, NM_IP_CONFIG_SOURCE_UNKNOWN); - empty_l3cd->ifindex = 0; + nm_l3_config_data_seal(l3cd); + + if (!g_atomic_pointer_compare_and_exchange(&empty_l3cd, NULL, l3cd)) { + nm_l3_config_data_unref(l3cd); + goto again; + } } - return empty_l3cd; + return l3cd; } int @@ -2713,6 +2737,7 @@ _init_from_connection_ip(NML3ConfigData *self, int addr_family, NMConnection *co guint nnameservers; guint nsearches; const char *gateway_str; + const char *method; NMIPAddr gateway_bin; guint i; int idx; @@ -2730,6 +2755,24 @@ _init_from_connection_ip(NML3ConfigData *self, int addr_family, NMConnection *co never_default = nm_setting_ip_config_get_never_default(s_ip); + method = nm_setting_ip_config_get_method(s_ip); + if (IS_IPv4) { + if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + self->dhcp_enabled_4 = TRUE; + } else { + self->dhcp_enabled_4 = FALSE; + } + } else { + method = nm_setting_ip_config_get_method(s_ip); + if (NM_IN_STRSET(method, + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { + self->dhcp_enabled_6 = TRUE; + } else { + self->dhcp_enabled_6 = FALSE; + } + } + nm_l3_config_data_set_never_default(self, addr_family, !!never_default); if (!never_default && (gateway_str = nm_setting_ip_config_get_gateway(s_ip)) @@ -3413,6 +3456,11 @@ nm_l3_config_data_merge(NML3ConfigData *self, self->dhcp_lease_x[0] = nm_dhcp_lease_ref(self->dhcp_lease_x[0]); self->dhcp_lease_x[1] = nm_dhcp_lease_ref(self->dhcp_lease_x[1]); } + if (src->dhcp_enabled_4) + self->dhcp_enabled_4 = TRUE; + + if (src->dhcp_enabled_6) + self->dhcp_enabled_6 = TRUE; } NML3ConfigData * diff --git a/src/core/nm-l3-config-data.h b/src/core/nm-l3-config-data.h index 80abb00d..b55b2f41 100644 --- a/src/core/nm-l3-config-data.h +++ b/src/core/nm-l3-config-data.h @@ -554,6 +554,8 @@ NMSettingIP6ConfigPrivacy nm_l3_config_data_get_ip6_privacy(const NML3ConfigData gboolean nm_l3_config_data_set_ip6_privacy(NML3ConfigData *self, NMSettingIP6ConfigPrivacy ip6_privacy); +gboolean nm_l3_config_data_get_dhcp_enabled(const NML3ConfigData *self, int addr_family); + NMProxyConfigMethod nm_l3_config_data_get_proxy_method(const NML3ConfigData *self); gboolean nm_l3_config_data_set_proxy_method(NML3ConfigData *self, NMProxyConfigMethod value); diff --git a/src/core/nm-l3-ipv4ll.c b/src/core/nm-l3-ipv4ll.c index ec871bef..551a90fe 100644 --- a/src/core/nm-l3-ipv4ll.c +++ b/src/core/nm-l3-ipv4ll.c @@ -390,23 +390,23 @@ _ipv4ll_addrgen(NML3IPv4LL *self, gboolean generate_new_addr) _ASSERT(self); /* MAC_HASH_KEY is the same as used by systemd. */ -#define MAC_HASH_KEY \ - ((const guint8[16]){0xdf, \ - 0x04, \ - 0x22, \ - 0x98, \ - 0x3f, \ - 0xad, \ - 0x14, \ - 0x52, \ - 0xf9, \ - 0x87, \ - 0x2e, \ - 0xd1, \ - 0x9c, \ - 0x70, \ - 0xe2, \ - 0xf2}) +#define MAC_HASH_KEY \ + NM_HASH_SEED_16(0xdf, \ + 0x04, \ + 0x22, \ + 0x98, \ + 0x3f, \ + 0xad, \ + 0x14, \ + 0x52, \ + 0xf9, \ + 0x87, \ + 0x2e, \ + 0xd1, \ + 0x9c, \ + 0x70, \ + 0xe2, \ + 0xf2) if (self->mac_set && (!self->seed_set || !nm_ether_addr_equal(&self->mac, &self->seed_mac))) { /* systemd's ipv4ll library by default only hashes the MAC address (as we do here). @@ -465,23 +465,23 @@ _ipv4ll_addrgen(NML3IPv4LL *self, gboolean generate_new_addr) gen_addr: -#define PICK_HASH_KEY \ - ((const guint8[16]){0x15, \ - 0xac, \ - 0x82, \ - 0xa6, \ - 0xd6, \ - 0x3f, \ - 0x49, \ - 0x78, \ - 0x98, \ - 0x77, \ - 0x5d, \ - 0x0c, \ - 0x69, \ - 0x02, \ - 0x94, \ - 0x0b}) +#define PICK_HASH_KEY \ + NM_HASH_SEED_16(0x15, \ + 0xac, \ + 0x82, \ + 0xa6, \ + 0xd6, \ + 0x3f, \ + 0x49, \ + 0x78, \ + 0x98, \ + 0x77, \ + 0x5d, \ + 0x0c, \ + 0x69, \ + 0x02, \ + 0x94, \ + 0x0b) h = c_siphash_hash(PICK_HASH_KEY, (const guint8 *) &self->seed, sizeof(self->seed)); diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index ce9d5849..f428d04c 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -165,7 +165,18 @@ typedef struct { /* This flag is only used temporarily to do a bulk update and * clear all the ones that are no longer in used. */ - bool os_dirty : 1; + bool os_non_dynamic_dirty : 1; + + /* Indicates that we have a object in combined_l3cd_commited that keeps the + * object state alive. */ + bool os_non_dynamic : 1; + + /* Indicates that there is a dynamic route from _commit_collect_routes(), that keeps the + * object state alive. */ + bool os_dynamic : 1; + + /* Indicates that this dynamic obj-state is marked as dirty. */ + bool os_dynamic_dirty : 1; } ObjStateData; G_STATIC_ASSERT(G_STRUCT_OFFSET(ObjStateData, obj) == 0); @@ -334,6 +345,7 @@ typedef struct _NML3CfgPrivate { bool nacd_acd_not_supported : 1; bool acd_ipv4_addresses_on_link_has : 1; + bool acd_data_pruning_needed : 1; bool changed_configs_configs : 1; bool changed_configs_acd_state : 1; @@ -394,7 +406,8 @@ static void _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is static void _nm_l3cfg_emit_signal_notify_acd_event_all(NML3Cfg *self); -static gboolean _acd_has_valid_link(const NMPObject *obj, +static gboolean _acd_has_valid_link(NML3Cfg *self, + const NMPObject *obj, const guint8 **out_addr_bin, gboolean *out_acd_not_supported); @@ -674,9 +687,9 @@ _nm_l3cfg_emit_signal_notify_l3cd_changed(NML3Cfg *self, /*****************************************************************************/ static void -_l3_changed_configs_set_dirty(NML3Cfg *self) +_l3_changed_configs_set_dirty(NML3Cfg *self, const char *reason) { - _LOGT("IP configuration changed (mark dirty)"); + _LOGT("IP configuration changed (mark dirty): %s", reason); self->priv.p->changed_configs_configs = TRUE; self->priv.p->changed_configs_acd_state = TRUE; } @@ -770,51 +783,70 @@ _nm_n_acd_data_probe_new(NML3Cfg *self, in_addr_t addr, guint32 timeout_msec, gp /*****************************************************************************/ -#define nm_assert_obj_state(self, obj_state) \ - G_STMT_START \ - { \ - if (NM_MORE_ASSERTS > 0) { \ - const NML3Cfg *_self = (self); \ - const ObjStateData *_obj_state = (obj_state); \ - \ - nm_assert(_obj_state); \ - nm_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(_obj_state->obj), \ - NMP_OBJECT_TYPE_IP4_ADDRESS, \ - NMP_OBJECT_TYPE_IP6_ADDRESS, \ - NMP_OBJECT_TYPE_IP4_ROUTE, \ - NMP_OBJECT_TYPE_IP6_ROUTE)); \ - nm_assert(!_obj_state->os_plobj || _obj_state->os_was_in_platform); \ - nm_assert(_obj_state->os_failedobj_expiry_msec != 0 \ - || _obj_state->os_failedobj_prioq_idx == NM_PRIOQ_IDX_NULL); \ - nm_assert(_obj_state->os_failedobj_expiry_msec == 0 || !_obj_state->os_plobj); \ - nm_assert(_obj_state->os_failedobj_expiry_msec == 0 \ - || c_list_is_empty(&_obj_state->os_zombie_lst)); \ - nm_assert(_obj_state->os_failedobj_expiry_msec == 0 || _obj_state->obj); \ - if (_self) { \ - if (c_list_is_empty(&_obj_state->os_zombie_lst)) { \ - nm_assert(_self->priv.p->combined_l3cd_commited); \ - \ - if (NM_MORE_ASSERTS > 5) { \ - nm_assert(c_list_contains(&_self->priv.p->obj_state_lst_head, \ - &_obj_state->os_lst)); \ - nm_assert(_obj_state->os_plobj \ - == nm_platform_lookup_obj(_self->priv.platform, \ - NMP_CACHE_ID_TYPE_OBJECT_TYPE, \ - _obj_state->obj)); \ - nm_assert( \ - c_list_is_empty(&obj_state->os_zombie_lst) \ - ? (_obj_state->obj \ - == nm_dedup_multi_entry_get_obj(nm_l3_config_data_lookup_obj( \ - _self->priv.p->combined_l3cd_commited, \ - _obj_state->obj))) \ - : (!nm_l3_config_data_lookup_obj( \ - _self->priv.p->combined_l3cd_commited, \ - _obj_state->obj))); \ - } \ - } \ - } \ - } \ - } \ +#define nm_assert_obj_state(self, obj_state) \ + G_STMT_START \ + { \ + if (NM_MORE_ASSERTS > 0) { \ + const NML3Cfg *_self = (self); \ + const ObjStateData *_obj_state = (obj_state); \ + \ + nm_assert(_obj_state); \ + nm_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(_obj_state->obj), \ + NMP_OBJECT_TYPE_IP4_ADDRESS, \ + NMP_OBJECT_TYPE_IP6_ADDRESS, \ + NMP_OBJECT_TYPE_IP4_ROUTE, \ + NMP_OBJECT_TYPE_IP6_ROUTE)); \ + nm_assert(!_obj_state->os_plobj || _obj_state->os_was_in_platform); \ + nm_assert(_obj_state->os_failedobj_expiry_msec != 0 \ + || _obj_state->os_failedobj_prioq_idx == NM_PRIOQ_IDX_NULL); \ + nm_assert(_obj_state->os_failedobj_expiry_msec == 0 || !_obj_state->os_plobj); \ + nm_assert(_obj_state->os_failedobj_expiry_msec == 0 \ + || c_list_is_empty(&_obj_state->os_zombie_lst)); \ + nm_assert(_obj_state->os_failedobj_expiry_msec == 0 || _obj_state->obj); \ + nm_assert(!_obj_state->os_plobj \ + || NMP_OBJECT_GET_TYPE(_obj_state->obj) \ + == NMP_OBJECT_GET_TYPE(_obj_state->os_plobj)); \ + if (_self) { \ + if (c_list_is_empty(&_obj_state->os_zombie_lst)) { \ + nm_assert(_self->priv.p->combined_l3cd_commited); \ + \ + if (NM_MORE_ASSERTS > 5) { \ + /* metric-any must be resolved before adding the object. Otherwise, + * their real metric is not known, and they cannot be compared to objects + * from NMPlatform cache. */ \ + nm_assert(!NM_IN_SET(NMP_OBJECT_GET_TYPE(_obj_state->obj), \ + NMP_OBJECT_TYPE_IP4_ROUTE, \ + NMP_OBJECT_TYPE_IP6_ROUTE) \ + || !NMP_OBJECT_CAST_IP_ROUTE(_obj_state->obj)->metric_any); \ + \ + nm_assert(c_list_contains(&_self->priv.p->obj_state_lst_head, \ + &_obj_state->os_lst)); \ + nm_assert(_obj_state->os_plobj \ + == nm_platform_lookup_obj(_self->priv.platform, \ + NMP_CACHE_ID_TYPE_OBJECT_TYPE, \ + _obj_state->obj)); \ + if (!c_list_is_empty(&obj_state->os_zombie_lst)) { \ + nm_assert(!obj_state->os_non_dynamic); \ + nm_assert(!obj_state->os_non_dynamic_dirty); \ + nm_assert(!obj_state->os_dynamic); \ + nm_assert(!obj_state->os_dynamic_dirty); \ + } \ + if (obj_state->os_non_dynamic) { \ + nm_assert( \ + _obj_state->obj \ + == nm_dedup_multi_entry_get_obj(nm_l3_config_data_lookup_obj( \ + _self->priv.p->combined_l3cd_commited, \ + _obj_state->obj))); \ + } else { \ + nm_assert(!nm_l3_config_data_lookup_obj( \ + _self->priv.p->combined_l3cd_commited, \ + _obj_state->obj)); \ + } \ + } \ + } \ + } \ + } \ + } \ G_STMT_END static ObjStateData * @@ -828,7 +860,10 @@ _obj_state_data_new(const NMPObject *obj, const NMPObject *plobj) .os_plobj = nmp_object_ref(plobj), .os_was_in_platform = !!plobj, .os_nm_configured = FALSE, - .os_dirty = FALSE, + .os_non_dynamic_dirty = FALSE, + .os_non_dynamic = FALSE, + .os_dynamic = FALSE, + .os_dynamic_dirty = FALSE, .os_failedobj_expiry_msec = 0, .os_failedobj_prioq_idx = NM_PRIOQ_IDX_NULL, .os_zombie_lst = C_LIST_INIT(obj_state->os_zombie_lst), @@ -897,34 +932,6 @@ _obj_state_data_to_string(const ObjStateData *obj_state, char *buf, gsize buf_si return buf0; } -static gboolean -_obj_state_data_update(ObjStateData *obj_state, const NMPObject *obj) -{ - gboolean changed = FALSE; - - nm_assert_obj_state(NULL, obj_state); - nm_assert(obj); - nm_assert(nmp_object_id_equal(obj_state->obj, obj)); - - obj_state->os_dirty = FALSE; - - if (obj_state->obj != obj) { - nm_auto_nmpobj const NMPObject *obj_old = NULL; - - if (!nmp_object_equal(obj_state->obj, obj)) - changed = TRUE; - obj_old = g_steal_pointer(&obj_state->obj); - obj_state->obj = nmp_object_ref(obj); - } - - if (!c_list_is_empty(&obj_state->os_zombie_lst)) { - c_list_unlink(&obj_state->os_zombie_lst); - changed = TRUE; - } - - return changed; -} - /*****************************************************************************/ static void @@ -999,6 +1006,151 @@ out: } static void +_obj_states_track_new(NML3Cfg *self, const NMPObject *obj, gboolean dynamic) +{ + char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; + ObjStateData *obj_state; + + obj_state = _obj_state_data_new( + obj, + nm_platform_lookup_obj(self->priv.platform, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj)); + obj_state->os_dynamic = dynamic; + obj_state->os_non_dynamic = !dynamic; + c_list_link_tail(&self->priv.p->obj_state_lst_head, &obj_state->os_lst); + g_hash_table_add(self->priv.p->obj_state_hash, obj_state); + _LOGD("obj-state: track%s: %s", + dynamic ? " (dynamic)" : "", + _obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf))); + nm_assert_obj_state(self, obj_state); +} + +static gboolean +_obj_states_track_update(NML3Cfg *self, + ObjStateData *obj_state, + const NMPObject *obj, + gboolean dynamic) +{ + gboolean changed = FALSE; + + nm_assert_obj_state(NULL, obj_state); + nm_assert(obj); + nm_assert(nmp_object_id_equal(obj_state->obj, obj)); + + if (dynamic) { + if (!obj_state->os_dynamic) + changed = TRUE; + obj_state->os_dynamic_dirty = FALSE; + obj_state->os_dynamic = TRUE; + } else { + if (!obj_state->os_non_dynamic) + changed = TRUE; + obj_state->os_non_dynamic_dirty = FALSE; + obj_state->os_non_dynamic = TRUE; + } + + if (obj_state->obj != obj && (!dynamic || !obj_state->os_non_dynamic)) { + nm_auto_nmpobj const NMPObject *obj_old = NULL; + + if (!nmp_object_equal(obj_state->obj, obj)) + changed = TRUE; + obj_old = g_steal_pointer(&obj_state->obj); + obj_state->obj = nmp_object_ref(obj); + } + + if (!c_list_is_empty(&obj_state->os_zombie_lst)) { + c_list_unlink(&obj_state->os_zombie_lst); + changed = TRUE; + } + + if (changed) { + char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; + + _LOGD("obj-state: update: %s (static: %d, dynamic: %d)", + _obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)), + !!obj_state->os_non_dynamic, + !!obj_state->os_dynamic); + } + + nm_assert_obj_state(self, obj_state); + return changed; +} + +static gboolean +_obj_states_track_mark_dirty(NML3Cfg *self, gboolean dynamic) +{ + ObjStateData *obj_state; + gboolean any_dirty = FALSE; + + c_list_for_each_entry (obj_state, &self->priv.p->obj_state_lst_head, os_lst) { + if (!c_list_is_empty(&obj_state->os_zombie_lst)) { + /* we can ignore zombies. */ + continue; + } + if (dynamic) { + if (!obj_state->os_dynamic) + continue; + obj_state->os_dynamic_dirty = TRUE; + } else { + if (!obj_state->os_non_dynamic) + continue; + obj_state->os_non_dynamic_dirty = TRUE; + } + any_dirty = TRUE; + } + + return any_dirty; +} + +static void +_obj_states_track_prune_dirty(NML3Cfg *self, gboolean also_dynamic) +{ + GHashTableIter h_iter; + ObjStateData *obj_state; + char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; + + g_hash_table_iter_init(&h_iter, self->priv.p->obj_state_hash); + while (g_hash_table_iter_next(&h_iter, (gpointer *) &obj_state, NULL)) { + if (!c_list_is_empty(&obj_state->os_zombie_lst)) { + /* The object is half-dead already and only kept for cleanup. But + * it does not need to be untracked. */ + continue; + } + + /* Resolve the "dirty" flags. */ + if (obj_state->os_non_dynamic_dirty) { + obj_state->os_non_dynamic = FALSE; + obj_state->os_non_dynamic_dirty = FALSE; + } + if (also_dynamic) { + if (obj_state->os_dynamic_dirty) { + obj_state->os_dynamic = FALSE; + obj_state->os_dynamic_dirty = FALSE; + } + } + + if (obj_state->os_non_dynamic || obj_state->os_dynamic) { + /* This obj-state is still alive. Keep it. */ + continue; + } + + if (obj_state->os_plobj && obj_state->os_nm_configured) { + nm_assert(obj_state->os_failedobj_prioq_idx == NM_PRIOQ_IDX_NULL); + c_list_link_tail(&self->priv.p->obj_state_zombie_lst_head, &obj_state->os_zombie_lst); + obj_state->os_zombie_count = ZOMBIE_COUNT_START; + _LOGD("obj-state: now zombie: %s", + _obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf))); + continue; + } + + _LOGD("obj-state: untrack: %s", _obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf))); + nm_prioq_remove(&self->priv.p->failedobj_prioq, + obj_state, + &obj_state->os_failedobj_prioq_idx); + g_hash_table_iter_remove(&h_iter); + } +} + +static void _obj_states_update_all(NML3Cfg *self) { static const NMPObjectType obj_types[] = { @@ -1007,21 +1159,13 @@ _obj_states_update_all(NML3Cfg *self) NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE, }; - char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE]; ObjStateData *obj_state; int i; gboolean any_dirty = FALSE; nm_assert(NM_IS_L3CFG(self)); - c_list_for_each_entry (obj_state, &self->priv.p->obj_state_lst_head, os_lst) { - if (!c_list_is_empty(&obj_state->os_zombie_lst)) { - /* we can ignore zombies. */ - continue; - } - any_dirty = TRUE; - obj_state->os_dirty = TRUE; - } + any_dirty = _obj_states_track_mark_dirty(self, FALSE); for (i = 0; i < (int) G_N_ELEMENTS(obj_types); i++) { const NMPObjectType obj_type = obj_types[i]; @@ -1039,59 +1183,24 @@ _obj_states_update_all(NML3Cfg *self) /* this is a nodev route. We don't track an obj-state for this. */ continue; } - + if (obj_type == NMP_OBJECT_TYPE_IP4_ROUTE + && NMP_OBJECT_CAST_IP4_ROUTE(obj)->weight > 0) { + /* this route weight is bigger than 0, that means we don't know + * which kind of route this will be. It can only be determined during commit. */ + continue; + } obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &obj); if (!obj_state) { - obj_state = - _obj_state_data_new(obj, - nm_platform_lookup_obj(self->priv.platform, - NMP_CACHE_ID_TYPE_OBJECT_TYPE, - obj)); - c_list_link_tail(&self->priv.p->obj_state_lst_head, &obj_state->os_lst); - g_hash_table_add(self->priv.p->obj_state_hash, obj_state); - _LOGD("obj-state: track: %s", - _obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf))); - nm_assert_obj_state(self, obj_state); + _obj_states_track_new(self, obj, FALSE); continue; } - if (_obj_state_data_update(obj_state, obj)) { - _LOGD("obj-state: update: %s", - _obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf))); - } - - nm_assert_obj_state(self, obj_state); + _obj_states_track_update(self, obj_state, obj, FALSE); } } - if (any_dirty) { - GHashTableIter h_iter; - - g_hash_table_iter_init(&h_iter, self->priv.p->obj_state_hash); - while (g_hash_table_iter_next(&h_iter, (gpointer *) &obj_state, NULL)) { - if (!c_list_is_empty(&obj_state->os_zombie_lst)) - continue; - if (!obj_state->os_dirty) - continue; - - if (obj_state->os_plobj && obj_state->os_nm_configured) { - nm_assert(obj_state->os_failedobj_prioq_idx == NM_PRIOQ_IDX_NULL); - c_list_link_tail(&self->priv.p->obj_state_zombie_lst_head, - &obj_state->os_zombie_lst); - obj_state->os_zombie_count = ZOMBIE_COUNT_START; - _LOGD("obj-state: now zombie: %s", - _obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf))); - continue; - } - - _LOGD("obj-state: untrack: %s", - _obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf))); - nm_prioq_remove(&self->priv.p->failedobj_prioq, - obj_state, - &obj_state->os_failedobj_prioq_idx); - g_hash_table_iter_remove(&h_iter); - } - } + if (any_dirty) + _obj_states_track_prune_dirty(self, FALSE); } typedef struct { @@ -1192,6 +1301,7 @@ _commit_collect_routes(NML3Cfg *self, const int IS_IPv4 = NM_IS_IPv4(addr_family); const NMDedupMultiHeadEntry *head_entry; const NMDedupMultiEntry *entry; + gboolean is_dhcp_enabled; nm_assert(routes && !*routes); nm_assert(routes_nodev && !*routes_nodev); @@ -1211,17 +1321,21 @@ _commit_collect_routes(NML3Cfg *self, else { nm_assert(NMP_OBJECT_CAST_IP_ROUTE(obj)->ifindex == self->priv.ifindex); - if (!any_addrs) { + is_dhcp_enabled = + nm_l3_config_data_get_dhcp_enabled(self->priv.p->combined_l3cd_commited, + addr_family); + if (!any_addrs && is_dhcp_enabled) { /* This is a unicast route (or a similar route, which has an * ifindex). * * However, during this commit we don't plan to configure any - * IP addresses. With `ipvx.method=manual` that should not be - * possible. More likely, this is because the profile has - * `ipvx.method=auto` and static routes. + * IP addresses when the profile has `ipvx.method=auto` and + * static routes. * * Don't configure any such routes before we also have at least - * one IP address. + * one IP address except for `ipvx.method=manual` where static + * routes are allowed to configure even if the connection has + * no addresses * * This code applies to IPv4 and IPv6, however for IPv6 we * early on configure a link local address, so in practice the @@ -1263,6 +1377,13 @@ loop_done: if (singlehop_routes) { for (i = 0; i < singlehop_routes->len; i++) { const NMPObject *obj = singlehop_routes->pdata[i]; + ObjStateData *obj_state; + + obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &obj); + if (!obj_state) + _obj_states_track_new(self, obj, TRUE); + else + _obj_states_track_update(self, obj_state, obj, TRUE); if (!_obj_states_sync_filter(self, obj, commit_type)) continue; @@ -1403,8 +1524,8 @@ _load_link(NML3Cfg *self, gboolean initial) nacd_link_now_up = FALSE; nacd_changed = FALSE; - nacd_old_valid = _acd_has_valid_link(obj_old, &nacd_old_addr, NULL); - nacd_new_valid = _acd_has_valid_link(obj, &nacd_new_addr, NULL); + nacd_old_valid = _acd_has_valid_link(self, obj_old, &nacd_old_addr, NULL); + nacd_new_valid = _acd_has_valid_link(self, obj, &nacd_new_addr, NULL); if (self->priv.p->nacd_instance_ensure_retry) { if (nacd_new_valid && (!nacd_old_valid @@ -1614,7 +1735,8 @@ _acd_data_find_track(const AcdData *acd_data, /*****************************************************************************/ static gboolean -_acd_has_valid_link(const NMPObject *obj, +_acd_has_valid_link(NML3Cfg *self, + const NMPObject *obj, const guint8 **out_addr_bin, gboolean *out_acd_not_supported) { @@ -1635,6 +1757,11 @@ _acd_has_valid_link(const NMPObject *obj, return FALSE; } + if (nm_platform_link_get_ifi_flags(self->priv.platform, self->priv.ifindex, IFF_NOARP)) { + NM_SET_OUT(out_acd_not_supported, TRUE); + return FALSE; + } + NM_SET_OUT(out_acd_not_supported, FALSE); NM_SET_OUT(out_addr_bin, addr_bin); return TRUE; @@ -1787,7 +1914,7 @@ _l3_acd_nacd_instance_ensure_retry_cb(gpointer user_data) nm_clear_g_source_inst(&self->priv.p->nacd_instance_ensure_retry); - _l3_changed_configs_set_dirty(self); + _l3_changed_configs_set_dirty(self, "nacd retry"); nm_l3cfg_commit(self, NM_L3_CFG_COMMIT_TYPE_AUTO); return G_SOURCE_REMOVE; } @@ -1810,7 +1937,7 @@ _l3_acd_nacd_instance_reset(NML3Cfg *self, NMTernary start_timer, gboolean acd_d switch (start_timer) { case NM_TERNARY_FALSE: - _l3_changed_configs_set_dirty(self); + _l3_changed_configs_set_dirty(self, "nacd reset"); nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO); break; case NM_TERNARY_TRUE: @@ -1864,7 +1991,7 @@ again: return NULL; } - valid = _acd_has_valid_link(self->priv.plobj, &addr_bin, &acd_not_supported); + valid = _acd_has_valid_link(self, self->priv.plobj, &addr_bin, &acd_not_supported); if (!valid) goto failed_create_acd; @@ -2325,7 +2452,7 @@ _nm_printf(5, 6) static void _l3_acd_data_state_set_full(NML3Cfg *self, if (changed && allow_commit) { /* The availability of an address just changed (and we are instructed to * trigger a new commit). Do it. */ - _l3_changed_configs_set_dirty(self); + _l3_changed_configs_set_dirty(self, "acd state changed"); nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO); } } @@ -2972,8 +3099,7 @@ handle_start_defending: NM_L3_ACD_ADDR_STATE_READY, !NM_IN_SET(state_change_mode, ACD_STATE_CHANGE_MODE_INIT, - ACD_STATE_CHANGE_MODE_INIT_REAPPLY, - ACD_STATE_CHANGE_MODE_POST_COMMIT), + ACD_STATE_CHANGE_MODE_INIT_REAPPLY), "probe is ready, waiting for address to be configured"); } return; @@ -3053,7 +3179,10 @@ _l3_acd_data_process_changes(NML3Cfg *self) AcdData *acd_data; gint64 now_msec = 0; - _l3_acd_data_prune(self, FALSE); + if (self->priv.p->acd_data_pruning_needed) + _l3_acd_data_prune(self, FALSE); + + self->priv.p->acd_data_pruning_needed = FALSE; c_list_for_each_entry (acd_data, &self->priv.p->acd_lst_head, acd_lst) { _l3_acd_data_state_change(self, @@ -3271,7 +3400,7 @@ nm_l3cfg_commit_on_idle_schedule(NML3Cfg *self, NML3CfgCommitType commit_type) if (self->priv.p->commit_on_idle_source) { if (self->priv.p->commit_on_idle_type < commit_type) { /* For multiple calls, we collect the maximum "commit-type". */ - _LOGT("commit on idle (scheduled) (update to %s)", + _LOGT("schedule commit on idle (upgrade type to %s)", _l3_cfg_commit_type_to_string(commit_type, sbuf_commit_type, sizeof(sbuf_commit_type))); @@ -3280,7 +3409,7 @@ nm_l3cfg_commit_on_idle_schedule(NML3Cfg *self, NML3CfgCommitType commit_type) return FALSE; } - _LOGT("commit on idle (scheduled) (%s)", + _LOGT("schedule commit on idle (%s)", _l3_cfg_commit_type_to_string(commit_type, sbuf_commit_type, sizeof(sbuf_commit_type))); self->priv.p->commit_on_idle_source = nm_g_idle_add_source(_l3_commit_on_idle_cb, self); self->priv.p->commit_on_idle_type = commit_type; @@ -3553,7 +3682,7 @@ nm_l3cfg_add_config(NML3Cfg *self, nm_assert(l3_config_data->acd_defend_type_confdata == acd_defend_type); if (changed) { - _l3_changed_configs_set_dirty(self); + _l3_changed_configs_set_dirty(self, "configuration added"); nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO); } @@ -3590,7 +3719,7 @@ _l3cfg_remove_config(NML3Cfg *self, continue; } - _l3_changed_configs_set_dirty(self); + _l3_changed_configs_set_dirty(self, "configuration removed"); _l3_config_datas_remove_index_fast(self->priv.p->l3_config_datas, idx); changed = TRUE; if (l3cd) { @@ -3783,6 +3912,9 @@ _l3cfg_update_combined_config(NML3Cfg *self, NM_SET_OUT(out_changed_combined_l3cd, FALSE); + if (to_commit) + self->priv.p->acd_data_pruning_needed = FALSE; + if (!self->priv.p->changed_configs_configs) { if (!self->priv.p->changed_configs_acd_state) goto out; @@ -3830,6 +3962,7 @@ _l3cfg_update_combined_config(NML3Cfg *self, self->priv.p->changed_configs_acd_state = TRUE; } else { _l3_acd_data_add_all(self, l3_config_datas_arr, l3_config_datas_len, reapply); + self->priv.p->acd_data_pruning_needed = TRUE; self->priv.p->changed_configs_acd_state = FALSE; } @@ -4827,6 +4960,7 @@ _l3_commit_one(NML3Cfg *self, NMIPRouteTableSyncMode route_table_sync; char sbuf_commit_type[50]; guint i; + gboolean any_dirty = FALSE; nm_assert(NM_IS_L3CFG(self)); nm_assert(NM_IN_SET(commit_type, @@ -4839,6 +4973,9 @@ _l3_commit_one(NML3Cfg *self, nm_utils_addr_family_to_char(addr_family), _l3_cfg_commit_type_to_string(commit_type, sbuf_commit_type, sizeof(sbuf_commit_type))); + if (IS_IPv4) + any_dirty = _obj_states_track_mark_dirty(self, TRUE); + addresses = _commit_collect_addresses(self, addr_family, commit_type); _commit_collect_routes(self, @@ -4863,6 +5000,9 @@ _l3_commit_one(NML3Cfg *self, if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_NONE) route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN; + if (any_dirty) + _obj_states_track_prune_dirty(self, TRUE); + if (commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY) { gs_unref_array GArray *ipv6_temp_addrs_keep = NULL; diff --git a/src/core/nm-l3cfg.h b/src/core/nm-l3cfg.h index 9b8ec67f..241fde02 100644 --- a/src/core/nm-l3cfg.h +++ b/src/core/nm-l3cfg.h @@ -34,8 +34,8 @@ typedef enum _nm_packed { /** * NML3CfgConfigFlags: * @NM_L3CFG_CONFIG_FLAGS_NONE: no flags, the default. - * @NM_L3_CONFIG_MERGE_FLAGS_ONLY_FOR_ACD: if this merge flag is set, - * the the NML3ConfigData doesn't get merged and it's information won't be + * @NM_L3CFG_CONFIG_FLAGS_ONLY_FOR_ACD: if this flag is set, + * the NML3ConfigData doesn't get merged and the information won't be * synced. The only purpose is to run ACD on its IPv4 addresses, but * regardless whether ACD succeeds/fails, the IP addresses won't be configured. * The point is to run ACD first (without configuring it), and only diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index 937acbba..9c58a47d 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -66,7 +66,6 @@ typedef struct { bool user_enabled : 1; bool sw_enabled : 1; bool hw_enabled : 1; - bool os_owner : 1; } RfkillRadioState; #define AUTOCONNECT_RESET_RETRIES_TIMER_SEC 300 @@ -800,7 +799,7 @@ initited: * a lot of stale entries. We must from time to time clean them up. * * Do do this cleanup, whenever we have more entries then 2 times the number of links. */ - if (G_UNLIKELY(g_hash_table_size(priv->device_route_metrics) > NM_MAX(20, n_links * 2))) { + if (G_UNLIKELY(g_hash_table_size(priv->device_route_metrics) > NM_MAX(20u, n_links * 2u))) { /* from time to time, we need to do some house-keeping and prune stale entries. * Otherwise, on a system where interfaces frequently come and go (docker), we * keep growing this cache for ifindexes that no longer exist. */ @@ -2893,9 +2892,6 @@ _rfkill_radio_state_get_enabled(const RfkillRadioState *rstate, gboolean check_c { gboolean enabled; - /* If the device is not owned by the os, hw_enabled will be FALSE, hence - * we don't need to consider os_owner here. - */ enabled = rstate->user_enabled && rstate->hw_enabled; if (check_changeable) enabled &= rstate->sw_enabled; @@ -2912,7 +2908,6 @@ _rfkill_radio_state_set_from_manager(NMManager *self, NMRfkillType rtype, Rfkill case NM_RFKILL_STATE_UNAVAILABLE: rstate->sw_enabled = TRUE; rstate->hw_enabled = TRUE; - rstate->os_owner = TRUE; /* A rfkill-type is available when there is a compatible * killswitch or a compatible device. */ @@ -2928,26 +2923,16 @@ _rfkill_radio_state_set_from_manager(NMManager *self, NMRfkillType rtype, Rfkill rstate->available = TRUE; rstate->sw_enabled = TRUE; rstate->hw_enabled = TRUE; - rstate->os_owner = TRUE; return; case NM_RFKILL_STATE_SOFT_BLOCKED: rstate->available = TRUE; rstate->sw_enabled = FALSE; rstate->hw_enabled = TRUE; - rstate->os_owner = TRUE; return; case NM_RFKILL_STATE_HARD_BLOCKED: rstate->available = TRUE; rstate->sw_enabled = FALSE; rstate->hw_enabled = FALSE; - /* In case the OS doesn't own the NIC, we would be in NM_RFKILL_STATE_HARD_BLOCKED */ - rstate->os_owner = TRUE; - return; - case NM_RFKILL_STATE_HARD_BLOCKED_OS_NOT_OWNER: - rstate->available = TRUE; - rstate->sw_enabled = FALSE; - rstate->hw_enabled = FALSE; - rstate->os_owner = FALSE; return; } nm_assert_not_reached(); @@ -3011,12 +2996,11 @@ _rfkill_update_one_type(NMManager *self, NMRfkillType rtype) /* Print out all states affecting device enablement */ _LOGD(LOGD_RFKILL, - "rfkill: %s available %d hw-enabled %d sw-enabled %d os-owner %d", + "rfkill: %s available %d hw-enabled %d sw-enabled %d", nm_rfkill_type_to_string(rtype), rstate->available, rstate->hw_enabled, - rstate->sw_enabled, - rstate->os_owner); + rstate->sw_enabled); /* Log new killswitch state */ new_rfkilled = rstate->hw_enabled && rstate->sw_enabled; @@ -4440,11 +4424,7 @@ platform_query_devices(NMManager *self) gs_free char *order = NULL; guess_assume = nm_config_get_first_start(nm_config_get()); - order = nm_config_data_get_value(NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_GROUP_MAIN, - NM_CONFIG_KEYFILE_KEY_MAIN_SLAVES_ORDER, - NM_CONFIG_GET_VALUE_STRIP); - links = nm_platform_link_get_all(priv->platform, !nm_streq0(order, "index")); + links = nm_platform_link_get_all(priv->platform); if (!links) return; for (i = 0; i < links->len; i++) { @@ -4867,7 +4847,7 @@ is_compatible_with_slave(NMConnection *master, NMConnection *slave) s_con = nm_connection_get_setting_connection(slave); g_assert(s_con); - return nm_connection_is_type(master, nm_setting_connection_get_slave_type(s_con)); + return nm_connection_is_type(master, nm_setting_connection_get_port_type(s_con)); } /** @@ -5380,7 +5360,7 @@ out: } static int -compare_slaves(gconstpointer a, gconstpointer b, gpointer sort_by_name) +compare_slaves(gconstpointer a, gconstpointer b) { const SlaveConnectionInfo *a_info = a; const SlaveConnectionInfo *b_info = b; @@ -5391,11 +5371,7 @@ compare_slaves(gconstpointer a, gconstpointer b, gpointer sort_by_name) if (!b_info->device) return -1; - if (GPOINTER_TO_INT(sort_by_name)) { - return nm_strcmp0(nm_device_get_iface(a_info->device), nm_device_get_iface(b_info->device)); - } - - return nm_device_get_ifindex(a_info->device) - nm_device_get_ifindex(b_info->device); + return nm_strcmp0(nm_device_get_iface(a_info->device), nm_device_get_iface(b_info->device)); } static void @@ -5415,17 +5391,7 @@ autoconnect_slaves(NMManager *self, slaves = find_slaves(self, master_connection, master_device, &n_slaves, for_user_request); if (n_slaves > 1) { - gs_free char *value = NULL; - - value = nm_config_data_get_value(NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_GROUP_MAIN, - NM_CONFIG_KEYFILE_KEY_MAIN_SLAVES_ORDER, - NM_CONFIG_GET_VALUE_STRIP); - g_qsort_with_data(slaves, - n_slaves, - sizeof(slaves[0]), - compare_slaves, - GINT_TO_POINTER(!nm_streq0(value, "index"))); + qsort(slaves, n_slaves, sizeof(slaves[0]), compare_slaves); } bind_lifetime_to_profile_visibility = @@ -7354,14 +7320,12 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed) gboolean enabled = _rfkill_radio_state_get_enabled(rstate, TRUE); _LOGD(LOGD_RFKILL, - "rfkill: %s %s devices (hw_enabled %d, sw_enabled %d, user_enabled %d, " - "os_owner %d)", + "rfkill: %s %s devices (hw_enabled %d, sw_enabled %d, user_enabled %d)", enabled ? "enabling" : "disabling", nm_rfkill_type_to_string(rtype), rstate->hw_enabled, rstate->sw_enabled, - rstate->user_enabled, - rstate->os_owner); + rstate->user_enabled); if (nm_device_get_rfkill_type(device) == rtype) nm_device_set_enabled(device, enabled); } @@ -8846,13 +8810,11 @@ nm_manager_init(NMManager *self) .user_enabled = TRUE, .sw_enabled = FALSE, .hw_enabled = TRUE, - .os_owner = TRUE, }; priv->radio_states[NM_RFKILL_TYPE_WWAN] = (RfkillRadioState){ .user_enabled = TRUE, .sw_enabled = FALSE, .hw_enabled = TRUE, - .os_owner = TRUE, }; priv->sleeping = FALSE; @@ -9402,10 +9364,13 @@ static const NMDBusInterfaceInfoExtended interface_info_manager = { "b", NM_MANAGER_WIMAX_ENABLED, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX, - NM_AUDIT_OP_RADIO_CONTROL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WimaxHardwareEnabled", - "b", - NM_MANAGER_WIMAX_HARDWARE_ENABLED), + NM_AUDIT_OP_RADIO_CONTROL, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( + "WimaxHardwareEnabled", + "b", + NM_MANAGER_WIMAX_HARDWARE_ENABLED, + .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("RadioFlags", "u", NM_MANAGER_RADIO_FLAGS), diff --git a/src/core/nm-netns.c b/src/core/nm-netns.c index ad156f99..ed33d336 100644 --- a/src/core/nm-netns.c +++ b/src/core/nm-netns.c @@ -905,11 +905,19 @@ nm_netns_ip_route_ecmp_commit(NMNetns *self, if (obj_del) { if (NMP_OBJECT_CAST_IP4_ROUTE(obj_del)->n_nexthops > 1) nm_platform_object_delete(priv->platform, obj_del); - else if (track_obj->l3cfg != l3cfg) - nm_l3cfg_commit_on_idle_schedule(track_obj->l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO); + else if (NMP_OBJECT_CAST_IP4_ROUTE(obj_del)->ifindex != nm_l3cfg_get_ifindex(l3cfg)) { + /* A single-hop route from a different interface was merged + * into a ECMP route. Now, it is time to notify the l3cfg that + * is managing that single-hop route to remove it. */ + nm_l3cfg_commit_on_idle_schedule( + nm_netns_l3cfg_get(self, NMP_OBJECT_CAST_IP4_ROUTE(obj_del)->ifindex), + NM_L3_CFG_COMMIT_TYPE_UPDATE); + } } if (route->n_nexthops <= 1) { + NMPObject *route_clone; + /* This is a single hop route. Return it to the caller. */ if (!*out_singlehop_routes) { /* Note that the returned array does not own a reference. This @@ -918,7 +926,28 @@ nm_netns_ip_route_ecmp_commit(NMNetns *self, *out_singlehop_routes = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); } - g_ptr_array_add(*out_singlehop_routes, (gpointer) nmp_object_ref(route_obj)); + + /* We have here a IPv4 single-hop route. For internal tracking purposes, + * this route has a positive "weight" (which was used to mark it as a candidate + * for ECMP merging). Now we want to return this route to NML3Cfg and add it + * as regular single-hop routes. + * + * A single-hop route in kernel always has a "weight" of zero. This route + * cannot be added as-is. Well, if we would, then the result would be + * a different(!) route (with a zero "weight"). + * + * Anticipate that and normalize the route now to be a regular single-hop + * route (with weight zero). nm_platform_ip_route_normalize() does that. + * We really want to return a regular route here, not the route with a positive + * weight that exists for internal tracking purposes. + */ + nm_assert(NMP_OBJECT_GET_TYPE(route_obj) == NMP_OBJECT_TYPE_IP4_ROUTE); + nm_assert(route_obj->ip4_route.weight > 0u); + + route_clone = nmp_object_clone(route_obj, FALSE); + nm_platform_ip_route_normalize(AF_INET, NMP_OBJECT_CAST_IP_ROUTE(route_clone)); + g_ptr_array_add(*out_singlehop_routes, route_clone); + if (changed) { _LOGT("ecmp-route: single-hop %s", nmp_object_to_string(route_obj, diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index efdb0636..feea97b1 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -1766,7 +1766,7 @@ _connection_autoconnect_retries_set(NMPolicy *self, nm_assert(retry_time != 0); priv->reset_connections_retries_idle_source = nm_g_timeout_add_seconds_source( - MAX(0, retry_time - nm_utils_get_monotonic_timestamp_sec()), + NM_MAX(0, retry_time - nm_utils_get_monotonic_timestamp_sec()), reset_connections_retries, self); } @@ -2635,11 +2635,15 @@ dns_config_changed(NMDnsManager *dns_manager, gpointer user_data) if (priv->updating_dns) return; - nm_manager_for_each_device (priv->manager, device, tmp_lst) { - nm_device_clear_dns_lookup_data(device, "DNS configuration changed"); + if (!nm_dns_manager_is_unmanaged(dns_manager)) { + nm_manager_for_each_device (priv->manager, device, tmp_lst) { + nm_device_clear_dns_lookup_data(device, "DNS configuration changed"); + } + + update_system_hostname(self, "DNS configuration changed"); } - update_system_hostname(self, "DNS configuration changed"); + nm_dispatcher_call_dns_change(); } static void diff --git a/src/core/nm-rfkill-manager.c b/src/core/nm-rfkill-manager.c index 03333899..aea5df11 100644 --- a/src/core/nm-rfkill-manager.c +++ b/src/core/nm-rfkill-manager.c @@ -106,8 +106,6 @@ nm_rfkill_state_to_string(NMRfkillState state) return "soft-blocked"; case NM_RFKILL_STATE_HARD_BLOCKED: return "hard-blocked"; - case NM_RFKILL_STATE_HARD_BLOCKED_OS_NOT_OWNER: - return "hard-blocked-os-not-owner"; } return nm_assert_unreachable_val("unknown"); } @@ -171,7 +169,7 @@ killswitch_destroy(Killswitch *ks) } static NMRfkillState -sysfs_state_to_nm_state(int sysfs_state, int sysfs_reason) +sysfs_state_to_nm_state(int sysfs_state) { switch (sysfs_state) { case 0: @@ -179,11 +177,6 @@ sysfs_state_to_nm_state(int sysfs_state, int sysfs_reason) case 1: return NM_RFKILL_STATE_UNBLOCKED; case 2: - /* sysfs reason is a bitmap, in case we have both reasons (SIGNAL and NOT_OWNER), we want - * to consider the device as not owned. - */ - if (sysfs_reason & 2) - return NM_RFKILL_STATE_HARD_BLOCKED_OS_NOT_OWNER; return NM_RFKILL_STATE_HARD_BLOCKED; default: nm_log_warn(LOGD_RFKILL, "unhandled rfkill state %d", sysfs_state); @@ -214,7 +207,6 @@ recheck_killswitches(NMRfkillManager *self) struct udev_device *device; NMRfkillState dev_state; int sysfs_state; - int sysfs_reason; device = udev_device_new_from_subsystem_sysname(nm_udev_client_get_udev(priv->udev_client), "rfkill", @@ -227,24 +219,15 @@ recheck_killswitches(NMRfkillManager *self) G_MININT, G_MAXINT, -1); - - sysfs_reason = _nm_utils_ascii_str_to_int64( - udev_device_get_property_value(device, "RFKILL_HW_BLOCK_REASON"), - 16, - G_MININT, - G_MAXINT, - 1); /* defaults to SIGNAL in case the kernel does not support this */ - - dev_state = sysfs_state_to_nm_state(sysfs_state, sysfs_reason); + dev_state = sysfs_state_to_nm_state(sysfs_state); nm_log_dbg(LOGD_RFKILL, - "%s rfkill%s switch %s state now %d/%s reason: 0x%x", + "%s rfkill%s switch %s state now %d/%s", nm_rfkill_type_to_string(ks->rtype), ks->platform ? " platform" : "", ks->name, sysfs_state, - nm_rfkill_state_to_string(dev_state), - sysfs_reason); + nm_rfkill_state_to_string(dev_state)); if (ks->platform == FALSE) { if (dev_state > poll_states[ks->rtype]) diff --git a/src/core/nm-rfkill-manager.h b/src/core/nm-rfkill-manager.h index 818ab4b2..7e90c9ac 100644 --- a/src/core/nm-rfkill-manager.h +++ b/src/core/nm-rfkill-manager.h @@ -12,13 +12,6 @@ typedef enum { NM_RFKILL_STATE_UNBLOCKED = 1, NM_RFKILL_STATE_SOFT_BLOCKED = 2, NM_RFKILL_STATE_HARD_BLOCKED = 3, - /* NM_RFKILL_STATE_HARD_BLOCKED_OS_NOT_OWNER means that the CSME firmware - * is currently controlling the device. This feature is implmented on Intel - * wifi devices only. - * The NetworkManager can get ownership on the device, but it requires to - * first ask ownership through the iwlmei kernel module. - */ - NM_RFKILL_STATE_HARD_BLOCKED_OS_NOT_OWNER = 4, } NMRfkillState; typedef enum { diff --git a/src/core/nm-types.h b/src/core/nm-types.h index 18f44ca9..104a2f4b 100644 --- a/src/core/nm-types.h +++ b/src/core/nm-types.h @@ -6,7 +6,7 @@ #ifndef __NETWORKMANAGER_TYPES_H__ #define __NETWORKMANAGER_TYPES_H__ -#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON) +#if !((NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_DAEMON) #error Cannot use this header. #endif diff --git a/src/core/platform/nm-fake-platform.c b/src/core/platform/nm-fake-platform.c index f6f377d4..74bbe4fb 100644 --- a/src/core/platform/nm-fake-platform.c +++ b/src/core/platform/nm-fake-platform.c @@ -720,6 +720,14 @@ link_change(NMPlatform *platform, obj_tmp->link.port_data.bond.prio = port_data->bond.prio; link_set_obj(platform, device, obj_tmp); return TRUE; + case NM_PORT_KIND_BRIDGE: + obj_tmp = nmp_object_clone(device->obj, FALSE); + obj_tmp->link.port_kind = NM_PORT_KIND_BRIDGE; + obj_tmp->link.port_data.bridge.path_cost = port_data->bridge.path_cost; + obj_tmp->link.port_data.bridge.priority = port_data->bridge.priority; + obj_tmp->link.port_data.bridge.hairpin = port_data->bridge.hairpin; + link_set_obj(platform, device, obj_tmp); + return TRUE; case NM_PORT_KIND_NONE: return TRUE; } diff --git a/src/core/platform/tests/test-common.h b/src/core/platform/tests/test-common.h index 2802d8fd..12d6e7ce 100644 --- a/src/core/platform/tests/test-common.h +++ b/src/core/platform/tests/test-common.h @@ -32,7 +32,7 @@ * Normalize the requested_value to the kernel_value, if it look as if a rounding * error happens. If the difference is larger than +/- 1, no normalization happens! */ \ \ - ((_requested_value >= (NM_MAX(_kernel_value, 1) - 1)) \ + ((_requested_value >= (NM_MAX(_kernel_value, (typeof(_kernel_value)) 1) - 1)) \ && (_requested_value <= (NM_MIN(_kernel_value, ~((typeof(_kernel_value)) 0) - 1) + 1))) \ ? _kernel_value \ : _requested_value; \ diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c index 8a54ac48..c931605b 100644 --- a/src/core/platform/tests/test-link.c +++ b/src/core/platform/tests/test-link.c @@ -230,7 +230,6 @@ test_port(int controller, int port_type, SignalData *controller_changed) link_callback, SLAVE_NAME); SignalData *link_changed, *link_removed; - char *value; NMLinkType controller_type = nm_platform_link_get_type(NM_PLATFORM_GET, controller); gboolean test_link_changed_signal_arg1; gboolean test_link_changed_signal_arg2; @@ -296,7 +295,7 @@ test_port(int controller, int port_type, SignalData *controller_changed) .prio = prio_has ? 6 : 0, }; - g_assert(nm_platform_link_change(NM_PLATFORM_GET, ifindex_port, NULL, &bond_port, 0)); + g_assert(nm_platform_link_change(NM_PLATFORM_GET, ifindex_port, NULL, &bond_port, NULL, 0)); accept_signals(link_changed, 1, 3); link = nmtstp_link_get(NM_PLATFORM_GET, ifindex_port, SLAVE_NAME); @@ -306,13 +305,35 @@ test_port(int controller, int port_type, SignalData *controller_changed) } else if (controller_type == NM_LINK_TYPE_BRIDGE) { /* Skip this part for nm-fake-platform */ if (nmtstp_is_root_test() && nmtstp_is_sysfs_writable()) { - g_assert(nm_platform_sysctl_slave_set_option(NM_PLATFORM_GET, - ifindex_port, - "priority", - "614")); - value = nm_platform_sysctl_slave_get_option(NM_PLATFORM_GET, ifindex_port, "priority"); - g_assert_cmpstr(value, ==, "614"); - g_free(value); + NMPlatformLinkBridgePort bridge_port; + const NMPlatformLink *link; + const NMPlatformLnkBridge *lnk; + + link = nmtstp_link_get_typed(NM_PLATFORM_GET, 0, SLAVE_NAME, NM_LINK_TYPE_DUMMY); + g_assert(link); + + lnk = nm_platform_link_get_lnk_bridge(NM_PLATFORM_GET, controller, NULL); + g_assert(lnk); + + bridge_port = (NMPlatformLinkBridgePort){ + .path_cost = 100, + .priority = 614, + .hairpin = 0, + }; + + g_assert(nm_platform_link_change(NM_PLATFORM_GET, + ifindex_port, + NULL, + NULL, + &bridge_port, + 0)); + accept_signals(link_changed, 1, 3); + + link = nmtstp_link_get(NM_PLATFORM_GET, ifindex_port, SLAVE_NAME); + g_assert(link); + g_assert_cmpint(link->port_data.bridge.path_cost, ==, 100); + g_assert_cmpint(link->port_data.bridge.priority, ==, 614); + g_assert_cmpint(link->port_data.bridge.hairpin, ==, 0); } } @@ -2692,7 +2713,7 @@ test_link_set_properties(void) | NM_PLATFORM_LINK_CHANGE_GSO_MAX_SEGMENTS; ifindex = nmtstp_link_dummy_add(NM_PLATFORM_GET, FALSE, "dummy1")->ifindex; - g_assert(nm_platform_link_change(NM_PLATFORM_GET, ifindex, &props, NULL, flags)); + g_assert(nm_platform_link_change(NM_PLATFORM_GET, ifindex, &props, NULL, NULL, flags)); link = nmtstp_link_get(NM_PLATFORM_GET, ifindex, "dummy1"); g_assert(link); diff --git a/src/core/platform/tests/test-platform-general.c b/src/core/platform/tests/test-platform-general.c index cebd44f6..fd6aae82 100644 --- a/src/core/platform/tests/test-platform-general.c +++ b/src/core/platform/tests/test-platform-general.c @@ -44,7 +44,7 @@ test_link_get_all(void) platform = nm_linux_platform_new(NULL, TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT, TRUE); - links = nm_platform_link_get_all(platform, TRUE); + links = nm_platform_link_get_all(platform); } /*****************************************************************************/ diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c index 8796de36..7fc20298 100644 --- a/src/core/settings/nm-settings.c +++ b/src/core/settings/nm-settings.c @@ -3530,7 +3530,7 @@ load_plugins(NMSettings *self, const char *const *plugins, GError **error) continue; } - if (nm_strv_find_first(plugins, iter - plugins, pname) >= 0) { + if (nm_strv_contains(plugins, iter - plugins, pname)) { /* the plugin is already mentioned in the list previously. * Don't load a duplicate. */ continue; 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 84a9479d..04e79725 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 @@ -306,7 +306,7 @@ check_if_bond_slave(shvarFile *ifcfg, NMSettingConnection *s_con) } g_object_set(s_con, - NM_SETTING_CONNECTION_MASTER, + NM_SETTING_CONNECTION_CONTROLLER, v, NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME, @@ -340,7 +340,7 @@ check_if_team_slave(shvarFile *ifcfg, NMSettingConnection *s_con) } g_object_set(s_con, - NM_SETTING_CONNECTION_MASTER, + NM_SETTING_CONNECTION_CONTROLLER, v, NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, @@ -512,7 +512,7 @@ make_connection_setting(const char *file, old_value, v); } else { - g_object_set(s_con, NM_SETTING_CONNECTION_MASTER, v, NULL); + g_object_set(s_con, NM_SETTING_CONNECTION_CONTROLLER, v, NULL); g_object_set(s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BRIDGE_SETTING_NAME, @@ -535,7 +535,7 @@ make_connection_setting(const char *file, old_value, v); } else { - g_object_set(s_con, NM_SETTING_CONNECTION_MASTER, v, NULL); + g_object_set(s_con, NM_SETTING_CONNECTION_CONTROLLER, v, NULL); g_object_set(s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_OVS_PORT_SETTING_NAME, @@ -555,7 +555,7 @@ make_connection_setting(const char *file, old_value, v); } else { - g_object_set(s_con, NM_SETTING_CONNECTION_MASTER, v, NULL); + g_object_set(s_con, NM_SETTING_CONNECTION_CONTROLLER, v, NULL); g_object_set(s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_VRF_SETTING_NAME, 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 08deaf5a..e703bb73 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 @@ -1346,6 +1346,7 @@ write_ethtool_setting(NMConnection *connection, shvarFile *ifcfg, GError **error guint32 u32; gboolean b; gboolean any_option = FALSE; + char prop_name[300]; s_con = nm_connection_get_setting_connection(connection); if (s_con) { @@ -1426,6 +1427,30 @@ write_ethtool_setting(NMConnection *connection, shvarFile *ifcfg, GError **error any_option = TRUE; } + is_first = TRUE; + for (ethtool_id = _NM_ETHTOOL_ID_CHANNELS_FIRST; ethtool_id <= _NM_ETHTOOL_ID_CHANNELS_LAST; + ethtool_id++) { + if (nm_setting_option_get_uint32(NM_SETTING(s_ethtool), + nm_ethtool_data[ethtool_id]->optname, + &u32)) { + nm_sprintf_buf(prop_name, "ethtool.%s", nm_ethtool_data[ethtool_id]->optname); + set_error_unsupported(error, connection, prop_name, FALSE); + return FALSE; + } + } + + is_first = TRUE; + for (ethtool_id = _NM_ETHTOOL_ID_EEE_FIRST; ethtool_id <= _NM_ETHTOOL_ID_EEE_LAST; + ethtool_id++) { + if (nm_setting_option_get_boolean(NM_SETTING(s_ethtool), + nm_ethtool_data[ethtool_id]->optname, + &b)) { + nm_sprintf_buf(prop_name, "ethtool.%s", nm_ethtool_data[ethtool_id]->optname); + set_error_unsupported(error, connection, prop_name, FALSE); + return FALSE; + } + } + if (!any_option) { /* Write an empty dummy "-A" option without arguments. This is to * ensure that the reader will create an (all default) NMSettingEthtool. @@ -2235,34 +2260,38 @@ write_connection_setting(NMSettingConnection *s_con, shvarFile *ifcfg, const cha master = NULL; } - if (nm_setting_connection_is_slave_type(s_con, NM_SETTING_BOND_SETTING_NAME)) { + if (nm_streq0(nm_setting_connection_get_port_type(s_con), NM_SETTING_BOND_SETTING_NAME)) { svSetValueStr(ifcfg, "MASTER_UUID", master); svSetValueStr(ifcfg, "MASTER", master_iface); svSetValueStr(ifcfg, "SLAVE", "yes"); - } else if (nm_setting_connection_is_slave_type(s_con, NM_SETTING_BRIDGE_SETTING_NAME)) { + } else if (nm_streq0(nm_setting_connection_get_port_type(s_con), + NM_SETTING_BRIDGE_SETTING_NAME)) { svSetValueStr(ifcfg, "BRIDGE_UUID", master); svSetValueStr(ifcfg, "BRIDGE", master_iface); - } else if (nm_setting_connection_is_slave_type(s_con, NM_SETTING_TEAM_SETTING_NAME)) { + } else if (nm_streq0(nm_setting_connection_get_port_type(s_con), + NM_SETTING_TEAM_SETTING_NAME)) { svSetValueStr(ifcfg, "TEAM_MASTER_UUID", master); svSetValueStr(ifcfg, "TEAM_MASTER", master_iface); if (NM_IN_STRSET(type, NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_VLAN_SETTING_NAME)) svUnsetValue(ifcfg, "TYPE"); - } else if (nm_setting_connection_is_slave_type(s_con, NM_SETTING_OVS_PORT_SETTING_NAME)) { + } else if (nm_streq0(nm_setting_connection_get_port_type(s_con), + NM_SETTING_OVS_PORT_SETTING_NAME)) { svSetValueStr(ifcfg, "OVS_PORT_UUID", master); svSetValueStr(ifcfg, "OVS_PORT", master_iface); - } else if (nm_setting_connection_is_slave_type(s_con, NM_SETTING_VRF_SETTING_NAME)) { + } else if (nm_streq0(nm_setting_connection_get_port_type(s_con), + NM_SETTING_VRF_SETTING_NAME)) { svSetValueStr(ifcfg, "VRF_UUID", master); svSetValueStr(ifcfg, "VRF", master_iface); } else { _LOGW("don't know how to set master for a %s slave", - nm_setting_connection_get_slave_type(s_con)); + nm_setting_connection_get_port_type(s_con)); } } if (nm_streq0(type, NM_SETTING_TEAM_SETTING_NAME)) svSetValueStr(ifcfg, "DEVICETYPE", TYPE_TEAM); else if (master_iface - && nm_setting_connection_is_slave_type(s_con, NM_SETTING_TEAM_SETTING_NAME)) + && nm_streq0(nm_setting_connection_get_port_type(s_con), NM_SETTING_TEAM_SETTING_NAME)) svSetValueStr(ifcfg, "DEVICETYPE", TYPE_TEAM_PORT); /* secondary connection UUIDs */ 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 8c1e9d94..1e6b6c25 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 @@ -2231,7 +2231,7 @@ test_clear_master(void) s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION); g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, "br0"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, "bridge"); + g_assert_cmpstr(nm_setting_connection_get_port_type(s_con), ==, "bridge"); /* 2. write the connection to a new file */ _writer_new_connec_exp(connection, @@ -2248,7 +2248,7 @@ test_clear_master(void) NULL); g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, NULL); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NULL); + g_assert_cmpstr(nm_setting_connection_get_port_type(s_con), ==, NULL); nmtst_assert_connection_verifies_after_normalization(connection, 0, 0); @@ -3623,6 +3623,11 @@ test_roundtrip_ethtool(void) optname = nm_ethtool_data[ethtool_id]->optname; vtype = nm_ethtool_id_get_variant_type(ethtool_id); + if (nm_ethtool_optname_is_channels(optname) || nm_ethtool_optname_is_eee(optname)) { + /* Not supported */ + continue; + } + if (NM_IN_SET(ethtool_id, NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX, NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX)) { @@ -7664,9 +7669,7 @@ test_read_bridge_component(void) s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION); g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, "br0"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), - ==, - NM_SETTING_BRIDGE_SETTING_NAME); + g_assert_cmpstr(nm_setting_connection_get_port_type(s_con), ==, NM_SETTING_BRIDGE_SETTING_NAME); s_port = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_BRIDGE_PORT); g_assert(nm_setting_bridge_port_get_hairpin_mode(s_port)); @@ -8259,7 +8262,7 @@ test_read_bond_slave(void) g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, "bond0"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME); + g_assert_cmpstr(nm_setting_connection_get_port_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME); } static void @@ -8315,7 +8318,7 @@ test_read_bond_port(void) s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION); g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, "bond99"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME); + g_assert_cmpstr(nm_setting_connection_get_port_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME); s_port = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_BOND_PORT); g_assert_cmpuint(nm_setting_bond_port_get_queue_id(s_port), ==, 1); @@ -8554,7 +8557,7 @@ test_read_bond_slave_ib(void) s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION); g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, "bond0"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME); + g_assert_cmpstr(nm_setting_connection_get_port_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME); } static void diff --git a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c index 866b1ffd..b26bad69 100644 --- a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c +++ b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c @@ -2004,7 +2004,7 @@ test_read_bridge_component(void) g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, expected_id); g_assert_cmpstr(nm_setting_connection_get_uuid(s_con), ==, expected_uuid); g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, "br0"); - g_assert(nm_setting_connection_is_slave_type(s_con, NM_SETTING_BRIDGE_SETTING_NAME)); + g_assert_cmpstr(nm_setting_connection_get_port_type(s_con), ==, NM_SETTING_BRIDGE_SETTING_NAME); s_wired = nm_connection_get_setting_wired(connection); g_assert(s_wired); @@ -2046,9 +2046,9 @@ test_write_bridge_component(void) TRUE, NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_CONNECTION_MASTER, + NM_SETTING_CONNECTION_CONTROLLER, "br0", - NM_SETTING_CONNECTION_SLAVE_TYPE, + NM_SETTING_CONNECTION_PORT_TYPE, NM_SETTING_BRIDGE_SETTING_NAME, NULL); @@ -2357,9 +2357,9 @@ test_read_minimal_slave(void) NM_SETTING_WIRED_SETTING_NAME, &s_con); g_object_set(s_con, - NM_SETTING_CONNECTION_MASTER, + NM_SETTING_CONNECTION_CONTROLLER, "br0", - NM_SETTING_CONNECTION_SLAVE_TYPE, + NM_SETTING_CONNECTION_PORT_TYPE, "bridge", NULL); nmtst_connection_normalize(con_archetype); diff --git a/src/core/supplicant/nm-supplicant-interface.c b/src/core/supplicant/nm-supplicant-interface.c index 18525724..eb7a40a5 100644 --- a/src/core/supplicant/nm-supplicant-interface.c +++ b/src/core/supplicant/nm-supplicant-interface.c @@ -689,7 +689,7 @@ _bss_info_properties_changed(NMSupplicantInterface *self, v_v = nm_g_variant_lookup_value(properties, "SSID", G_VARIANT_TYPE_BYTESTRING); if (v_v) { arr_data = g_variant_get_fixed_array(v_v, &arr_len, 1); - arr_len = MIN(32, arr_len); + arr_len = NM_MIN(32u, arr_len); /* Stupid ieee80211 layer uses <hidden> */ if (arr_data && arr_len @@ -765,9 +765,15 @@ _bss_info_properties_changed(NMSupplicantInterface *self, gboolean p_owe_transition_mode; gboolean p_metered; guint32 rate; + guint32 bandwidth; arr_data = g_variant_get_fixed_array(v_v, &arr_len, 1); - nm_wifi_utils_parse_ies(arr_data, arr_len, &rate, &p_metered, &p_owe_transition_mode); + nm_wifi_utils_parse_ies(arr_data, + arr_len, + &rate, + &bandwidth, + &p_metered, + &p_owe_transition_mode); p_max_rate = NM_MAX(p_max_rate, rate); p_max_rate_has = TRUE; g_variant_unref(v_v); @@ -777,7 +783,8 @@ _bss_info_properties_changed(NMSupplicantInterface *self, else bss_info->rsn_flags &= ~NM_802_11_AP_SEC_KEY_MGMT_OWE_TM; - bss_info->metered = p_metered; + bss_info->metered = p_metered; + bss_info->bandwidth = bandwidth; } if (p_max_rate_has) @@ -1373,7 +1380,7 @@ _get_capability(NMSupplicantInterfacePrivate *priv, NMSupplCapType type) case NM_SUPPL_CAP_TYPE_AP: iface_value = NM_SUPPL_CAP_MASK_GET(priv->iface_capabilities, type); value = NM_SUPPL_CAP_MASK_GET(priv->global_capabilities, type); - value = MAX(iface_value, value); + value = NM_MAX(iface_value, value); break; case NM_SUPPL_CAP_TYPE_FT: value = NM_SUPPL_CAP_MASK_GET(priv->global_capabilities, type); diff --git a/src/core/supplicant/nm-supplicant-settings-verify.c b/src/core/supplicant/nm-supplicant-settings-verify.c index fc40bade..8f2561a6 100644 --- a/src/core/supplicant/nm-supplicant-settings-verify.c +++ b/src/core/supplicant/nm-supplicant-settings-verify.c @@ -228,7 +228,7 @@ validate_type_keyword(const struct Opt *opt, const char *value, const guint32 le s++; } - if (nm_strv_find_first(opt->str_allowed, -1, value) < 0) + if (!nm_strv_contains(opt->str_allowed, -1, value)) return FALSE; if (!s) diff --git a/src/core/supplicant/nm-supplicant-types.h b/src/core/supplicant/nm-supplicant-types.h index 1ae67e13..870a53c3 100644 --- a/src/core/supplicant/nm-supplicant-types.h +++ b/src/core/supplicant/nm-supplicant-types.h @@ -55,9 +55,9 @@ typedef enum { _NM_SUPPL_CAP_TYPE_NUM, } NMSupplCapType; -#define NM_SUPPL_CAP_MASK_NO(type) ((NMSupplCapMask) (1llu << ((type) *2u))) -#define NM_SUPPL_CAP_MASK_YES(type) ((NMSupplCapMask) (2llu << ((type) *2u))) -#define NM_SUPPL_CAP_MASK_MASK(type) ((NMSupplCapMask) (3llu << ((type) *2u))) +#define NM_SUPPL_CAP_MASK_NO(type) ((NMSupplCapMask) (1llu << ((type) * 2u))) +#define NM_SUPPL_CAP_MASK_YES(type) ((NMSupplCapMask) (2llu << ((type) * 2u))) +#define NM_SUPPL_CAP_MASK_MASK(type) ((NMSupplCapMask) (3llu << ((type) * 2u))) typedef enum { NM_SUPPL_CAP_MASK_NONE = 0, @@ -179,6 +179,8 @@ typedef struct _NMSupplicantBssInfo { guint32 max_rate; + guint32 bandwidth; + guint8 signal_percent; NMEtherAddr bssid; diff --git a/src/core/tests/test-core-with-expect.c b/src/core/tests/test-core-with-expect.c index 01510126..680843fc 100644 --- a/src/core/tests/test-core-with-expect.c +++ b/src/core/tests/test-core-with-expect.c @@ -617,7 +617,7 @@ test_nmp_utils_new_vlan_name(void) g_assert(ifname && ifname[0]); g_assert_cmpint(strlen(ifname), ==, - MIN(15, strlen(parent_names[i]) + strlen(vlan_id_s))); + NM_MIN(15u, strlen(parent_names[i]) + strlen(vlan_id_s))); g_assert(g_str_has_suffix(ifname, vlan_id_s)); g_assert(ifname[strlen(ifname) - strlen(vlan_id_s)] == '.'); g_assert(strncmp(ifname, parent_names[i], strlen(ifname) - strlen(vlan_id_s)) == 0); diff --git a/src/core/tests/test-core.c b/src/core/tests/test-core.c index 8296d745..e90cf6e9 100644 --- a/src/core/tests/test-core.c +++ b/src/core/tests/test-core.c @@ -302,7 +302,7 @@ test_nm_utils_log_connection_diff(void) g_object_set(nm_connection_get_setting_connection(connection2), NM_SETTING_CONNECTION_ID, "id2", - NM_SETTING_CONNECTION_MASTER, + NM_SETTING_CONNECTION_CONTROLLER, "master2", NULL); nm_utils_log_connection_diff(connection, @@ -2104,8 +2104,19 @@ do_test_stable_id_parse(const char *stable_id, NMUtilsStableType expected_stable_type, const char *expected_generated) { - gs_free char *generated = NULL; - NMUtilsStableType stable_type; + gs_free char *generated = NULL; + NMUtilsStableType stable_type; + char ssid_bin[] = "SSID(\202)"; + gs_unref_bytes GBytes *ssid = g_bytes_new_static(ssid_bin, sizeof(ssid_bin) - 1); + + while (TRUE) { + if (NM_STR_HAS_PREFIX(stable_id, "NO_SSID:")) { + stable_id += NM_STRLEN("NO_SSID:"); + nm_clear_pointer(&ssid, g_bytes_unref); + continue; + } + break; + } if (expected_stable_type == NM_UTILS_STABLE_TYPE_GENERATED) g_assert(expected_generated); @@ -2117,8 +2128,13 @@ do_test_stable_id_parse(const char *stable_id, else g_assert(stable_id); - stable_type = - nm_utils_stable_id_parse(stable_id, "_DEVICE", "_MAC", "_BOOT", "_CONNECTION", &generated); + stable_type = nm_utils_stable_id_parse(stable_id, + "_DEVICE", + "_MAC", + "_BOOT", + "_CONNECTION", + ssid, + &generated); g_assert_cmpint(expected_stable_type, ==, stable_type); @@ -2160,6 +2176,12 @@ test_stable_id_parse(void) _parse_generated("${${CONNECTION}", "${${CONNECTION}=11{_CONNECTION}"); _parse_generated("${CONNECTION}x", "${CONNECTION}=11{_CONNECTION}x"); _parse_generated("x${CONNECTION}", "x${CONNECTION}=11{_CONNECTION}"); + _parse_generated("x${CONNECTION}${NETWORK_SSID}", + "x${CONNECTION}=11{_CONNECTION}${NETWORK_SSID}=12{s:SSID(\\202)}"); + _parse_generated("NO_SSID:x${CONNECTION}${NETWORK_SSID}", + "x${CONNECTION}=11{_CONNECTION}${NETWORK_SSID}=13{c:_CONNECTION}"); + _parse_generated("${NETWORK_SSID}", "${NETWORK_SSID}=12{s:SSID(\\202)}"); + _parse_generated("NO_SSID:${NETWORK_SSID}", "${NETWORK_SSID}=13{c:_CONNECTION}"); _parse_generated("${BOOT}x", "${BOOT}=5{_BOOT}x"); _parse_generated("x${BOOT}", "x${BOOT}=5{_BOOT}"); _parse_generated("x${BOOT}${CONNECTION}", "x${BOOT}=5{_BOOT}${CONNECTION}=11{_CONNECTION}"); @@ -2169,6 +2191,30 @@ test_stable_id_parse(void) _parse_random("${RANDOM}"); _parse_random(" ${RANDOM}"); _parse_random("${BOOT}${RANDOM}"); + + { + gs_free char *str = NULL; + char ssid_bin[] = "foo\n"; + gs_unref_bytes GBytes *ssid = g_bytes_new_static(ssid_bin, sizeof(ssid_bin) - 1); + NMUtilsStableType stable_type; + + stable_type = nm_utils_stable_id_parse_network_ssid(ssid, "uuid", FALSE, &str); + + g_assert_cmpint(stable_type, ==, NM_UTILS_STABLE_TYPE_GENERATED); + g_assert_cmpstr(str, ==, "${NETWORK_SSID}=9{s:foo\\012}"); + + nm_clear_g_free(&str); + + stable_type = nm_utils_stable_id_parse_network_ssid(ssid, "uuid", TRUE, &str); + + g_assert_cmpint(stable_type, ==, NM_UTILS_STABLE_TYPE_GENERATED); + g_assert_cmpstr(str, ==, "wqLBg0FtOnCi7yYQKGDUj6CDixc"); + + nm_clear_g_free(&str); + + str = nm_utils_stable_id_generated_complete("${NETWORK_SSID}=9{s:foo\\012}"); + g_assert_cmpstr(str, ==, "wqLBg0FtOnCi7yYQKGDUj6CDixc"); + } } /*****************************************************************************/ diff --git a/src/core/tests/test-l3cfg.c b/src/core/tests/test-l3cfg.c index 962b2eec..6b82fe43 100644 --- a/src/core/tests/test-l3cfg.c +++ b/src/core/tests/test-l3cfg.c @@ -760,7 +760,7 @@ test_l3_ipv4ll(gconstpointer test_data) if (next_timeout_msec <= 0) break; - next_timeout_msec = NM_MIN(next_timeout_msec, nmtst_get_rand_uint32() % 1000u); + next_timeout_msec = NM_MIN(next_timeout_msec, (gint64) (nmtst_get_rand_uint32() % 1000u)); nmtst_main_context_iterate_until(NULL, next_timeout_msec, FALSE); _LOGT("poll 1 intermezzo"); diff --git a/src/core/vpn/nm-vpn-connection.c b/src/core/vpn/nm-vpn-connection.c index d7102a12..3dba9ff6 100644 --- a/src/core/vpn/nm-vpn-connection.c +++ b/src/core/vpn/nm-vpn-connection.c @@ -1143,7 +1143,8 @@ static void device_state_changed(NMActiveConnection *active, NMDevice *device, NMDeviceState new_state, - NMDeviceState old_state) + NMDeviceState old_state, + NMDeviceStateReason reason) { if (_service_and_connection_can_persist(NM_VPN_CONNECTION(active))) { if (new_state <= NM_DEVICE_STATE_DISCONNECTED || new_state == NM_DEVICE_STATE_FAILED) { |