diff options
Diffstat (limited to 'src/core/devices')
30 files changed, 1333 insertions, 439 deletions
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", |