diff options
| author | Michael Biebl <biebl@debian.org> | 2018-10-20 01:30:31 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2018-10-20 01:30:31 +0200 |
| commit | 6518e361171f64bcaaa4bf868139362ed95cc2e0 (patch) | |
| tree | d2d5b53faf80646a40ec2c0c7f2a42b3959612f5 /src/devices | |
| parent | e126f3e804c35480c4f075777430419d6ece23da (diff) | |
New upstream version 1.14.2 upstream/1.14.2
Diffstat (limited to 'src/devices')
58 files changed, 3931 insertions, 1911 deletions
diff --git a/src/devices/adsl/meson.build b/src/devices/adsl/meson.build index ee804d23..7ac0e123 100644 --- a/src/devices/adsl/meson.build +++ b/src/devices/adsl/meson.build @@ -20,10 +20,10 @@ libnm_device_plugin_adsl = shared_module( core_plugins += libnm_device_plugin_adsl -run_target( +test( 'check-local-devices-adsl', - command: [check_exports, libnm_device_plugin_adsl.full_path(), linker_script_devices], - depends: libnm_device_plugin_adsl + check_exports, + args: [libnm_device_plugin_adsl.full_path(), linker_script_devices], ) # FIXME: check_so_symbols replacement diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index 1450a836..c9984f51 100644 --- a/src/devices/adsl/nm-device-adsl.c +++ b/src/devices/adsl/nm-device-adsl.c @@ -87,25 +87,23 @@ get_generic_capabilities (NMDevice *dev) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMSettingAdsl *s_adsl; const char *protocol; - if (!NM_DEVICE_CLASS (nm_device_adsl_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - if (!nm_connection_is_type (connection, NM_SETTING_ADSL_SETTING_NAME)) + if (!NM_DEVICE_CLASS (nm_device_adsl_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_adsl = nm_connection_get_setting_adsl (connection); - if (!s_adsl) - return FALSE; - /* FIXME: we don't yet support IPoATM */ protocol = nm_setting_adsl_get_protocol (s_adsl); - if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_IPOATM) == 0) + if (nm_streq0 (protocol, NM_SETTING_ADSL_PROTOCOL_IPOATM)) { + /* FIXME: we don't yet support IPoATM */ + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "IPoATM protocol is not yet supported"); return FALSE; + } return TRUE; } @@ -669,7 +667,7 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructed = constructed; object_class->dispose = dispose; @@ -678,14 +676,16 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_adsl); - parent_class->get_generic_capabilities = get_generic_capabilities; + device_class->connection_type_check_compatible = NM_SETTING_ADSL_SETTING_NAME; + + device_class->get_generic_capabilities = get_generic_capabilities; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->complete_connection = complete_connection; + device_class->check_connection_compatible = check_connection_compatible; + device_class->complete_connection = complete_connection; - parent_class->act_stage2_config = act_stage2_config; - parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - parent_class->deactivate = deactivate; + device_class->act_stage2_config = act_stage2_config; + device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->deactivate = deactivate; obj_properties[PROP_ATM_INDEX] = g_param_spec_int (NM_DEVICE_ADSL_ATM_INDEX, "", "", diff --git a/src/devices/bluetooth/meson.build b/src/devices/bluetooth/meson.build index 30284f9e..019f04f6 100644 --- a/src/devices/bluetooth/meson.build +++ b/src/devices/bluetooth/meson.build @@ -31,10 +31,10 @@ libnm_device_plugin_bluetooth = shared_module( core_plugins += libnm_device_plugin_bluetooth -run_target( +test( 'check-local-devices-bluetooth', - command: [check_exports, libnm_device_plugin_bluetooth.full_path(), linker_script_devices], - depends: libnm_device_plugin_bluetooth + check_exports, + args: [libnm_device_plugin_bluetooth.full_path(), linker_script_devices], ) # FIXME: check_so_symbols replacement diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c index d8e40d6f..b722f692 100644 --- a/src/devices/bluetooth/nm-bluez-device.c +++ b/src/devices/bluetooth/nm-bluez-device.c @@ -94,7 +94,7 @@ typedef struct { NMSettings *settings; GSList *connections; - NMConnection *pan_connection; + NMSettingsConnection *pan_connection; gboolean pan_connection_no_autocreate; } NMBluezDevicePrivate; @@ -114,8 +114,9 @@ G_DEFINE_TYPE (NMBluezDevice, nm_bluez_device, G_TYPE_OBJECT) /*****************************************************************************/ static void cp_connection_added (NMSettings *settings, - NMConnection *connection, NMBluezDevice *self); -static gboolean connection_compatible (NMBluezDevice *self, NMConnection *connection); + NMSettingsConnection *sett_conn, + NMBluezDevice *self); +static gboolean connection_compatible (NMBluezDevice *self, NMSettingsConnection *sett_conn); /*****************************************************************************/ @@ -181,10 +182,10 @@ nm_bluez_device_get_connected (NMBluezDevice *self) static void pan_connection_check_create (NMBluezDevice *self) { - NMConnection *connection; - NMConnection *added; + gs_unref_object NMConnection *connection = NULL; + NMSettingsConnection *added; NMSetting *setting; - char *id; + gs_free char *id = NULL; char uuid[37]; GError *error = NULL; NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); @@ -226,35 +227,25 @@ pan_connection_check_create (NMBluezDevice *self) NULL); nm_connection_add_setting (connection, setting); - /* Setting: IPv4 */ - setting = nm_setting_ip4_config_new (); - g_object_set (G_OBJECT (setting), - NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE, - NULL); - nm_connection_add_setting (connection, setting); - - /* Setting: IPv6 */ - setting = nm_setting_ip6_config_new (); - g_object_set (G_OBJECT (setting), - NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE, - NULL); - nm_connection_add_setting (connection, setting); + if (!nm_connection_normalize (connection, NULL, NULL, &error)) { + nm_log_err (LOGD_BT, "bluez[%s] couldn't generate a connection for NAP device: %s", + priv->path, error->message); + g_error_free (error); + g_return_if_reached (); + } /* Adding a new connection raises a signal which eventually calls check_emit_usable (again) * which then already finds the suitable connection in priv->connections. This is confusing, * so block the signal. check_emit_usable will succeed after this function call returns. */ g_signal_handlers_block_by_func (priv->settings, cp_connection_added, self); - added = NM_CONNECTION (nm_settings_add_connection (priv->settings, connection, FALSE, &error)); + added = nm_settings_add_connection (priv->settings, connection, FALSE, &error); g_signal_handlers_unblock_by_func (priv->settings, cp_connection_added, self); if (added) { - g_assert (!g_slist_find (priv->connections, added)); - g_assert (connection_compatible (self, added)); - g_assert (nm_connection_compare (added, connection, NM_SETTING_COMPARE_FLAG_EXACT)); + nm_assert (!g_slist_find (priv->connections, added)); + nm_assert (connection_compatible (self, added)); - nm_settings_connection_set_flags (NM_SETTINGS_CONNECTION (added), NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, TRUE); + nm_settings_connection_set_flags (added, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, TRUE); priv->connections = g_slist_prepend (priv->connections, g_object_ref (added)); priv->pan_connection = added; @@ -263,11 +254,7 @@ pan_connection_check_create (NMBluezDevice *self) nm_log_warn (LOGD_BT, "bluez[%s] couldn't add new Bluetooth connection for NAP device: '%s' (%s): %s", priv->path, id, uuid, error->message); g_clear_error (&error); - } - g_object_unref (connection); - - g_free (id); } static gboolean @@ -321,9 +308,10 @@ check_emit_usable_schedule (NMBluezDevice *self) /*****************************************************************************/ static gboolean -connection_compatible (NMBluezDevice *self, NMConnection *connection) +connection_compatible (NMBluezDevice *self, NMSettingsConnection *sett_conn) { NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); + NMConnection *connection = nm_settings_connection_get_connection (sett_conn); NMSettingBluetooth *s_bt; const char *bt_type; const char *bdaddr; @@ -361,22 +349,24 @@ connection_compatible (NMBluezDevice *self, NMConnection *connection) } static gboolean -_internal_track_connection (NMBluezDevice *self, NMConnection *connection, gboolean tracked) +_internal_track_connection (NMBluezDevice *self, + NMSettingsConnection *sett_conn, + gboolean tracked) { NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); gboolean was_tracked; - was_tracked = !!g_slist_find (priv->connections, connection); + was_tracked = !!g_slist_find (priv->connections, sett_conn); if (was_tracked == !!tracked) return FALSE; if (tracked) - priv->connections = g_slist_prepend (priv->connections, g_object_ref (connection)); + priv->connections = g_slist_prepend (priv->connections, g_object_ref (sett_conn)); else { - priv->connections = g_slist_remove (priv->connections, connection); - if (priv->pan_connection == connection) + priv->connections = g_slist_remove (priv->connections, sett_conn); + if (priv->pan_connection == sett_conn) priv->pan_connection = NULL; - g_object_unref (connection); + g_object_unref (sett_conn); } return TRUE; @@ -384,32 +374,32 @@ _internal_track_connection (NMBluezDevice *self, NMConnection *connection, gbool static void cp_connection_added (NMSettings *settings, - NMConnection *connection, + NMSettingsConnection *sett_conn, NMBluezDevice *self) { - if (connection_compatible (self, connection)) { - if (_internal_track_connection (self, connection, TRUE)) + if (connection_compatible (self, sett_conn)) { + if (_internal_track_connection (self, sett_conn, TRUE)) check_emit_usable (self); } } static void cp_connection_removed (NMSettings *settings, - NMConnection *connection, + NMSettingsConnection *sett_conn, NMBluezDevice *self) { - if (_internal_track_connection (self, connection, FALSE)) + if (_internal_track_connection (self, sett_conn, FALSE)) check_emit_usable (self); } static void cp_connection_updated (NMSettings *settings, - NMConnection *connection, + NMSettingsConnection *sett_conn, gboolean by_user, NMBluezDevice *self) { - if (_internal_track_connection (self, connection, - connection_compatible (self, connection))) + if (_internal_track_connection (self, sett_conn, + connection_compatible (self, sett_conn))) check_emit_usable_schedule (self); } @@ -423,10 +413,8 @@ load_connections (NMBluezDevice *self) connections = nm_settings_get_connections (priv->settings, NULL); for (i = 0; connections[i]; i++) { - NMConnection *connection = (NMConnection *) connections[i]; - - if (connection_compatible (self, connection)) - changed |= _internal_track_connection (self, connection, TRUE); + if (connection_compatible (self, connections[i])) + changed |= _internal_track_connection (self, connections[i], TRUE); } if (changed) check_emit_usable (self); @@ -1178,14 +1166,14 @@ dispose (GObject *object) { NMBluezDevice *self = NM_BLUEZ_DEVICE (object); NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); - NMConnection *to_delete = NULL; + NMSettingsConnection *to_delete = NULL; nm_clear_g_source (&priv->check_emit_usable_id); if (priv->pan_connection) { /* Check whether we want to remove the created connection. If so, we take a reference * and delete it at the end of dispose(). */ - if (NM_FLAGS_HAS (nm_settings_connection_get_flags (NM_SETTINGS_CONNECTION (priv->pan_connection)), + if (NM_FLAGS_HAS (nm_settings_connection_get_flags (priv->pan_connection), NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) to_delete = g_object_ref (priv->pan_connection); @@ -1219,8 +1207,8 @@ dispose (GObject *object) if (to_delete) { nm_log_dbg (LOGD_BT, "bluez[%s] removing Bluetooth connection for NAP device: '%s' (%s)", priv->path, - nm_connection_get_id (to_delete), nm_connection_get_uuid (to_delete)); - nm_settings_connection_delete (NM_SETTINGS_CONNECTION (to_delete), NULL); + nm_settings_connection_get_id (to_delete), nm_settings_connection_get_uuid (to_delete)); + nm_settings_connection_delete (to_delete, NULL); g_object_unref (to_delete); } diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c index c74ecd81..711f2e57 100644 --- a/src/devices/bluetooth/nm-bluez-manager.c +++ b/src/devices/bluetooth/nm-bluez-manager.c @@ -244,8 +244,8 @@ setup_bluez5 (NMBluezManager *self) static void watch_name_on_appeared (GDBusConnection *connection, - const gchar *name, - const gchar *name_owner, + const char *name, + const char *name_owner, gpointer user_data) { check_bluez_and_try_setup (NM_BLUEZ_MANAGER (user_data)); diff --git a/src/devices/bluetooth/nm-bluez5-manager.c b/src/devices/bluetooth/nm-bluez5-manager.c index 5d3bd23a..e984212b 100644 --- a/src/devices/bluetooth/nm-bluez5-manager.c +++ b/src/devices/bluetooth/nm-bluez5-manager.c @@ -224,7 +224,7 @@ network_server_unregister_bridge (const NMBtVTableNetworkServer *vtable, } static void -network_server_removed (GDBusProxy *proxy, const gchar *path, NMBluez5Manager *self) +network_server_removed (GDBusProxy *proxy, const char *path, NMBluez5Manager *self) { NetworkServer *network_server; @@ -241,7 +241,7 @@ network_server_removed (GDBusProxy *proxy, const gchar *path, NMBluez5Manager *s } static void -network_server_added (GDBusProxy *proxy, const gchar *path, const char *addr, NMBluez5Manager *self) +network_server_added (GDBusProxy *proxy, const char *path, const char *addr, NMBluez5Manager *self) { NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); NetworkServer *network_server; @@ -342,7 +342,7 @@ device_initialized (NMBluezDevice *device, gboolean success, NMBluez5Manager *se } static void -device_added (GDBusProxy *proxy, const gchar *path, NMBluez5Manager *self) +device_added (GDBusProxy *proxy, const char *path, NMBluez5Manager *self) { NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); NMBluezDevice *device; @@ -356,7 +356,7 @@ device_added (GDBusProxy *proxy, const gchar *path, NMBluez5Manager *self) } static void -device_removed (GDBusProxy *proxy, const gchar *path, NMBluez5Manager *self) +device_removed (GDBusProxy *proxy, const char *path, NMBluez5Manager *self) { NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); NMBluezDevice *device; diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index 92ad0b31..1f650d33 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -36,6 +36,7 @@ #include "nm-setting-serial.h" #include "nm-setting-ppp.h" #include "NetworkManagerUtils.h" +#include "settings/nm-settings-connection.h" #include "nm-utils.h" #include "nm-bt-error.h" #include "platform/nm-platform.h" @@ -137,7 +138,7 @@ get_generic_capabilities (NMDevice *device) static gboolean can_auto_connect (NMDevice *device, - NMConnection *connection, + NMSettingsConnection *sett_conn, char **specific_object) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); @@ -145,11 +146,11 @@ can_auto_connect (NMDevice *device, nm_assert (!specific_object || !*specific_object); - if (!NM_DEVICE_CLASS (nm_device_bt_parent_class)->can_auto_connect (device, connection, NULL)) + if (!NM_DEVICE_CLASS (nm_device_bt_parent_class)->can_auto_connect (device, sett_conn, NULL)) return FALSE; /* Can't auto-activate a DUN connection without ModemManager */ - bt_type = get_connection_bt_type (connection); + bt_type = get_connection_bt_type (nm_settings_connection_get_connection (sett_conn)); if (bt_type == NM_BT_CAPABILITY_DUN && priv->mm_running == FALSE) return FALSE; @@ -157,36 +158,36 @@ can_auto_connect (NMDevice *device, } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); - NMSettingConnection *s_con; NMSettingBluetooth *s_bt; const char *bdaddr; guint32 bt_type; - if (!NM_DEVICE_CLASS (nm_device_bt_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_bt_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_BLUETOOTH_SETTING_NAME)) + bt_type = get_connection_bt_type (connection); + if (!NM_FLAGS_ALL (priv->capabilities, bt_type)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not support bluetooth type of profile"); return FALSE; + } s_bt = nm_connection_get_setting_bluetooth (connection); - if (!s_bt) - return FALSE; - - bt_type = get_connection_bt_type (connection); - if (!(bt_type & priv->capabilities)) - return FALSE; bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt); - if (!bdaddr) + if (!bdaddr) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "profile lacks bdaddr setting"); return FALSE; - if (!nm_utils_hwaddr_matches (priv->bdaddr, -1, bdaddr, -1)) + } + if (!nm_utils_hwaddr_matches (priv->bdaddr, -1, bdaddr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "devices bdaddr setting mismatches"); return FALSE; + } return TRUE; } @@ -195,18 +196,25 @@ static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) device); guint32 bt_type; bt_type = get_connection_bt_type (connection); - if (!(bt_type & priv->capabilities)) + if (!(bt_type & priv->capabilities)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not support bluetooth type"); return FALSE; + } /* DUN connections aren't available without ModemManager */ - if (bt_type == NM_BT_CAPABILITY_DUN && priv->mm_running == FALSE) + if (bt_type == NM_BT_CAPABILITY_DUN && priv->mm_running == FALSE) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "ModemManager missing for DUN profile"); return FALSE; + } return TRUE; } @@ -1177,6 +1185,8 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_bluetooth); + device_class->connection_type_check_compatible = NM_SETTING_BLUETOOTH_SETTING_NAME; + device_class->get_generic_capabilities = get_generic_capabilities; device_class->can_auto_connect = can_auto_connect; device_class->deactivate = deactivate; diff --git a/src/devices/nm-device-6lowpan.c b/src/devices/nm-device-6lowpan.c new file mode 100644 index 00000000..b6b9157c --- /dev/null +++ b/src/devices/nm-device-6lowpan.c @@ -0,0 +1,345 @@ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2018 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-device-6lowpan.h" + +#include "nm-device-private.h" +#include "settings/nm-settings.h" +#include "platform/nm-platform.h" +#include "nm-device-factory.h" +#include "nm-setting-6lowpan.h" +#include "nm-utils.h" + +#include "nm-device-logging.h" +_LOG_DECLARE_SELF(NMDevice6Lowpan); + +/*****************************************************************************/ + +typedef struct { + gulong parent_state_id; +} NMDevice6LowpanPrivate; + +struct _NMDevice6Lowpan { + NMDevice parent; + NMDevice6LowpanPrivate _priv; +}; + +struct _NMDevice6LowpanClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDevice6Lowpan, nm_device_6lowpan, NM_TYPE_DEVICE) + +#define NM_DEVICE_6LOWPAN_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDevice6Lowpan, NM_IS_DEVICE_6LOWPAN) + +/*****************************************************************************/ + +static void +parent_state_changed (NMDevice *parent, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason, + gpointer user_data) +{ + NMDevice6Lowpan *self = NM_DEVICE_6LOWPAN (user_data); + + nm_device_set_unmanaged_by_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent, FALSE), reason); +} + +static void +parent_changed_notify (NMDevice *device, + int old_ifindex, + NMDevice *old_parent, + int new_ifindex, + NMDevice *new_parent) +{ + NMDevice6Lowpan *self = NM_DEVICE_6LOWPAN (device); + NMDevice6LowpanPrivate *priv = NM_DEVICE_6LOWPAN_GET_PRIVATE (self); + + NM_DEVICE_CLASS (nm_device_6lowpan_parent_class)->parent_changed_notify (device, old_ifindex, old_parent, new_ifindex, new_parent); + + /* note that @self doesn't have to clear @parent_state_id on dispose, + * because NMDevice's dispose() will unset the parent, which in turn calls + * parent_changed_notify(). */ + nm_clear_g_signal_handler (old_parent, &priv->parent_state_id); + + if (new_parent) { + priv->parent_state_id = g_signal_connect (new_parent, + NM_DEVICE_STATE_CHANGED, + G_CALLBACK (parent_state_changed), + device); + + /* Set parent-dependent unmanaged flag */ + nm_device_set_unmanaged_by_flags (device, + NM_UNMANAGED_PARENT, + !nm_device_get_managed (new_parent, FALSE), + NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); + } + + if (new_ifindex > 0) { + /* Recheck availability now that the parent has changed */ + nm_device_queue_recheck_available (device, + NM_DEVICE_STATE_REASON_PARENT_CHANGED, + NM_DEVICE_STATE_REASON_PARENT_CHANGED); + } +} + +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); + NMPlatformError plerr; + NMSetting6Lowpan *s_6lowpan; + int parent_ifindex; + + s_6lowpan = NM_SETTING_6LOWPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_6LOWPAN)); + g_return_val_if_fail (s_6lowpan, FALSE); + + parent_ifindex = parent ? nm_device_get_ifindex (parent) : 0; + + if (parent_ifindex <= 0) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_MISSING_DEPENDENCIES, + "6LoWPAN devices can not be created without a parent interface"); + g_return_val_if_fail (!parent, FALSE); + return FALSE; + } + + plerr = nm_platform_link_6lowpan_add (nm_device_get_platform (device), iface, parent_ifindex, out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create 6lowpan interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string_a (plerr)); + return FALSE; + } + + nm_device_parent_set_ifindex (device, parent_ifindex); + + return TRUE; +} + +static NMDeviceCapabilities +get_generic_capabilities (NMDevice *dev) +{ + return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; +} + +static void +link_changed (NMDevice *device, + const NMPlatformLink *pllink) +{ + NMDevice6Lowpan *self = NM_DEVICE_6LOWPAN (device); + int parent = 0; + int ifindex; + + NM_DEVICE_CLASS (nm_device_6lowpan_parent_class)->link_changed (device, pllink); + + ifindex = nm_device_get_ifindex (device); + if (!nm_platform_link_6lowpan_get_properties (nm_device_get_platform (device), ifindex, &parent)) { + _LOGW (LOGD_DEVICE, "could not get 6lowpan properties"); + return; + } + + nm_device_parent_set_ifindex (device, parent); +} + +static gboolean +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) +{ + if (!nm_device_parent_get_device (device)) + return FALSE; + return NM_DEVICE_CLASS (nm_device_6lowpan_parent_class)->is_available (device, flags); +} + +static gboolean +complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + NMConnection *const*existing_connections, + GError **error) +{ + NMSetting6Lowpan *s_6lowpan; + + nm_utils_complete_generic (nm_device_get_platform (device), + connection, + NM_SETTING_6LOWPAN_SETTING_NAME, + existing_connections, + NULL, + _("6LOWPAN connection"), + NULL, + TRUE); + + s_6lowpan = NM_SETTING_6LOWPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_6LOWPAN)); + if (!s_6lowpan) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + "A '6lowpan' setting is required."); + return FALSE; + } + + /* If there's no 6LoWPAN interface, no parent, and no hardware address in the + * settings, then there's not enough information to complete the setting. + */ + if ( !nm_setting_6lowpan_get_parent (s_6lowpan) + && !nm_device_match_parent_hwaddr (device, connection, TRUE)) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + "The '6lowpan' setting had no interface name, parent, or hardware address."); + return FALSE; + } + + return TRUE; +} + +static void +update_connection (NMDevice *device, NMConnection *connection) +{ + NMSetting6Lowpan *s_6lowpan = NM_SETTING_6LOWPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_6LOWPAN)); + + if (!s_6lowpan) { + s_6lowpan = (NMSetting6Lowpan *) nm_setting_6lowpan_new (); + nm_connection_add_setting (connection, (NMSetting *) s_6lowpan); + } + + g_object_set (s_6lowpan, + NM_SETTING_6LOWPAN_PARENT, + nm_device_parent_find_for_connection (device, + nm_setting_6lowpan_get_parent (s_6lowpan)), + NULL); +} + +static NMActStageReturn +act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *out_failure_reason) +{ + NMActStageReturn ret; + + ret = NM_DEVICE_CLASS (nm_device_6lowpan_parent_class)->act_stage1_prepare (dev, out_failure_reason); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + + if (!nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE)) + return NM_ACT_STAGE_RETURN_FAILURE; + return NM_ACT_STAGE_RETURN_SUCCESS; +} + +/*****************************************************************************/ + +static void +nm_device_6lowpan_init (NMDevice6Lowpan *self) +{ +} + +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 ("Parent", "o", NM_DEVICE_PARENT), + ), + ), +}; + +static void +nm_device_6lowpan_class_init (NMDevice6LowpanClass *klass) +{ + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_6lowpan); + + device_class->connection_type_supported = NM_SETTING_6LOWPAN_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_6LOWPAN_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_6LOWPAN); + + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->complete_connection = complete_connection; + device_class->create_and_realize = create_and_realize; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; + device_class->link_changed = link_changed; + device_class->is_available = is_available; + device_class->parent_changed_notify = parent_changed_notify; + device_class->update_connection = update_connection; +} + +/*****************************************************************************/ + +#define NM_TYPE_6LOWPAN_DEVICE_FACTORY (nm_6lowpan_device_factory_get_type ()) +#define NM_6LOWPAN_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_6LOWPAN_DEVICE_FACTORY, NM6LowpanDeviceFactory)) + +static NMDevice * +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_6LOWPAN, + NM_DEVICE_IFACE, iface, + NM_DEVICE_TYPE_DESC, "6LoWPAN", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_6LOWPAN, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_6LOWPAN, + NULL); +} + +static const char * +get_connection_parent (NMDeviceFactory *factory, NMConnection *connection) +{ + NMSetting6Lowpan *s_6lowpan; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_6LOWPAN_SETTING_NAME), NULL); + + s_6lowpan = NM_SETTING_6LOWPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_6LOWPAN)); + g_assert (s_6lowpan); + + return nm_setting_6lowpan_get_parent (s_6lowpan); +} + +static char * +get_connection_iface (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + NMSetting6Lowpan *s_6lowpan; + const char *ifname; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_6LOWPAN_SETTING_NAME), NULL); + + s_6lowpan = NM_SETTING_6LOWPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_6LOWPAN)); + g_assert (s_6lowpan); + + if (!parent_iface) + return NULL; + + ifname = nm_connection_get_interface_name (connection); + return g_strdup (ifname); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL (6LOWPAN, 6Lowpan, 6lowpan, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_6LOWPAN) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_6LOWPAN_SETTING_NAME), + factory_class->create_device = create_device; + factory_class->get_connection_parent = get_connection_parent; + factory_class->get_connection_iface = get_connection_iface; +); diff --git a/src/devices/nm-device-6lowpan.h b/src/devices/nm-device-6lowpan.h new file mode 100644 index 00000000..86edf4af --- /dev/null +++ b/src/devices/nm-device-6lowpan.h @@ -0,0 +1,37 @@ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2018 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DEVICE_6LOWPAN_H__ +#define __NETWORKMANAGER_DEVICE_6LOWPAN_H__ + +#include "nm-device.h" + +#define NM_TYPE_DEVICE_6LOWPAN (nm_device_6lowpan_get_type ()) +#define NM_DEVICE_6LOWPAN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_6LOWPAN, NMDevice6Lowpan)) +#define NM_DEVICE_6LOWPAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_6LOWPAN, NMDevice6LowpanClass)) +#define NM_IS_DEVICE_6LOWPAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_6LOWPAN)) +#define NM_IS_DEVICE_6LOWPAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_6LOWPAN)) +#define NM_DEVICE_6LOWPAN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_6LOWPAN, NMDevice6LowpanClass)) + +typedef struct _NMDevice6Lowpan NMDevice6Lowpan; +typedef struct _NMDevice6LowpanClass NMDevice6LowpanClass; + +GType nm_device_6lowpan_get_type (void); + +#endif /* __NETWORKMANAGER_DEVICE_6LOWPAN_H__ */ diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index f59ec9ff..6e7e6ffc 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2011 - 2016 Red Hat, Inc. + * Copyright 2011 - 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -56,23 +56,6 @@ get_generic_capabilities (NMDevice *dev) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingBond *s_bond; - - if (!NM_DEVICE_CLASS (nm_device_bond_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_bond = nm_connection_get_setting_bond (connection); - if (!s_bond || !nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) - return FALSE; - - /* FIXME: match bond properties like mode, etc? */ - - return TRUE; -} - -static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, @@ -363,7 +346,6 @@ static NMActStageReturn act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *out_failure_reason) { NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; - gboolean no_firmware = FALSE; ret = NM_DEVICE_CLASS (nm_device_bond_parent_class)->act_stage1_prepare (dev, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) @@ -374,7 +356,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *out_failure_reason) ret = apply_bonding_config (dev); if (ret != NM_ACT_STAGE_RETURN_FAILURE) ret = nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE); - nm_device_bring_up (dev, TRUE, &no_firmware); + nm_device_bring_up (dev, TRUE, NULL); return ret; } @@ -386,7 +368,7 @@ enslave_slave (NMDevice *device, gboolean configure) { NMDeviceBond *self = NM_DEVICE_BOND (device); - gboolean success = TRUE, no_firmware = FALSE; + gboolean success = TRUE; const char *slave_iface = nm_device_get_ip_iface (slave); NMConnection *master_con; @@ -397,7 +379,7 @@ enslave_slave (NMDevice *device, success = nm_platform_link_enslave (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)); - nm_device_bring_up (slave, TRUE, &no_firmware); + nm_device_bring_up (slave, TRUE, NULL); if (!success) return FALSE; @@ -434,7 +416,7 @@ release_slave (NMDevice *device, gboolean configure) { NMDeviceBond *self = NM_DEVICE_BOND (device); - gboolean success, no_firmware = FALSE; + gboolean success; gs_free char *address = NULL; if (configure) { @@ -463,7 +445,7 @@ release_slave (NMDevice *device, * IFF_UP), so we must bring it back up here to ensure carrier changes and * other state is noticed by the now-released slave. */ - if (!nm_device_bring_up (slave, TRUE, &no_firmware)) + if (!nm_device_bring_up (slave, TRUE, NULL)) _LOGW (LOGD_BOND, "released bond slave could not be brought up."); } else { _LOGI (LOGD_BOND, "bond slave %s was released", @@ -632,27 +614,28 @@ static void nm_device_bond_class_init (NMDeviceBondClass *klass) { NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_BOND_SETTING_NAME, NM_LINK_TYPE_BOND) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_bond); - parent_class->is_master = TRUE; - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->complete_connection = complete_connection; - - parent_class->update_connection = update_connection; - parent_class->master_update_slave_connection = master_update_slave_connection; - - parent_class->create_and_realize = create_and_realize; - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; - parent_class->enslave_slave = enslave_slave; - parent_class->release_slave = release_slave; - parent_class->can_reapply_change = can_reapply_change; - parent_class->reapply_connection = reapply_connection; + device_class->connection_type_supported = NM_SETTING_BOND_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_BOND_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_BOND); + + device_class->is_master = TRUE; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->complete_connection = complete_connection; + + device_class->update_connection = update_connection; + device_class->master_update_slave_connection = master_update_slave_connection; + + device_class->create_and_realize = create_and_realize; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; + device_class->enslave_slave = enslave_slave; + device_class->release_slave = release_slave; + device_class->can_reapply_change = can_reapply_change; + device_class->reapply_connection = reapply_connection; } /*****************************************************************************/ diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index c81a0253..e79de95c 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -61,41 +61,63 @@ static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMSettingBluetooth *s_bt; - if (!NM_DEVICE_CLASS (nm_device_bridge_parent_class)->check_connection_available (device, connection, flags, specific_object)) + if (!NM_DEVICE_CLASS (nm_device_bridge_parent_class)->check_connection_available (device, connection, flags, specific_object, error)) return FALSE; s_bt = _nm_connection_get_setting_bluetooth_for_nap (connection); if (s_bt) { - return nm_bt_vtable_network_server - && nm_bt_vtable_network_server->is_available (nm_bt_vtable_network_server, - nm_setting_bluetooth_get_bdaddr (s_bt)); + const char *bdaddr; + + if (!nm_bt_vtable_network_server) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "bluetooth plugin not available to activate NAP profile"); + return FALSE; + } + + bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt); + if (!nm_bt_vtable_network_server->is_available (nm_bt_vtable_network_server, bdaddr)) { + if (bdaddr) + nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "not suitable NAP device \"%s\" available", bdaddr); + else + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "not suitable NAP device available"); + return FALSE; + } } return TRUE; } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMSettingBridge *s_bridge; const char *mac_address; - if (!NM_DEVICE_CLASS (nm_device_bridge_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_bridge_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; - s_bridge = nm_connection_get_setting_bridge (connection); - if (!s_bridge) - return FALSE; + if ( nm_connection_is_type (connection, NM_SETTING_BLUETOOTH_SETTING_NAME) + && _nm_connection_get_setting_bluetooth_for_nap (connection)) { + s_bridge = nm_connection_get_setting_bridge (connection); + if (!s_bridge) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "missing bridge setting for bluetooth NAP profile"); + return FALSE; + } - if (!nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)) { - if ( nm_connection_is_type (connection, NM_SETTING_BLUETOOTH_SETTING_NAME) - && _nm_connection_get_setting_bluetooth_for_nap (connection)) { - /* a bluetooth NAP connection is handled by the bridge */ - } else + /* a bluetooth NAP connection is handled by the bridge. + * + * Proceed... */ + } else { + s_bridge = _nm_connection_check_main_setting (connection, NM_SETTING_BRIDGE_SETTING_NAME, error); + if (!s_bridge) return FALSE; } @@ -104,8 +126,11 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) const char *hw_addr; hw_addr = nm_device_get_hw_address (device); - if (!hw_addr || !nm_utils_hwaddr_matches (hw_addr, -1, mac_address, -1)) + if (!hw_addr || !nm_utils_hwaddr_matches (hw_addr, -1, mac_address, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "mac address mismatches"); return FALSE; + } } return TRUE; @@ -505,28 +530,29 @@ static void nm_device_bridge_class_init (NMDeviceBridgeClass *klass) { NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_BRIDGE_SETTING_NAME, NM_LINK_TYPE_BRIDGE) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_bridge); - parent_class->is_master = TRUE; - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->check_connection_available = check_connection_available; - parent_class->complete_connection = complete_connection; - - parent_class->update_connection = update_connection; - parent_class->master_update_slave_connection = master_update_slave_connection; - - parent_class->create_and_realize = create_and_realize; - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage2_config = act_stage2_config; - parent_class->deactivate = deactivate; - parent_class->enslave_slave = enslave_slave; - parent_class->release_slave = release_slave; - parent_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; + device_class->connection_type_supported = NM_SETTING_BRIDGE_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_BRIDGE); + + device_class->is_master = TRUE; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->check_connection_compatible = check_connection_compatible; + device_class->check_connection_available = check_connection_available; + device_class->complete_connection = complete_connection; + + device_class->update_connection = update_connection; + device_class->master_update_slave_connection = master_update_slave_connection; + + device_class->create_and_realize = create_and_realize; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->deactivate = deactivate; + device_class->enslave_slave = enslave_slave; + device_class->release_slave = release_slave; + device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; } /*****************************************************************************/ diff --git a/src/devices/nm-device-dummy.c b/src/devices/nm-device-dummy.c index 9be4d29f..a9059383 100644 --- a/src/devices/nm-device-dummy.c +++ b/src/devices/nm-device-dummy.c @@ -117,21 +117,6 @@ create_and_realize (NMDevice *device, return TRUE; } -static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingDummy *s_dummy; - - if (!NM_DEVICE_CLASS (nm_device_dummy_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_dummy = nm_connection_get_setting_dummy (connection); - if (!s_dummy) - return FALSE; - - return TRUE; -} - static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { @@ -173,13 +158,13 @@ nm_device_dummy_class_init (NMDeviceDummyClass *klass) NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_DUMMY) - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_dummy); - device_class->connection_type = NM_SETTING_DUMMY_SETTING_NAME; + device_class->connection_type_supported = NM_SETTING_DUMMY_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_DUMMY_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_DUMMY); + device_class->complete_connection = complete_connection; - device_class->check_connection_compatible = check_connection_compatible; device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; device_class->update_connection = update_connection; diff --git a/src/devices/nm-device-ethernet-utils.c b/src/devices/nm-device-ethernet-utils.c index 298e6dff..b18eadfa 100644 --- a/src/devices/nm-device-ethernet-utils.c +++ b/src/devices/nm-device-ethernet-utils.c @@ -18,33 +18,24 @@ #include "nm-default.h" -#include <string.h> - -#include "nm-connection.h" - #include "nm-device-ethernet-utils.h" +#include "settings/nm-settings-connection.h" + char * -nm_device_ethernet_utils_get_default_wired_name (NMConnection *const *connections) +nm_device_ethernet_utils_get_default_wired_name (GHashTable *existing_ids) { char *temp; - guint j; int i; /* Find the next available unique connection name */ - for (i = 1; i <= 10000; i++) { + for (i = 1; i < G_MAXINT; i++) { temp = g_strdup_printf (_("Wired connection %d"), i); - for (j = 0; connections[j]; j++) { - if (nm_streq0 (nm_connection_get_id (connections[j]), temp)) { - g_free (temp); - goto next; - } - } - return temp; -next: - ; + if ( !existing_ids + || !g_hash_table_contains (existing_ids, temp)) + return temp; + g_free (temp); } - return NULL; } diff --git a/src/devices/nm-device-ethernet-utils.h b/src/devices/nm-device-ethernet-utils.h index 197d0a9e..7e5c8b31 100644 --- a/src/devices/nm-device-ethernet-utils.h +++ b/src/devices/nm-device-ethernet-utils.h @@ -19,6 +19,6 @@ #ifndef __NETWORKMANAGER_DEVICE_ETHERNET_UTILS_H__ #define __NETWORKMANAGER_DEVICE_ETHERNET_UTILS_H__ -char *nm_device_ethernet_utils_get_default_wired_name (NMConnection *const *connections); +char *nm_device_ethernet_utils_get_default_wired_name (GHashTable *existing_ids); #endif /* NETWORKMANAGER_DEVICE_ETHERNET_UTILS_H */ diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index a9a9f968..0fb8fea4 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -343,23 +343,21 @@ match_subchans (NMDeviceEthernet *self, NMSettingWired *s_wired, gboolean *try_m } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); NMSettingWired *s_wired; - if (!NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; - s_wired = nm_connection_get_setting_wired (connection); - if (nm_connection_is_type (connection, NM_SETTING_PPPOE_SETTING_NAME)) { - /* NOP */ - } else if (nm_connection_is_type (connection, NM_SETTING_WIRED_SETTING_NAME)) { + s_wired = nm_connection_get_setting_wired (connection); + } else { + s_wired = _nm_connection_check_main_setting (connection, NM_SETTING_WIRED_SETTING_NAME, error); if (!s_wired) return FALSE; - } else - return FALSE; + } if (s_wired) { const char *mac, *perm_hw_addr; @@ -367,28 +365,43 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) const char * const *mac_blacklist; int i; - if (!match_subchans (self, s_wired, &try_mac)) + if (!match_subchans (self, s_wired, &try_mac)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "s390 subchannels don't match"); return FALSE; + } perm_hw_addr = nm_device_get_permanent_hw_address (device); mac = nm_setting_wired_get_mac_address (s_wired); if (perm_hw_addr) { - if (try_mac && mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) + if ( try_mac + && mac + && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "permanent MAC address doesn't match"); return FALSE; + } /* Check for MAC address blacklist */ mac_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired); for (i = 0; mac_blacklist[i]; i++) { if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { - g_warn_if_reached (); + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "invalid MAC in blacklist"); return FALSE; } - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) + if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "permanent MAC address of device blacklisted"); return FALSE; + } } - } else if (mac) + } else if (mac) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has no permanent MAC address to match"); return FALSE; + } } return TRUE; @@ -1185,7 +1198,6 @@ wake_on_lan_enable (NMDevice *device) NMSettingWiredWakeOnLan wol; NMSettingWired *s_wired; const char *password = NULL; - gs_free char *value = NULL; s_wired = (NMSettingWired *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRED); if (s_wired) { @@ -1195,27 +1207,25 @@ wake_on_lan_enable (NMDevice *device) goto found; } - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "ethernet.wake-on-lan", - device); - - if (value) { - wol = _nm_utils_ascii_str_to_int64 (value, 10, - NM_SETTING_WIRED_WAKE_ON_LAN_NONE, - G_MAXINT32, - NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT); - - if ( NM_FLAGS_ANY (wol, NM_SETTING_WIRED_WAKE_ON_LAN_EXCLUSIVE_FLAGS) - && !nm_utils_is_power_of_two (wol)) { - nm_log_dbg (LOGD_ETHER, "invalid default value %u for wake-on-lan", (guint) wol); - wol = NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT; - } - if (wol != NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) - goto found; + wol = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "ethernet.wake-on-lan", + device, + NM_SETTING_WIRED_WAKE_ON_LAN_NONE, + G_MAXINT32, + NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT); + + if ( NM_FLAGS_ANY (wol, NM_SETTING_WIRED_WAKE_ON_LAN_EXCLUSIVE_FLAGS) + && !nm_utils_is_power_of_two (wol)) { + nm_log_dbg (LOGD_ETHER, "invalid default value %u for wake-on-lan", (guint) wol); + wol = NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT; } + if (wol != NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) + goto found; wol = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE; found: - return nm_platform_ethtool_set_wake_on_lan (nm_device_get_platform (device), nm_device_get_ifindex (device), wol, password); + return nm_platform_ethtool_set_wake_on_lan (nm_device_get_platform (device), + nm_device_get_ifindex (device), + wol, password); } /*****************************************************************************/ @@ -1430,12 +1440,14 @@ new_default_connection (NMDevice *self) NMConnection *connection; NMSettingsConnection *const*connections; NMSetting *setting; + gs_unref_hashtable GHashTable *existing_ids = NULL; struct udev_device *dev; const char *perm_hw_addr; const char *uprop = "0"; gs_free char *defname = NULL; gs_free char *uuid = NULL; gs_free char *machine_id = NULL; + guint i, n_connections; if (nm_config_get_no_auto_default_for_device (nm_config_get (), self)) return NULL; @@ -1448,8 +1460,13 @@ new_default_connection (NMDevice *self) setting = nm_setting_connection_new (); nm_connection_add_setting (connection, setting); - connections = nm_settings_get_connections (nm_device_get_settings (self), NULL); - defname = nm_device_ethernet_utils_get_default_wired_name ((NMConnection *const*) connections); + connections = nm_settings_get_connections (nm_device_get_settings (self), &n_connections); + if (n_connections > 0) { + existing_ids = g_hash_table_new (nm_str_hash, g_str_equal); + for (i = 0; i < n_connections; i++) + g_hash_table_add (existing_ids, (char *) nm_settings_connection_get_id (connections[i])); + } + defname = nm_device_ethernet_utils_get_default_wired_name (existing_ids); if (!defname) return NULL; @@ -1750,12 +1767,10 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); g_type_class_add_private (object_class, sizeof (NMDeviceEthernetPrivate)); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_WIRED_SETTING_NAME, NM_LINK_TYPE_ETHERNET) - object_class->dispose = dispose; object_class->finalize = finalize; object_class->get_property = get_property; @@ -1763,25 +1778,28 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_wired); - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->complete_connection = complete_connection; - parent_class->new_default_connection = new_default_connection; - - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage2_config = act_stage2_config; - parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - parent_class->get_configured_mtu = get_configured_mtu; - parent_class->deactivate = deactivate; - parent_class->get_s390_subchannels = get_s390_subchannels; - parent_class->update_connection = update_connection; - parent_class->carrier_changed_notify = carrier_changed_notify; - parent_class->link_changed = link_changed; - parent_class->is_available = is_available; - parent_class->can_reapply_change = can_reapply_change; - parent_class->reapply_connection = reapply_connection; - - parent_class->state_changed = device_state_changed; + device_class->connection_type_supported = NM_SETTING_WIRED_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_ETHERNET); + + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->check_connection_compatible = check_connection_compatible; + device_class->complete_connection = complete_connection; + device_class->new_default_connection = new_default_connection; + + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->get_configured_mtu = get_configured_mtu; + device_class->deactivate = deactivate; + device_class->get_s390_subchannels = get_s390_subchannels; + device_class->update_connection = update_connection; + device_class->carrier_changed_notify = carrier_changed_notify; + device_class->link_changed = link_changed; + device_class->is_available = is_available; + device_class->can_reapply_change = can_reapply_change; + device_class->reapply_connection = reapply_connection; + + device_class->state_changed = device_state_changed; obj_properties[PROP_SPEED] = g_param_spec_uint (NM_DEVICE_ETHERNET_SPEED, "", "", diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index bc717bb3..a11ead6e 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2014 Red Hat, Inc. + * Copyright (C) 2014 - 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -417,6 +417,7 @@ nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc call callback, user_data); \ } G_STMT_END + _ADD_INTERNAL (nm_6lowpan_device_factory_get_type); _ADD_INTERNAL (nm_bond_device_factory_get_type); _ADD_INTERNAL (nm_bridge_device_factory_get_type); _ADD_INTERNAL (nm_dummy_device_factory_get_type); @@ -430,6 +431,8 @@ nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc call _ADD_INTERNAL (nm_veth_device_factory_get_type); _ADD_INTERNAL (nm_vlan_device_factory_get_type); _ADD_INTERNAL (nm_vxlan_device_factory_get_type); + _ADD_INTERNAL (nm_wireguard_device_factory_get_type); + _ADD_INTERNAL (nm_wpan_device_factory_get_type); load_factories_from_dir (NMPLUGINDIR, callback, user_data); } diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c index 27eaf8d6..d00aa93b 100644 --- a/src/devices/nm-device-generic.c +++ b/src/devices/nm-device-generic.c @@ -86,19 +86,19 @@ realize_start_notify (NMDevice *device, const NMPlatformLink *plink) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMSettingConnection *s_con; - if (!NM_DEVICE_CLASS (nm_device_generic_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - if (!nm_connection_is_type (connection, NM_SETTING_GENERIC_SETTING_NAME)) + if (!NM_DEVICE_CLASS (nm_device_generic_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_con = nm_connection_get_setting_connection (connection); - if (!nm_setting_connection_get_interface_name (s_con)) + if (!nm_setting_connection_get_interface_name (s_con)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "generic profiles need an interface name"); return FALSE; + } return TRUE; } @@ -220,9 +220,7 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_GENERIC_SETTING_NAME, NM_LINK_TYPE_ANY) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructor = constructor; object_class->dispose = dispose; @@ -231,11 +229,15 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_generic); - parent_class->realize_start_notify = realize_start_notify; - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->get_type_description = get_type_description; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->update_connection = update_connection; + device_class->connection_type_supported = NM_SETTING_GENERIC_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_GENERIC_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_ANY); + + device_class->realize_start_notify = realize_start_notify; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->get_type_description = get_type_description; + device_class->check_connection_compatible = check_connection_compatible; + device_class->update_connection = update_connection; obj_properties[PROP_TYPE_DESCRIPTION] = g_param_spec_string (NM_DEVICE_GENERIC_TYPE_DESCRIPTION, "", "", diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index 99bcef00..41fac157 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2011 Red Hat, Inc. + * Copyright 2011 - 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -80,7 +80,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) NMSettingInfiniband *s_infiniband; char ifname_verified[IFNAMSIZ]; const char *transport_mode; - gboolean ok, no_firmware = FALSE; + gboolean ok; ret = NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->act_stage1_prepare (device, out_failure_reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) @@ -104,7 +104,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) /* With some drivers the interface must be down to set transport mode */ nm_device_take_down (device, TRUE); ok = nm_platform_sysctl_set (nm_device_get_platform (device), NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname_verified, "mode"), transport_mode); - nm_device_bring_up (device, TRUE, &no_firmware); + nm_device_bring_up (device, TRUE, NULL); if (!ok) { NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); @@ -123,30 +123,28 @@ get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMSettingInfiniband *s_infiniband; - if (!NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - if (!nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) - return FALSE; - - s_infiniband = nm_connection_get_setting_infiniband (connection); - if (!s_infiniband) + if (!NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; if (nm_device_is_real (device)) { const char *mac; const char *hw_addr; + s_infiniband = nm_connection_get_setting_infiniband (connection); + mac = nm_setting_infiniband_get_mac_address (s_infiniband); if (mac) { hw_addr = nm_device_get_permanent_hw_address (device); if ( !hw_addr - || !nm_utils_hwaddr_matches (mac, -1, hw_addr, -1)) + || !nm_utils_hwaddr_matches (mac, -1, hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "MAC address mismatches"); return FALSE; + } } } @@ -367,24 +365,26 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_INFINIBAND_SETTING_NAME, NM_LINK_TYPE_INFINIBAND) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->get_property = get_property; object_class->set_property = set_property; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_infiniband); - parent_class->create_and_realize = create_and_realize; - parent_class->unrealize = unrealize; - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->complete_connection = complete_connection; - parent_class->update_connection = update_connection; + device_class->connection_type_supported = NM_SETTING_INFINIBAND_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_INFINIBAND_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_INFINIBAND); + + device_class->create_and_realize = create_and_realize; + device_class->unrealize = unrealize; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->check_connection_compatible = check_connection_compatible; + device_class->complete_connection = complete_connection; + device_class->update_connection = update_connection; - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->get_configured_mtu = get_configured_mtu; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->get_configured_mtu = get_configured_mtu; obj_properties[PROP_IS_PARTITION] = g_param_spec_boolean (NM_DEVICE_INFINIBAND_IS_PARTITION, "", "", diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c index 2e266bb9..568403c6 100644 --- a/src/devices/nm-device-ip-tunnel.c +++ b/src/devices/nm-device-ip-tunnel.c @@ -179,10 +179,13 @@ clear: goto out; } - if (priv->mode == NM_IP_TUNNEL_MODE_GRE) { + if (NM_IN_SET (priv->mode, NM_IP_TUNNEL_MODE_GRE, NM_IP_TUNNEL_MODE_GRETAP)) { const NMPlatformLnkGre *lnk; - lnk = nm_platform_link_get_lnk_gre (nm_device_get_platform (device), ifindex, NULL); + if (priv->mode == NM_IP_TUNNEL_MODE_GRE) + lnk = nm_platform_link_get_lnk_gre (nm_device_get_platform (device), ifindex, NULL); + else + lnk = nm_platform_link_get_lnk_gretap (nm_device_get_platform (device), ifindex, NULL); if (!lnk) { _LOGW (LOGD_PLATFORM, "could not read %s properties", "gre"); goto clear; @@ -254,11 +257,21 @@ clear: ttl = lnk->ttl; tos = lnk->tos; pmtud = lnk->path_mtu_discovery; - } else if ( priv->mode == NM_IP_TUNNEL_MODE_IPIP6 - || priv->mode == NM_IP_TUNNEL_MODE_IP6IP6) { + } else if (NM_IN_SET (priv->mode, + NM_IP_TUNNEL_MODE_IPIP6, + NM_IP_TUNNEL_MODE_IP6IP6, + NM_IP_TUNNEL_MODE_IP6GRE, + NM_IP_TUNNEL_MODE_IP6GRETAP)) { const NMPlatformLnkIp6Tnl *lnk; + NMPlatform *plat = nm_device_get_platform (device); + + if (priv->mode == NM_IP_TUNNEL_MODE_IP6GRE) + lnk = nm_platform_link_get_lnk_ip6gre (plat, ifindex, NULL); + else if (priv->mode == NM_IP_TUNNEL_MODE_IP6GRETAP) + lnk = nm_platform_link_get_lnk_ip6gretap (plat, ifindex, NULL); + else + lnk = nm_platform_link_get_lnk_ip6tnl (plat, ifindex, NULL); - lnk = nm_platform_link_get_lnk_ip6tnl (nm_device_get_platform (device), ifindex, NULL); if (!lnk) { _LOGW (LOGD_PLATFORM, "could not read %s properties", "ip6tnl"); goto clear; @@ -272,6 +285,40 @@ clear: encap_limit = lnk->encap_limit; flow_label = lnk->flow_label; flags = ip6tnl_flags_plat_to_setting (lnk->flags); + + if (NM_IN_SET (priv->mode, + NM_IP_TUNNEL_MODE_IP6GRE, + NM_IP_TUNNEL_MODE_IP6GRETAP)) { + if (NM_FLAGS_HAS (lnk->input_flags, NM_GRE_KEY)) { + key = g_strdup_printf ("%u", lnk->input_key); + if (g_strcmp0 (priv->input_key, key)) { + g_free (priv->input_key); + priv->input_key = key; + _notify (self, PROP_INPUT_KEY); + } else + g_free (key); + } else { + if (priv->input_key) { + g_clear_pointer (&priv->input_key, g_free); + _notify (self, PROP_INPUT_KEY); + } + } + + if (NM_FLAGS_HAS (lnk->output_flags, NM_GRE_KEY)) { + key = g_strdup_printf ("%u", lnk->output_key); + if (g_strcmp0 (priv->output_key, key)) { + g_free (priv->output_key); + priv->output_key = key; + _notify (self, PROP_OUTPUT_KEY); + } else + g_free (key); + } else { + if (priv->output_key) { + g_clear_pointer (&priv->output_key, g_free); + _notify (self, PROP_OUTPUT_KEY); + } + } + } } else g_return_if_reached (); @@ -388,8 +435,6 @@ update_connection (NMDevice *device, NMConnection *connection) NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device); NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); NMSettingIPTunnel *s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); - NMDevice *parent = NULL; - const char *setting_parent, *new_parent; if (!s_ip_tunnel) { s_ip_tunnel = (NMSettingIPTunnel *) nm_setting_ip_tunnel_new (); @@ -399,25 +444,11 @@ update_connection (NMDevice *device, NMConnection *connection) if (nm_setting_ip_tunnel_get_mode (s_ip_tunnel) != priv->mode) g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_MODE, priv->mode, NULL); - parent = nm_device_parent_get_device (device); - - /* Update parent in the connection; default to parent's interface name */ - if (parent) { - new_parent = nm_device_get_iface (parent); - setting_parent = nm_setting_ip_tunnel_get_parent (s_ip_tunnel); - if (setting_parent && nm_utils_is_uuid (setting_parent)) { - NMConnection *parent_connection; - - /* Don't change a parent specified by UUID if it's still valid */ - parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (nm_device_get_settings (device), - setting_parent); - if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection)) - new_parent = NULL; - } - if (new_parent) - g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_PARENT, new_parent, NULL); - } else - g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_PARENT, NULL, NULL); + g_object_set (s_ip_tunnel, + NM_SETTING_IP_TUNNEL_PARENT, + nm_device_parent_find_for_connection (device, + nm_setting_ip_tunnel_get_parent (s_ip_tunnel)), + NULL); if (!address_equal_pp (priv->addr_family, nm_setting_ip_tunnel_get_local (s_ip_tunnel), @@ -456,7 +487,11 @@ update_connection (NMDevice *device, NMConnection *connection) NULL); } - if (priv->mode == NM_IP_TUNNEL_MODE_GRE || priv->mode == NM_IP_TUNNEL_MODE_IP6GRE) { + if (NM_IN_SET (priv->mode, + NM_IP_TUNNEL_MODE_GRE, + NM_IP_TUNNEL_MODE_GRETAP, + NM_IP_TUNNEL_MODE_IP6GRE, + NM_IP_TUNNEL_MODE_IP6GRETAP)) { if (g_strcmp0 (nm_setting_ip_tunnel_get_input_key (s_ip_tunnel), priv->input_key)) { g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_INPUT_KEY, @@ -473,54 +508,79 @@ update_connection (NMDevice *device, NMConnection *connection) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device); NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); NMSettingIPTunnel *s_ip_tunnel; const char *parent; - if (!NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); - if (!s_ip_tunnel) - return FALSE; - if (nm_setting_ip_tunnel_get_mode (s_ip_tunnel) != priv->mode) + if (nm_setting_ip_tunnel_get_mode (s_ip_tunnel) != priv->mode) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "incompatible IP tunnel mode"); return FALSE; + } if (nm_device_is_real (device)) { /* Check parent interface; could be an interface name or a UUID */ parent = nm_setting_ip_tunnel_get_parent (s_ip_tunnel); - if (parent && !nm_device_match_parent (device, parent)) + if (parent && !nm_device_match_parent (device, parent)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "IP tunnel parent mismatches"); return FALSE; + } if (!address_equal_pp (priv->addr_family, nm_setting_ip_tunnel_get_local (s_ip_tunnel), - priv->local)) + priv->local)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "local IP tunnel address mismatches"); return FALSE; + } if (!address_equal_pp (priv->addr_family, nm_setting_ip_tunnel_get_remote (s_ip_tunnel), - priv->remote)) + priv->remote)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "remote IP tunnel address mismatches"); return FALSE; + } - if (nm_setting_ip_tunnel_get_ttl (s_ip_tunnel) != priv->ttl) + if (nm_setting_ip_tunnel_get_ttl (s_ip_tunnel) != priv->ttl) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "TTL of IP tunnel mismatches"); return FALSE; + } - if (nm_setting_ip_tunnel_get_tos (s_ip_tunnel) != priv->tos) + if (nm_setting_ip_tunnel_get_tos (s_ip_tunnel) != priv->tos) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "TOS of IP tunnel mismatches"); return FALSE; + } if (priv->addr_family == AF_INET) { - if (nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel) != priv->path_mtu_discovery) + if (nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel) != priv->path_mtu_discovery) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "MTU discovery setting of IP tunnel mismatches"); return FALSE; + } } else { - if (nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel) != priv->encap_limit) + if (nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel) != priv->encap_limit) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "encapsulation limit of IP tunnel mismatches"); return FALSE; + } - if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label) + if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "flow-label of IP tunnel mismatches"); return FALSE; + } } } @@ -535,6 +595,8 @@ platform_link_to_tunnel_mode (const NMPlatformLink *link) switch (link->type) { case NM_LINK_TYPE_GRE: return NM_IP_TUNNEL_MODE_GRE; + case NM_LINK_TYPE_GRETAP: + return NM_IP_TUNNEL_MODE_GRETAP; case NM_LINK_TYPE_IP6TNL: lnk = nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, link->ifindex, NULL); if (lnk) { @@ -544,6 +606,10 @@ platform_link_to_tunnel_mode (const NMPlatformLink *link) return NM_IP_TUNNEL_MODE_IP6IP6; } return NM_IP_TUNNEL_MODE_UNKNOWN; + case NM_LINK_TYPE_IP6GRE: + return NM_IP_TUNNEL_MODE_IP6GRE; + case NM_LINK_TYPE_IP6GRETAP: + return NM_IP_TUNNEL_MODE_IP6GRETAP; case NM_LINK_TYPE_IPIP: return NM_IP_TUNNEL_MODE_IPIP; case NM_LINK_TYPE_SIT: @@ -559,15 +625,20 @@ tunnel_mode_to_link_type (NMIPTunnelMode tunnel_mode) switch (tunnel_mode) { case NM_IP_TUNNEL_MODE_GRE: return NM_LINK_TYPE_GRE; + case NM_IP_TUNNEL_MODE_GRETAP: + return NM_LINK_TYPE_GRETAP; case NM_IP_TUNNEL_MODE_IPIP6: case NM_IP_TUNNEL_MODE_IP6IP6: return NM_LINK_TYPE_IP6TNL; + case NM_IP_TUNNEL_MODE_IP6GRE: + return NM_LINK_TYPE_IP6GRE; + case NM_IP_TUNNEL_MODE_IP6GRETAP: + return NM_LINK_TYPE_IP6GRETAP; case NM_IP_TUNNEL_MODE_IPIP: return NM_LINK_TYPE_IPIP; case NM_IP_TUNNEL_MODE_SIT: return NM_LINK_TYPE_SIT; case NM_IP_TUNNEL_MODE_VTI: - case NM_IP_TUNNEL_MODE_IP6GRE: case NM_IP_TUNNEL_MODE_VTI6: case NM_IP_TUNNEL_MODE_ISATAP: return NM_LINK_TYPE_UNKNOWN; @@ -595,11 +666,16 @@ create_and_realize (NMDevice *device, NMPlatformLnkIp6Tnl lnk_ip6tnl = { }; const char *str; gint64 val; + NMIPTunnelMode mode; s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); g_assert (s_ip_tunnel); - switch (nm_setting_ip_tunnel_get_mode (s_ip_tunnel)) { + mode = nm_setting_ip_tunnel_get_mode (s_ip_tunnel); + switch (mode) { + case NM_IP_TUNNEL_MODE_GRETAP: + lnk_gre.is_tap = TRUE; + /* fall-through */ case NM_IP_TUNNEL_MODE_GRE: if (parent) lnk_gre.parent_ifindex = nm_device_get_ifindex (parent); @@ -700,6 +776,8 @@ create_and_realize (NMDevice *device, break; case NM_IP_TUNNEL_MODE_IPIP6: case NM_IP_TUNNEL_MODE_IP6IP6: + case NM_IP_TUNNEL_MODE_IP6GRE: + case NM_IP_TUNNEL_MODE_IP6GRETAP: if (parent) lnk_ip6tnl.parent_ifindex = nm_device_get_ifindex (parent); @@ -715,13 +793,44 @@ create_and_realize (NMDevice *device, lnk_ip6tnl.tclass = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); lnk_ip6tnl.encap_limit = nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel); lnk_ip6tnl.flow_label = nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel); - lnk_ip6tnl.proto = nm_setting_ip_tunnel_get_mode (s_ip_tunnel) == NM_IP_TUNNEL_MODE_IPIP6 ? IPPROTO_IPIP : IPPROTO_IPV6; lnk_ip6tnl.flags = ip6tnl_flags_setting_to_plat (nm_setting_ip_tunnel_get_flags (s_ip_tunnel)); - plerr = nm_platform_link_ip6tnl_add (nm_device_get_platform (device), iface, &lnk_ip6tnl, out_plink); + if (NM_IN_SET (mode, NM_IP_TUNNEL_MODE_IP6GRE, NM_IP_TUNNEL_MODE_IP6GRETAP)) { + val = _nm_utils_ascii_str_to_int64 (nm_setting_ip_tunnel_get_input_key (s_ip_tunnel), + 10, + 0, + G_MAXUINT32, + -1); + if (val != -1) { + lnk_ip6tnl.input_key = val; + lnk_ip6tnl.input_flags = NM_GRE_KEY; + } + + val = _nm_utils_ascii_str_to_int64 (nm_setting_ip_tunnel_get_output_key (s_ip_tunnel), + 10, + 0, + G_MAXUINT32, + -1); + if (val != -1) { + lnk_ip6tnl.output_key = val; + lnk_ip6tnl.output_flags = NM_GRE_KEY; + } + + lnk_ip6tnl.is_gre = TRUE; + lnk_ip6tnl.is_tap = (mode == NM_IP_TUNNEL_MODE_IP6GRETAP); + + plerr = nm_platform_link_ip6gre_add (nm_device_get_platform (device), + iface, &lnk_ip6tnl, out_plink); + } else { + lnk_ip6tnl.proto = nm_setting_ip_tunnel_get_mode (s_ip_tunnel) == NM_IP_TUNNEL_MODE_IPIP6 + ? IPPROTO_IPIP + : IPPROTO_IPV6; + plerr = nm_platform_link_ip6tnl_add (nm_device_get_platform (device), + iface, &lnk_ip6tnl, out_plink); + } if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create IPIP interface '%s' for '%s': %s", + "Failed to create IPv6 tunnel interface '%s' for '%s': %s", iface, nm_connection_get_id (connection), nm_platform_error_to_string_a (plerr)); @@ -852,6 +961,21 @@ set_property (GObject *object, guint prop_id, } } +static NMActStageReturn +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) +{ + NMActStageReturn ret; + + ret = NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->act_stage1_prepare (device, out_failure_reason); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + + if (!nm_device_hw_addr_set_cloned (device, nm_device_get_applied_connection (device), FALSE)) + return NM_ACT_STAGE_RETURN_FAILURE; + + return NM_ACT_STAGE_RETURN_SUCCESS; +} + /*****************************************************************************/ static void @@ -864,8 +988,11 @@ constructed (GObject *object) { NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE ((NMDeviceIPTunnel *) object); - if ( priv->mode == NM_IP_TUNNEL_MODE_IPIP6 - || priv->mode == NM_IP_TUNNEL_MODE_IP6IP6) + if (NM_IN_SET (priv->mode, + NM_IP_TUNNEL_MODE_IPIP6, + NM_IP_TUNNEL_MODE_IP6IP6, + NM_IP_TUNNEL_MODE_IP6GRE, + NM_IP_TUNNEL_MODE_IP6GRETAP)) priv->addr_family = AF_INET6; else priv->addr_family = AF_INET; @@ -925,6 +1052,17 @@ nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ip_tunnel); + device_class->connection_type_supported = NM_SETTING_IP_TUNNEL_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_IP_TUNNEL_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_GRE, + NM_LINK_TYPE_GRETAP, + NM_LINK_TYPE_IP6TNL, + NM_LINK_TYPE_IP6GRE, + NM_LINK_TYPE_IP6GRETAP, + NM_LINK_TYPE_IPIP, + NM_LINK_TYPE_SIT); + + device_class->act_stage1_prepare = act_stage1_prepare; device_class->link_changed = link_changed; device_class->can_reapply_change = can_reapply_change; device_class->complete_connection = complete_connection; @@ -935,13 +1073,6 @@ nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass) device_class->get_configured_mtu = get_configured_mtu; device_class->unrealize_notify = unrealize_notify; - NM_DEVICE_CLASS_DECLARE_TYPES (klass, - NM_SETTING_IP_TUNNEL_SETTING_NAME, - NM_LINK_TYPE_GRE, - NM_LINK_TYPE_IP6TNL, - NM_LINK_TYPE_IPIP, - NM_LINK_TYPE_SIT); - obj_properties[PROP_MODE] = g_param_spec_uint (NM_DEVICE_IP_TUNNEL_MODE, "", "", 0, G_MAXUINT, 0, @@ -1084,7 +1215,13 @@ get_connection_iface (NMDeviceFactory *factory, } NM_DEVICE_FACTORY_DEFINE_INTERNAL (IP_TUNNEL, IPTunnel, ip_tunnel, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_GRE, NM_LINK_TYPE_SIT, NM_LINK_TYPE_IPIP) + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_GRE, + NM_LINK_TYPE_GRETAP, + NM_LINK_TYPE_SIT, + NM_LINK_TYPE_IPIP, + NM_LINK_TYPE_IP6TNL, + NM_LINK_TYPE_IP6GRE, + NM_LINK_TYPE_IP6GRETAP) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_IP_TUNNEL_SETTING_NAME), factory_class->create_device = create_device; factory_class->get_connection_parent = get_connection_parent; diff --git a/src/devices/nm-device-macsec.c b/src/devices/nm-device-macsec.c index 166bfb57..8ea4c8b5 100644 --- a/src/devices/nm-device-macsec.c +++ b/src/devices/nm-device-macsec.c @@ -627,21 +627,6 @@ deactivate (NMDevice *device) supplicant_interface_release (self); } -static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingMacsec *s_macsec; - - if (!NM_DEVICE_CLASS (nm_device_macsec_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_macsec = nm_connection_get_setting_macsec (connection); - if (!s_macsec) - return FALSE; - - return TRUE; -} - /******************************************************************/ static NMDeviceCapabilities @@ -841,27 +826,26 @@ nm_device_macsec_class_init (NMDeviceMacsecClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_MACSEC) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->get_property = get_property; object_class->dispose = dispose; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_macsec); - parent_class->act_stage2_config = act_stage2_config; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->create_and_realize = create_and_realize; - parent_class->deactivate = deactivate; - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->link_changed = link_changed; - parent_class->is_available = is_available; - parent_class->parent_changed_notify = parent_changed_notify; - parent_class->state_changed = device_state_changed; - parent_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; - - parent_class->connection_type = NM_SETTING_MACSEC_SETTING_NAME; + device_class->connection_type_supported = NM_SETTING_MACSEC_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_MACSEC_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_MACSEC); + + device_class->act_stage2_config = act_stage2_config; + device_class->create_and_realize = create_and_realize; + device_class->deactivate = deactivate; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->link_changed = link_changed; + device_class->is_available = is_available; + device_class->parent_changed_notify = parent_changed_notify; + device_class->state_changed = device_state_changed; + device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; obj_properties[PROP_SCI] = g_param_spec_uint64 (NM_DEVICE_MACSEC_SCI, "", "", diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index dc4fb3e8..ff386c82 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -290,40 +290,58 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) /*****************************************************************************/ static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE ((NMDeviceMacvlan *) device); NMSettingMacvlan *s_macvlan; const char *parent = NULL; - if (!NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_macvlan = nm_connection_get_setting_macvlan (connection); - if (!s_macvlan) - return FALSE; - if (nm_setting_macvlan_get_tap (s_macvlan) != priv->props.tap) + if (nm_setting_macvlan_get_tap (s_macvlan) != priv->props.tap) { + if (priv->props.tap) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "macvtap device does not match macvlan profile"); + } else { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "macvlan device does not match macvtap profile"); + } return FALSE; + } /* Before the device is realized some properties will not be set */ if (nm_device_is_real (device)) { - if (setting_mode_to_platform (nm_setting_macvlan_get_mode (s_macvlan)) != priv->props.mode) + if (setting_mode_to_platform (nm_setting_macvlan_get_mode (s_macvlan)) != priv->props.mode) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "macvlan mode setting differs"); return FALSE; + } - if (nm_setting_macvlan_get_promiscuous (s_macvlan) == priv->props.no_promisc) + if (nm_setting_macvlan_get_promiscuous (s_macvlan) == priv->props.no_promisc) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "macvlan promiscuous setting differs"); return FALSE; + } /* Check parent interface; could be an interface name or a UUID */ parent = nm_setting_macvlan_get_parent (s_macvlan); if (parent) { - if (!nm_device_match_parent (device, parent)) + if (!nm_device_match_parent (device, parent)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "macvlan parent setting differs"); return FALSE; + } } else { /* Parent could be a MAC address in an NMSettingWired */ - if (!nm_device_match_hwaddr (device, connection, TRUE)) + if (!nm_device_match_parent_hwaddr (device, connection, TRUE)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "macvlan parent mac setting differs"); return FALSE; + } } } @@ -359,7 +377,7 @@ complete_connection (NMDevice *device, * settings, then there's not enough information to complete the setting. */ if ( !nm_setting_macvlan_get_parent (s_macvlan) - && !nm_device_match_hwaddr (device, connection, TRUE)) { + && !nm_device_match_parent_hwaddr (device, connection, TRUE)) { g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, "The 'macvlan' setting had no interface name, parent, or hardware address."); return FALSE; @@ -373,8 +391,6 @@ update_connection (NMDevice *device, NMConnection *connection) { NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE ((NMDeviceMacvlan *) device); NMSettingMacvlan *s_macvlan = nm_connection_get_setting_macvlan (connection); - NMDevice *parent_device; - const char *setting_parent, *new_parent; int new_mode; if (!s_macvlan) { @@ -392,24 +408,11 @@ update_connection (NMDevice *device, NMConnection *connection) if (priv->props.tap != nm_setting_macvlan_get_tap (s_macvlan)) g_object_set (s_macvlan, NM_SETTING_MACVLAN_TAP, !!priv->props.tap, NULL); - /* Update parent in the connection; default to parent's interface name */ - parent_device = nm_device_parent_get_device (device); - if (parent_device) { - new_parent = nm_device_get_iface (parent_device); - setting_parent = nm_setting_macvlan_get_parent (s_macvlan); - if (setting_parent && nm_utils_is_uuid (setting_parent)) { - NMConnection *parent_connection; - - /* Don't change a parent specified by UUID if it's still valid */ - parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (nm_device_get_settings (device), setting_parent); - if (parent_connection && nm_device_check_connection_compatible (parent_device, parent_connection)) - new_parent = NULL; - } - if (new_parent) - g_object_set (s_macvlan, NM_SETTING_MACVLAN_PARENT, new_parent, NULL); - } else - g_object_set (s_macvlan, NM_SETTING_MACVLAN_PARENT, NULL, NULL); - + g_object_set (s_macvlan, + NM_SETTING_MACVLAN_PARENT, + nm_device_parent_find_for_connection (device, + nm_setting_macvlan_get_parent (s_macvlan)), + NULL); } static NMActStageReturn @@ -495,17 +498,18 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP) - object_class->get_property = get_property; object_class->set_property = set_property; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_macvlan); + device_class->connection_type_supported = NM_SETTING_MACVLAN_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_MACVLAN_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP); + device_class->act_stage1_prepare = act_stage1_prepare; device_class->check_connection_compatible = check_connection_compatible; device_class->complete_connection = complete_connection; - device_class->connection_type = NM_SETTING_MACVLAN_SETTING_NAME; device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c index a6abb228..74b4d710 100644 --- a/src/devices/nm-device-ppp.c +++ b/src/devices/nm-device-ppp.c @@ -49,24 +49,6 @@ G_DEFINE_TYPE (NMDevicePpp, nm_device_ppp, NM_TYPE_DEVICE) #define NM_DEVICE_PPP_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDevicePpp, NM_IS_DEVICE_PPP) -static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingPppoe *s_pppoe; - - if (!NM_DEVICE_CLASS (nm_device_ppp_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - if (!nm_streq0 (nm_connection_get_connection_type (connection), - NM_SETTING_PPPOE_SETTING_NAME)) - return FALSE; - - s_pppoe = nm_connection_get_setting_pppoe (connection); - nm_assert (s_pppoe); - - return !!nm_setting_pppoe_get_parent (s_pppoe); -} - static NMDeviceCapabilities get_generic_capabilities (NMDevice *device) { @@ -275,20 +257,21 @@ nm_device_ppp_class_init (NMDevicePppClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_PPPOE_SETTING_NAME, NM_LINK_TYPE_PPP) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->dispose = dispose; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ppp); - parent_class->act_stage2_config = act_stage2_config; - parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->create_and_realize = create_and_realize; - parent_class->deactivate = deactivate; - parent_class->get_generic_capabilities = get_generic_capabilities; + device_class->connection_type_supported = NM_SETTING_PPPOE_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_PPPOE_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_PPP); + + device_class->act_stage2_config = act_stage2_config; + device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->create_and_realize = create_and_realize; + device_class->deactivate = deactivate; + device_class->get_generic_capabilities = get_generic_capabilities; } /*****************************************************************************/ diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index ba28e9e4..66c715de 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -130,12 +130,21 @@ void nm_device_commit_mtu (NMDevice *self); /*****************************************************************************/ -#define NM_DEVICE_CLASS_DECLARE_TYPES(klass, conn_type, ...) \ - NM_DEVICE_CLASS (klass)->connection_type = conn_type; \ - { \ - static const NMLinkType link_types[] = { __VA_ARGS__, NM_LINK_TYPE_NONE }; \ - NM_DEVICE_CLASS (klass)->link_types = link_types; \ - } +#define NM_DEVICE_DEFINE_LINK_TYPES(...) \ + ((NM_NARG (__VA_ARGS__) == 0) \ + ? NULL \ + : ({ \ + static const struct { \ + const NMLinkType types[NM_NARG (__VA_ARGS__)]; \ + const NMLinkType sentinel; \ + } _link_types = { \ + .types = { __VA_ARGS__ }, \ + .sentinel = NM_LINK_TYPE_NONE, \ + }; \ + \ + _link_types.types; \ + })\ + ) gboolean _nm_device_hash_check_invalid_keys (GHashTable *hash, const char *setting_name, GError **error, const char **whitelist); @@ -143,8 +152,8 @@ gboolean _nm_device_hash_check_invalid_keys (GHashTable *hash, const char *setti _nm_device_hash_check_invalid_keys (hash, setting_name, error, ((const char *[]) { __VA_ARGS__, NULL })) gboolean nm_device_match_parent (NMDevice *device, const char *parent); -gboolean nm_device_match_hwaddr (NMDevice *device, - NMConnection *connection, - gboolean fail_if_no_hwaddr); +gboolean nm_device_match_parent_hwaddr (NMDevice *device, + NMConnection *connection, + gboolean fail_if_no_hwaddr); #endif /* NM_DEVICE_PRIVATE_H */ diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index 3846676c..0f76b23a 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -289,18 +289,14 @@ _same_og (const char *str, gboolean og_valid, guint32 og_num) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceTun *self = NM_DEVICE_TUN (device); NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); NMSettingTunMode mode; NMSettingTun *s_tun; - if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_tun = nm_connection_get_setting_tun (connection); - if (!s_tun) + if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; if (nm_device_is_real (device)) { @@ -308,22 +304,43 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) case IFF_TUN: mode = NM_SETTING_TUN_MODE_TUN; break; case IFF_TAP: mode = NM_SETTING_TUN_MODE_TAP; break; default: - /* Huh? */ + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "invalid tun type on device"); return FALSE; } - if (mode != nm_setting_tun_get_mode (s_tun)) + s_tun = nm_connection_get_setting_tun (connection); + + if (mode != nm_setting_tun_get_mode (s_tun)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "tun mode setting mismatches"); return FALSE; - if (!_same_og (nm_setting_tun_get_owner (s_tun), priv->props.owner_valid, priv->props.owner)) + } + if (!_same_og (nm_setting_tun_get_owner (s_tun), priv->props.owner_valid, priv->props.owner)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "tun owner setting mismatches"); return FALSE; - if (!_same_og (nm_setting_tun_get_group (s_tun), priv->props.group_valid, priv->props.group)) + } + if (!_same_og (nm_setting_tun_get_group (s_tun), priv->props.group_valid, priv->props.group)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "tun group setting mismatches"); return FALSE; - if (nm_setting_tun_get_pi (s_tun) != priv->props.pi) + } + if (nm_setting_tun_get_pi (s_tun) != priv->props.pi) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "tun pi setting mismatches"); return FALSE; - if (nm_setting_tun_get_vnet_hdr (s_tun) != priv->props.vnet_hdr) + } + if (nm_setting_tun_get_vnet_hdr (s_tun) != priv->props.vnet_hdr) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "tun vnet-hdr setting mismatches"); return FALSE; - if (nm_setting_tun_get_multi_queue (s_tun) != priv->props.multi_queue) + } + if (nm_setting_tun_get_multi_queue (s_tun) != priv->props.multi_queue) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "tun multi-queue setting mismatches"); return FALSE; + } } return TRUE; @@ -430,13 +447,14 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_TUN) - object_class->get_property = get_property; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_tun); - device_class->connection_type = NM_SETTING_TUN_SETTING_NAME; + device_class->connection_type_supported = NM_SETTING_TUN_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_TUN_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_TUN); + device_class->link_changed = link_changed; device_class->complete_connection = complete_connection; device_class->check_connection_compatible = check_connection_compatible; diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c index 186173eb..6f90758c 100644 --- a/src/devices/nm-device-veth.c +++ b/src/devices/nm-device-veth.c @@ -153,12 +153,13 @@ nm_device_veth_class_init (NMDeviceVethClass *klass) NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_VETH) - object_class->get_property = get_property; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_veth); + device_class->connection_type_supported = NULL; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_VETH); + device_class->can_unmanaged_external_down = can_unmanaged_external_down; device_class->link_changed = link_changed; device_class->parent_changed_notify = parent_changed_notify; diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index b0e746a8..b7f0c4e7 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -331,33 +331,39 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) /*****************************************************************************/ static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE ((NMDeviceVlan *) device); NMSettingVlan *s_vlan; - const char *parent = NULL; + const char *parent; - if (!NM_DEVICE_CLASS (nm_device_vlan_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_vlan_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; - s_vlan = nm_connection_get_setting_vlan (connection); - if (!s_vlan) - return FALSE; - - /* Before the device is realized some properties will not be set */ if (nm_device_is_real (device)) { - if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id) + s_vlan = nm_connection_get_setting_vlan (connection); + + if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vlan id setting mismatches"); return FALSE; + } /* Check parent interface; could be an interface name or a UUID */ parent = nm_setting_vlan_get_parent (s_vlan); if (parent) { - if (!nm_device_match_parent (device, parent)) + if (!nm_device_match_parent (device, parent)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vlan parent setting differs"); return FALSE; + } } else { /* Parent could be a MAC address in an NMSettingWired */ - if (!nm_device_match_hwaddr (device, connection, TRUE)) + if (!nm_device_match_parent_hwaddr (device, connection, TRUE)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vlan parent mac setting differs"); return FALSE; + } } } @@ -368,12 +374,13 @@ static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { if (!nm_device_is_real (device)) return TRUE; - return NM_DEVICE_CLASS (nm_device_vlan_parent_class)->check_connection_available (device, connection, flags, specific_object); + return NM_DEVICE_CLASS (nm_device_vlan_parent_class)->check_connection_available (device, connection, flags, specific_object, error); } static gboolean @@ -405,7 +412,7 @@ complete_connection (NMDevice *device, * settings, then there's not enough information to complete the setting. */ if ( !nm_setting_vlan_get_parent (s_vlan) - && !nm_device_match_hwaddr (device, connection, TRUE)) { + && !nm_device_match_parent_hwaddr (device, connection, TRUE)) { g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, "The 'vlan' setting had no interface name, parent, or hardware address."); return FALSE; @@ -420,10 +427,8 @@ update_connection (NMDevice *device, NMConnection *connection) NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device); NMSettingVlan *s_vlan = nm_connection_get_setting_vlan (connection); int ifindex = nm_device_get_ifindex (device); - const char *setting_parent, *new_parent; const NMPlatformLink *plink; const NMPObject *polnk; - NMDevice *parent_device; guint vlan_id; guint vlan_flags; @@ -441,26 +446,11 @@ update_connection (NMDevice *device, NMConnection *connection) if (vlan_id != nm_setting_vlan_get_id (s_vlan)) g_object_set (s_vlan, NM_SETTING_VLAN_ID, vlan_id, NULL); - /* Update parent in the connection; default to parent's interface name */ - parent_device = nm_device_parent_get_device (device); - if ( parent_device - && polnk - && plink->parent > 0 - && nm_device_get_ifindex (parent_device) == plink->parent) { - new_parent = nm_device_get_iface (parent_device); - setting_parent = nm_setting_vlan_get_parent (s_vlan); - if (setting_parent && nm_utils_is_uuid (setting_parent)) { - NMConnection *parent_connection; - - /* Don't change a parent specified by UUID if it's still valid */ - parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (nm_device_get_settings (device), setting_parent); - if (parent_connection && nm_device_check_connection_compatible (parent_device, parent_connection)) - new_parent = NULL; - } - if (new_parent) - g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, new_parent, NULL); - } else - g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, NULL, NULL); + g_object_set (s_vlan, + NM_SETTING_VLAN_PARENT, + nm_device_parent_find_for_connection (device, + nm_setting_vlan_get_parent (s_vlan)), + NULL); if (polnk) vlan_flags = polnk->lnk_vlan.flags; @@ -599,27 +589,29 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_VLAN_SETTING_NAME, NM_LINK_TYPE_VLAN) + 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_vlan); - parent_class->create_and_realize = create_and_realize; - parent_class->link_changed = link_changed; - parent_class->unrealize_notify = unrealize_notify; - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->get_configured_mtu = get_configured_mtu; - parent_class->is_available = is_available; - parent_class->parent_changed_notify = parent_changed_notify; - - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->check_connection_available = check_connection_available; - parent_class->complete_connection = complete_connection; - parent_class->update_connection = update_connection; + device_class->connection_type_supported = NM_SETTING_VLAN_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_VLAN_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_VLAN); + + device_class->create_and_realize = create_and_realize; + device_class->link_changed = link_changed; + device_class->unrealize_notify = unrealize_notify; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->get_configured_mtu = get_configured_mtu; + device_class->is_available = is_available; + device_class->parent_changed_notify = parent_changed_notify; + + device_class->check_connection_compatible = check_connection_compatible; + device_class->check_connection_available = check_connection_available; + device_class->complete_connection = complete_connection; + device_class->update_connection = update_connection; obj_properties[PROP_VLAN_ID] = g_param_spec_uint (NM_DEVICE_VLAN_ID, "", "", diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c index e1252223..c34f4142 100644 --- a/src/devices/nm-device-vxlan.c +++ b/src/devices/nm-device-vxlan.c @@ -246,65 +246,108 @@ address_matches (const char *str, in_addr_t addr4, struct in6_addr *addr6) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE ((NMDeviceVxlan *) device); NMSettingVxlan *s_vxlan; const char *parent; - if (!NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_vxlan = nm_connection_get_setting_vxlan (connection); - if (!s_vxlan) + if (!NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; if (nm_device_is_real (device)) { + s_vxlan = nm_connection_get_setting_vxlan (connection); + parent = nm_setting_vxlan_get_parent (s_vxlan); - if (parent && !nm_device_match_parent (device, parent)) + if (parent && !nm_device_match_parent (device, parent)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan parent mismatches"); return FALSE; + } - if (priv->props.id != nm_setting_vxlan_get_id (s_vxlan)) + if (priv->props.id != nm_setting_vxlan_get_id (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan id mismatches"); return FALSE; + } - if (!address_matches (nm_setting_vxlan_get_local (s_vxlan), priv->props.local, &priv->props.local6)) + if (!address_matches (nm_setting_vxlan_get_local (s_vxlan), priv->props.local, &priv->props.local6)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan local address mismatches"); return FALSE; + } - if (!address_matches (nm_setting_vxlan_get_remote (s_vxlan), priv->props.group, &priv->props.group6)) + if (!address_matches (nm_setting_vxlan_get_remote (s_vxlan), priv->props.group, &priv->props.group6)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan remote address mismatches"); return FALSE; + } - if (priv->props.src_port_min != nm_setting_vxlan_get_source_port_min (s_vxlan)) + if (priv->props.src_port_min != nm_setting_vxlan_get_source_port_min (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan source port min mismatches"); return FALSE; + } - if (priv->props.src_port_max != nm_setting_vxlan_get_source_port_max (s_vxlan)) + if (priv->props.src_port_max != nm_setting_vxlan_get_source_port_max (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan source port max mismatches"); return FALSE; + } - if (priv->props.dst_port != nm_setting_vxlan_get_destination_port (s_vxlan)) + if (priv->props.dst_port != nm_setting_vxlan_get_destination_port (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan destination port mismatches"); return FALSE; + } - if (priv->props.tos != nm_setting_vxlan_get_tos (s_vxlan)) + if (priv->props.tos != nm_setting_vxlan_get_tos (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan TOS mismatches"); return FALSE; + } - if (priv->props.ttl != nm_setting_vxlan_get_ttl (s_vxlan)) + if (priv->props.ttl != nm_setting_vxlan_get_ttl (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan TTL mismatches"); return FALSE; + } - if (priv->props.learning != nm_setting_vxlan_get_learning (s_vxlan)) + if (priv->props.learning != nm_setting_vxlan_get_learning (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan learning mismatches"); return FALSE; + } - if (priv->props.ageing != nm_setting_vxlan_get_ageing (s_vxlan)) + if (priv->props.ageing != nm_setting_vxlan_get_ageing (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan ageing mismatches"); return FALSE; + } - if (priv->props.proxy != nm_setting_vxlan_get_proxy (s_vxlan)) + if (priv->props.proxy != nm_setting_vxlan_get_proxy (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan proxy mismatches"); return FALSE; + } - if (priv->props.rsc != nm_setting_vxlan_get_rsc (s_vxlan)) + if (priv->props.rsc != nm_setting_vxlan_get_rsc (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan rsc mismatches"); return FALSE; + } - if (priv->props.l2miss != nm_setting_vxlan_get_l2_miss (s_vxlan)) + if (priv->props.l2miss != nm_setting_vxlan_get_l2_miss (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan l2miss mismatches"); return FALSE; + } - if (priv->props.l3miss != nm_setting_vxlan_get_l3_miss (s_vxlan)) + if (priv->props.l3miss != nm_setting_vxlan_get_l3_miss (s_vxlan)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "vxlan l3miss mismatches"); return FALSE; + } } return TRUE; @@ -343,9 +386,6 @@ update_connection (NMDevice *device, NMConnection *connection) { NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE ((NMDeviceVxlan *) device); NMSettingVxlan *s_vxlan = nm_connection_get_setting_vxlan (connection); - NMDevice *parent_device; - const char *setting_parent; - const char *new_parent = NULL; if (!s_vxlan) { s_vxlan = (NMSettingVxlan *) nm_setting_vxlan_new (); @@ -355,23 +395,11 @@ update_connection (NMDevice *device, NMConnection *connection) if (priv->props.id != nm_setting_vxlan_get_id (s_vxlan)) g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_ID, priv->props.id, NULL); - parent_device = nm_device_parent_get_device (device); - - /* Update parent in the connection; default to parent's interface name */ - if (parent_device) { - new_parent = nm_device_get_iface (parent_device); - setting_parent = nm_setting_vxlan_get_parent (s_vxlan); - if (setting_parent && nm_utils_is_uuid (setting_parent)) { - NMConnection *parent_connection; - - /* Don't change a parent specified by UUID if it's still valid */ - parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (nm_device_get_settings (device), - setting_parent); - if (parent_connection && nm_device_check_connection_compatible (parent_device, parent_connection)) - new_parent = NULL; - } - } - g_object_set (s_vxlan, NM_SETTING_VXLAN_PARENT, new_parent, NULL); + g_object_set (s_vxlan, + NM_SETTING_VXLAN_PARENT, + nm_device_parent_find_for_connection (device, + nm_setting_vxlan_get_parent (s_vxlan)), + NULL); if (!address_matches (nm_setting_vxlan_get_remote (s_vxlan), priv->props.group, &priv->props.group6)) { if (priv->props.group) { @@ -577,15 +605,16 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_VXLAN) - object_class->get_property = get_property; dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_vxlan); + device_class->connection_type_supported = NM_SETTING_VXLAN_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_VXLAN_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_VXLAN); + device_class->link_changed = link_changed; device_class->unrealize_notify = unrealize_notify; - device_class->connection_type = NM_SETTING_VXLAN_SETTING_NAME; device_class->create_and_realize = create_and_realize; device_class->check_connection_compatible = check_connection_compatible; device_class->complete_connection = complete_connection; diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c new file mode 100644 index 00000000..62ec0274 --- /dev/null +++ b/src/devices/nm-device-wireguard.c @@ -0,0 +1,212 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2018 Javier Arteaga <jarteaga@jbeta.is> + */ + +#include "nm-default.h" + +#include "nm-device-wireguard.h" + +#include "nm-device-private.h" +#include "platform/nm-platform.h" +#include "nm-device-factory.h" + +#include "nm-device-logging.h" +_LOG_DECLARE_SELF(NMDeviceWireGuard); + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceWireGuard, + PROP_PUBLIC_KEY, + PROP_LISTEN_PORT, + PROP_FWMARK, +); + +struct _NMDeviceWireGuard { + NMDevice parent; + NMPlatformLnkWireGuard props; +}; + +struct _NMDeviceWireGuardClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDeviceWireGuard, nm_device_wireguard, NM_TYPE_DEVICE) + +/******************************************************************/ + +static GVariant * +get_public_key_as_variant (const NMDeviceWireGuard *self) +{ + return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + self->props.public_key, sizeof (self->props.public_key), 1); +} + +static void +update_properties (NMDevice *device) +{ + NMDeviceWireGuard *self; + const NMPlatformLink *plink; + const NMPlatformLnkWireGuard *props = NULL; + int ifindex; + + g_return_if_fail (NM_IS_DEVICE_WIREGUARD (device)); + self = NM_DEVICE_WIREGUARD (device); + + ifindex = nm_device_get_ifindex (device); + props = nm_platform_link_get_lnk_wireguard (nm_device_get_platform (device), ifindex, &plink); + if (!props) { + _LOGW (LOGD_PLATFORM, "could not get wireguard properties"); + return; + } + + g_object_freeze_notify (G_OBJECT (device)); + +#define CHECK_PROPERTY_CHANGED(field, prop) \ + G_STMT_START { \ + if (self->props.field != props->field) { \ + self->props.field = props->field; \ + _notify (self, prop); \ + } \ + } G_STMT_END + +#define CHECK_PROPERTY_CHANGED_ARRAY(field, prop) \ + G_STMT_START { \ + if (memcmp (&self->props.field, &props->field, sizeof (props->field)) != 0) { \ + memcpy (&self->props.field, &props->field, sizeof (props->field)); \ + _notify (self, prop); \ + } \ + } G_STMT_END + + CHECK_PROPERTY_CHANGED_ARRAY (public_key, PROP_PUBLIC_KEY); + CHECK_PROPERTY_CHANGED (listen_port, PROP_LISTEN_PORT); + CHECK_PROPERTY_CHANGED (fwmark, PROP_FWMARK); + + g_object_thaw_notify (G_OBJECT (device)); +} + +static void +link_changed (NMDevice *device, + const NMPlatformLink *pllink) +{ + NM_DEVICE_CLASS (nm_device_wireguard_parent_class)->link_changed (device, pllink); + update_properties (device); +} + + +/******************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD (object); + + switch (prop_id) { + case PROP_PUBLIC_KEY: + g_value_take_variant (value, get_public_key_as_variant (self)); + break; + case PROP_LISTEN_PORT: + g_value_set_uint (value, self->props.listen_port); + break; + case PROP_FWMARK: + g_value_set_uint (value, self->props.fwmark); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_device_wireguard_init (NMDeviceWireGuard *self) +{ +} + +static const NMDBusInterfaceInfoExtended interface_info_device_wireguard = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( + NM_DBUS_INTERFACE_DEVICE_WIREGUARD, + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("PublicKey", "ay", NM_DEVICE_WIREGUARD_PUBLIC_KEY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("ListenPort", "q", NM_DEVICE_WIREGUARD_LISTEN_PORT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("FwMark", "u", NM_DEVICE_WIREGUARD_FWMARK), + ), + ), +}; + +static void +nm_device_wireguard_class_init (NMDeviceWireGuardClass *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_wireguard); + + device_class->connection_type_supported = NULL; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_WIREGUARD); + + device_class->link_changed = link_changed; + + obj_properties[PROP_PUBLIC_KEY] = + g_param_spec_variant (NM_DEVICE_WIREGUARD_PUBLIC_KEY, + "", "", + G_VARIANT_TYPE ("ay"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_LISTEN_PORT] = + g_param_spec_uint (NM_DEVICE_WIREGUARD_LISTEN_PORT, + "", "", + 0, G_MAXUINT16, 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + obj_properties[PROP_FWMARK] = + g_param_spec_uint (NM_DEVICE_WIREGUARD_FWMARK, + "", "", + 0, G_MAXUINT32, 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); +} + +/*************************************************************/ + +#define NM_TYPE_WIREGUARD_DEVICE_FACTORY (nm_wireguard_device_factory_get_type ()) +#define NM_WIREGUARD_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WIREGUARD_DEVICE_FACTORY, NMWireGuardDeviceFactory)) + +static NMDevice * +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_WIREGUARD, + NM_DEVICE_IFACE, iface, + NM_DEVICE_TYPE_DESC, "WireGuard", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_WIREGUARD, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_WIREGUARD, + NULL); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL (WIREGUARD, WireGuard, wireguard, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WIREGUARD), + factory_class->create_device = create_device; +) diff --git a/src/devices/nm-device-wireguard.h b/src/devices/nm-device-wireguard.h new file mode 100644 index 00000000..3ad41f9b --- /dev/null +++ b/src/devices/nm-device-wireguard.h @@ -0,0 +1,41 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2018 Javier Arteaga <jarteaga@jbeta.is> + */ + +#ifndef __NM_DEVICE_WIREGUARD_H__ +#define __NM_DEVICE_WIREGUARD_H__ + +#include "nm-device.h" + +#define NM_TYPE_DEVICE_WIREGUARD (nm_device_wireguard_get_type ()) +#define NM_DEVICE_WIREGUARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_WIREGUARD, NMDeviceWireGuard)) +#define NM_DEVICE_WIREGUARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_WIREGUARD, NMDeviceWireGuardClass)) +#define NM_IS_DEVICE_WIREGUARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_WIREGUARD)) +#define NM_IS_DEVICE_WIREGUARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_WIREGUARD)) +#define NM_DEVICE_WIREGUARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_WIREGUARD, NMDeviceWireGuardClass)) + +#define NM_DEVICE_WIREGUARD_PUBLIC_KEY "public-key" +#define NM_DEVICE_WIREGUARD_LISTEN_PORT "listen-port" +#define NM_DEVICE_WIREGUARD_FWMARK "fwmark" + +typedef struct _NMDeviceWireGuard NMDeviceWireGuard; +typedef struct _NMDeviceWireGuardClass NMDeviceWireGuardClass; + +GType nm_device_wireguard_get_type (void); + +#endif /* __NM_DEVICE_WIREGUARD_H__ */ diff --git a/src/devices/nm-device-wpan.c b/src/devices/nm-device-wpan.c new file mode 100644 index 00000000..f910b0b8 --- /dev/null +++ b/src/devices/nm-device-wpan.c @@ -0,0 +1,253 @@ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2018 Lubomir Rintel <lkundrak@v3.sk> + */ + +#include "nm-default.h" + +#include "nm-manager.h" +#include "nm-device-wpan.h" + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "nm-act-request.h" +#include "nm-device-private.h" +#include "nm-ip4-config.h" +#include "platform/nm-platform.h" +#include "nm-device-factory.h" +#include "nm-setting-wpan.h" +#include "nm-core-internal.h" + +#include "nm-device-logging.h" +_LOG_DECLARE_SELF(NMDeviceWpan); + +/*****************************************************************************/ + +struct _NMDeviceWpan { + NMDevice parent; +}; + +struct _NMDeviceWpanClass { + NMDeviceClass parent; +}; + +G_DEFINE_TYPE (NMDeviceWpan, nm_device_wpan, NM_TYPE_DEVICE) + +/*****************************************************************************/ + +static gboolean +complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + NMConnection *const*existing_connections, + GError **error) +{ + NMSettingWpan *s_wpan; + + nm_utils_complete_generic (nm_device_get_platform (device), + connection, + NM_SETTING_WPAN_SETTING_NAME, + existing_connections, + NULL, + _("WPAN connection"), + NULL, + TRUE); + + s_wpan = NM_SETTING_WPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_WPAN)); + if (!s_wpan) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + "A 'wpan' setting is required."); + return FALSE; + } + + return TRUE; +} + +static void +update_connection (NMDevice *device, NMConnection *connection) +{ + NMSettingWpan *s_wpan = NM_SETTING_WPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_WPAN)); + + if (!s_wpan) { + s_wpan = (NMSettingWpan *) nm_setting_wpan_new (); + nm_connection_add_setting (connection, (NMSetting *) s_wpan); + } +} + +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) +{ + NMSettingWpan *s_wpan; + const char *mac, *hw_addr; + + if (!NM_DEVICE_CLASS (nm_device_wpan_parent_class)->check_connection_compatible (device, connection, error)) + return FALSE; + + s_wpan = NM_SETTING_WPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_WPAN)); + + mac = nm_setting_wpan_get_mac_address (s_wpan); + if (mac) { + hw_addr = nm_device_get_hw_address (device); + if (!nm_utils_hwaddr_matches (mac, -1, hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "MAC address mismatches"); + return FALSE; + } + } + + return TRUE; +} + +static NMActStageReturn +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) +{ + NMDeviceWpan *self = NM_DEVICE_WPAN (device); + NMConnection *connection; + NMSettingWpan *s_wpan; + NMPlatform *platform; + guint16 pan_id; + guint16 short_address; + int ifindex; + const guint8 *hwaddr; + gsize hwaddr_len = 0; + const NMPlatformLink *lowpan_plink; + NMDevice *lowpan_device = NULL; + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + + ret = NM_DEVICE_CLASS (nm_device_wpan_parent_class)->act_stage1_prepare (device, out_failure_reason); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + + platform = nm_device_get_platform (device); + g_return_val_if_fail (platform, NM_ACT_STAGE_RETURN_FAILURE); + + ifindex = nm_device_get_ifindex (device); + g_return_val_if_fail (ifindex > 0, NM_ACT_STAGE_RETURN_FAILURE); + + connection = nm_device_get_applied_connection (device); + g_return_val_if_fail (connection, NM_ACT_STAGE_RETURN_FAILURE); + + s_wpan = NM_SETTING_WPAN (nm_connection_get_setting (connection, NM_TYPE_SETTING_WPAN)); + g_return_val_if_fail (s_wpan, NM_ACT_STAGE_RETURN_FAILURE); + + hwaddr = nm_platform_link_get_address (platform, ifindex, &hwaddr_len); + g_return_val_if_fail (hwaddr, NM_ACT_STAGE_RETURN_FAILURE); + + /* As of kernel 4.16, the 6LoWPAN devices layered on top of WPANs + * need to be DOWN as well as the WPAN device itself in order to + * modify the WPAN properties. */ + lowpan_plink = nm_platform_link_get_by_address (platform, + NM_LINK_TYPE_6LOWPAN, + hwaddr, + hwaddr_len); + if (lowpan_plink && NM_FLAGS_HAS (lowpan_plink->n_ifi_flags, IFF_UP)) { + lowpan_device = nm_manager_get_device_by_ifindex (nm_manager_get (), + lowpan_plink->ifindex); + } + + if (lowpan_device) + nm_device_take_down (lowpan_device, TRUE); + + nm_device_take_down (device, TRUE); + + pan_id = nm_setting_wpan_get_pan_id (s_wpan); + if (pan_id != G_MAXUINT16) { + if (!nm_platform_wpan_set_pan_id (platform, ifindex, pan_id)) { + _LOGW (LOGD_DEVICE, "unable to set the PAN ID"); + goto out; + } + } + + short_address = nm_setting_wpan_get_short_address (s_wpan); + if (short_address != G_MAXUINT16) { + if (!nm_platform_wpan_set_short_addr (platform, ifindex, short_address)) { + _LOGW (LOGD_DEVICE, "unable to set the short address"); + goto out; + } + } + + ret = NM_ACT_STAGE_RETURN_SUCCESS; +out: + nm_device_bring_up (device, TRUE, NULL); + + if (lowpan_device) + nm_device_bring_up (lowpan_device, TRUE, NULL); + + return ret; +} + +/*****************************************************************************/ + +static void +nm_device_wpan_init (NMDeviceWpan *self) +{ +} + +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), + ), + ), +}; + +static void +nm_device_wpan_class_init (NMDeviceWpanClass *klass) +{ + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); + + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_wpan); + + device_class->connection_type_supported = NM_SETTING_WPAN_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_WPAN_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_WPAN); + + device_class->complete_connection = complete_connection; + device_class->check_connection_compatible = check_connection_compatible; + device_class->update_connection = update_connection; + device_class->act_stage1_prepare = act_stage1_prepare; +} + +/*****************************************************************************/ + +#define NM_TYPE_WPAN_DEVICE_FACTORY (nm_wpan_device_factory_get_type ()) +#define NM_WPAN_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WPAN_DEVICE_FACTORY, NMWpanDeviceFactory)) + +static NMDevice * +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_WPAN, + NM_DEVICE_IFACE, iface, + NM_DEVICE_TYPE_DESC, "WPAN", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_WPAN, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_WPAN, + NULL); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL (WPAN, Wpan, wpan, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WPAN) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WPAN_SETTING_NAME), + factory_class->create_device = create_device; +); diff --git a/src/devices/nm-device-wpan.h b/src/devices/nm-device-wpan.h new file mode 100644 index 00000000..33f24776 --- /dev/null +++ b/src/devices/nm-device-wpan.h @@ -0,0 +1,35 @@ +/* NetworkManager -- Network link manager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright 2018 Lubomir Rintel <lkundrak@v3.sk> + */ + +#ifndef __NETWORKMANAGER_DEVICE_WPAN_H__ +#define __NETWORKMANAGER_DEVICE_WPAN_H__ + +#define NM_TYPE_DEVICE_WPAN (nm_device_wpan_get_type ()) +#define NM_DEVICE_WPAN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_WPAN, NMDeviceWpan)) +#define NM_DEVICE_WPAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_WPAN, NMDeviceWpanClass)) +#define NM_IS_DEVICE_WPAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_WPAN)) +#define NM_IS_DEVICE_WPAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_WPAN)) +#define NM_DEVICE_WPAN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_WPAN, NMDeviceWpanClass)) + +typedef struct _NMDeviceWpan NMDeviceWpan; +typedef struct _NMDeviceWpanClass NMDeviceWpanClass; + +GType nm_device_wpan_get_type (void); + +#endif /* __NETWORKMANAGER_DEVICE_WPAN_H__ */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 33dd5e50..26ea06bd 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2005 - 2017 Red Hat, Inc. + * Copyright (C) 2005 - 2018 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ @@ -43,6 +43,7 @@ #include "nm-utils/nm-random-utils.h" #include "nm-utils/unaligned.h" +#include "nm-ethtool-utils.h" #include "nm-common-macros.h" #include "nm-device-private.h" #include "NetworkManagerUtils.h" @@ -65,6 +66,7 @@ #include "nm-firewall-manager.h" #include "settings/nm-settings-connection.h" #include "settings/nm-settings.h" +#include "nm-setting-ethtool.h" #include "nm-auth-utils.h" #include "nm-netns.h" #include "nm-dispatcher.h" @@ -78,7 +80,10 @@ #include "nm-audit-manager.h" #include "nm-connectivity.h" #include "nm-dbus-interface.h" + +#include "nm-device-generic.h" #include "nm-device-vlan.h" +#include "nm-device-wireguard.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF (NMDevice); @@ -172,6 +177,12 @@ struct _NMDeviceConnectivityHandle { bool is_periodic_bump_on_complete:1; }; +typedef struct { + int ifindex; + NMEthtoolFeatureStates *features; + NMTernary requested[_NM_ETHTOOL_ID_FEATURE_NUM]; +} EthtoolState; + /*****************************************************************************/ enum { @@ -453,6 +464,7 @@ typedef struct _NMDevicePrivate { gulong state_sigid; NMDhcp4Config * config; char * pac_url; + char * root_path; bool was_active; guint grace_id; } dhcp4; @@ -508,6 +520,8 @@ typedef struct _NMDevicePrivate { GHashTable * ip6_saved_properties; + EthtoolState *ethtool_state; + struct { NMDhcpClient * client; NMNDiscDHCPLevel mode; @@ -614,7 +628,7 @@ static void _set_state_full (NMDevice *self, static void queued_state_clear (NMDevice *device); static gboolean queued_ip4_config_change (gpointer user_data); static gboolean queued_ip6_config_change (gpointer user_data); -static void ip_check_ping_watch_cb (GPid pid, gint status, gpointer user_data); +static void ip_check_ping_watch_cb (GPid pid, int status, gpointer user_data); static gboolean ip_config_valid (NMDeviceState state); static NMActStageReturn dhcp4_start (NMDevice *self); static gboolean dhcp6_start (NMDevice *self, gboolean wait_for_ll); @@ -724,6 +738,7 @@ NM_UTILS_LOOKUP_STR_DEFINE (nm_device_state_reason_to_str, NMDeviceStateReason, NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_OVSDB_FAILED, "ovsdb-failed"), NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE, "ip-address-duplicate"), NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED, "ip-method-unsupported"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED, "sriov-configuration-failed"), ); #define reason_to_string(reason) \ @@ -739,6 +754,86 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (mtu_source_to_str, NMDeviceMtuSource, /*****************************************************************************/ +static void +_ethtool_state_reset (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->ethtool_state) { + gs_free NMEthtoolFeatureStates *features = priv->ethtool_state->features; + gs_free EthtoolState *ethtool_state = g_steal_pointer (&priv->ethtool_state); + + if (!nm_platform_ethtool_set_features (nm_device_get_platform (self), + ethtool_state->ifindex, + features, + ethtool_state->requested, + FALSE)) + _LOGW (LOGD_DEVICE, "ethtool: failure resetting one or more offload features"); + else + _LOGD (LOGD_DEVICE, "ethtool: offload features successfully reset"); + } +} + +static void +_ethtool_state_set (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + int ifindex; + NMConnection *connection; + NMSettingEthtool *s_ethtool; + NMPlatform *platform; + gs_free EthtoolState *ethtool_state = NULL; + gs_free NMEthtoolFeatureStates *features = NULL; + + _ethtool_state_reset (self); + + connection = nm_device_get_applied_connection (self); + if (!connection) + return; + + ifindex = nm_device_get_ip_ifindex (self); + if (ifindex <= 0) + return; + + s_ethtool = NM_SETTING_ETHTOOL (nm_connection_get_setting (connection, NM_TYPE_SETTING_ETHTOOL)); + if (!s_ethtool) + return; + + ethtool_state = g_new (EthtoolState, 1); + if (nm_setting_ethtool_init_features (s_ethtool, ethtool_state->requested) == 0) + return; + + platform = nm_device_get_platform (self); + + features = nm_platform_ethtool_get_link_features (platform, ifindex); + if (!features) { + _LOGW (LOGD_DEVICE, "ethtool: failure setting offload features (cannot read features)"); + return; + } + + if (!nm_platform_ethtool_set_features (platform, + ifindex, + features, + ethtool_state->requested, + TRUE)) + _LOGW (LOGD_DEVICE, "ethtool: failure setting one or more offload features"); + else + _LOGD (LOGD_DEVICE, "ethtool: offload features successfully set"); + + ethtool_state->ifindex = ifindex; + ethtool_state->features = g_steal_pointer (&features); + priv->ethtool_state = g_steal_pointer (ðtool_state); +} + +/*****************************************************************************/ + +static gboolean +is_loopback (NMDevice *self) +{ + return NM_IS_DEVICE_GENERIC (self) + && NM_DEVICE_GET_PRIVATE (self)->ifindex == 1; +} + NMSettings * nm_device_get_settings (NMDevice *self) { @@ -1017,15 +1112,19 @@ nm_device_assume_state_reset (NMDevice *self) static void init_ip_config_dns_priority (NMDevice *self, NMIPConfig *config) { - gs_free char *value = NULL; - gint priority; - - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - (nm_ip_config_get_addr_family (config) == AF_INET) - ? "ipv4.dns-priority" - : "ipv6.dns-priority", - self); - priority = _nm_utils_ascii_str_to_int64 (value, 10, G_MININT, G_MAXINT, 0); + const char *property; + int priority; + + property = (nm_ip_config_get_addr_family (config) == AF_INET) + ? "ipv4.dns-priority" + : "ipv6.dns-priority"; + + priority = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + property, + self, + G_MININT, + G_MAXINT, + 0); nm_ip_config_set_dns_priority (config, priority ?: NM_DNS_PRIORITY_DEFAULT_NORMAL); } @@ -1627,6 +1726,41 @@ nm_device_parent_notify_changed (NMDevice *self, /*****************************************************************************/ +const char * +nm_device_parent_find_for_connection (NMDevice *self, + const char *current_setting_parent) +{ + const char *new_parent; + NMDevice *parent_device; + + parent_device = nm_device_parent_get_device (self); + if (!parent_device) + return NULL; + + new_parent = nm_device_get_iface (parent_device); + if (!new_parent) + return NULL; + + if ( current_setting_parent + && !nm_streq (current_setting_parent, new_parent) + && nm_utils_is_uuid (current_setting_parent)) { + NMSettingsConnection *parent_connection; + + /* Don't change a parent specified by UUID if it's still valid */ + parent_connection = nm_settings_get_connection_by_uuid (nm_device_get_settings (self), + current_setting_parent); + if ( parent_connection + && nm_device_check_connection_compatible (parent_device, + nm_settings_connection_get_connection (parent_connection), + NULL)) + return current_setting_parent; + } + + return new_parent; +} + +/*****************************************************************************/ + static void _stats_update_counters (NMDevice *self, guint64 tx_bytes, @@ -1731,7 +1865,11 @@ static gboolean get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMPlatform *platform = nm_device_get_platform (self); const NMPlatformLink *pllink; + const guint8 *hwaddr; + guint8 pseudo_hwaddr[ETH_ALEN]; + guint hwaddr_len; int ifindex; gboolean success; @@ -1739,7 +1877,7 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) ifindex = nm_device_get_ip_ifindex (self); g_return_val_if_fail (ifindex > 0, FALSE); - pllink = nm_platform_link_get (nm_device_get_platform (self), ifindex); + pllink = nm_platform_link_get (platform, ifindex); if ( !pllink || NM_IN_SET (pllink->type, NM_LINK_TYPE_NONE, NM_LINK_TYPE_UNKNOWN)) return FALSE; @@ -1749,9 +1887,35 @@ get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid) if (pllink->addr.len > NM_UTILS_HWADDR_LEN_MAX) g_return_val_if_reached (FALSE); + hwaddr = pllink->addr.data; + hwaddr_len = pllink->addr.len; + + if (pllink->type == NM_LINK_TYPE_6LOWPAN) { + /* If the underlying IEEE 802.15.4 device has a short address we generate + * a "pseudo 48-bit address" that's to be used in the same fashion as a + * wired Ethernet address. The mechanism is specified in Section 6. of + * RFC 4944 */ + guint16 pan_id; + guint16 short_addr; + + short_addr = nm_platform_wpan_get_short_addr (platform, pllink->parent); + if (short_addr != G_MAXUINT16) { + pan_id = nm_platform_wpan_get_pan_id (platform, pllink->parent); + pseudo_hwaddr[0] = short_addr & 0xff; + pseudo_hwaddr[1] = (short_addr >> 8) & 0xff; + pseudo_hwaddr[2] = 0; + pseudo_hwaddr[3] = 0; + pseudo_hwaddr[4] = pan_id & 0xff; + pseudo_hwaddr[5] = (pan_id >> 8) & 0xff; + + hwaddr = pseudo_hwaddr; + hwaddr_len = G_N_ELEMENTS (pseudo_hwaddr); + } + } + success = nm_utils_get_ipv6_interface_identifier (pllink->type, - pllink->addr.data, - pllink->addr.len, + hwaddr, + hwaddr_len, priv->dev_id, out_iid); if (!success) { @@ -1865,7 +2029,9 @@ nm_device_get_route_metric_default (NMDeviceType device_type) */ switch (device_type) { - /* 50 is reserved for VPN (NM_VPN_ROUTE_METRIC_DEFAULT) */ + /* 50 is also used for VPN plugins (NM_VPN_ROUTE_METRIC_DEFAULT) */ + case NM_DEVICE_TYPE_WIREGUARD: + return 50; case NM_DEVICE_TYPE_ETHERNET: case NM_DEVICE_TYPE_VETH: return 100; @@ -1905,10 +2071,14 @@ nm_device_get_route_metric_default (NMDeviceType device_type) return 700; case NM_DEVICE_TYPE_BT: return 750; + case NM_DEVICE_TYPE_6LOWPAN: + return 775; case NM_DEVICE_TYPE_OVS_BRIDGE: case NM_DEVICE_TYPE_OVS_INTERFACE: case NM_DEVICE_TYPE_OVS_PORT: return 800; + case NM_DEVICE_TYPE_WPAN: + return 850; case NM_DEVICE_TYPE_GENERIC: return 950; case NM_DEVICE_TYPE_UNKNOWN: @@ -1953,10 +2123,10 @@ guint32 nm_device_get_route_metric (NMDevice *self, int addr_family) { - char *value; gint64 route_metric; NMSettingIPConfig *s_ip; NMConnection *connection; + const char *property; g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32); g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), G_MAXUINT32); @@ -1981,15 +2151,13 @@ nm_device_get_route_metric (NMDevice *self, /* use the current NMConfigData, which makes this configuration reloadable. * Note that that means that the route-metric might change between SIGHUP. * You must cache the returned value if that is a problem. */ - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - addr_family == AF_INET ? "ipv4.route-metric" : "ipv6.route-metric", self); - if (value) { - route_metric = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, -1); - g_free (value); - - if (route_metric >= 0) - goto out; - } + property = addr_family == AF_INET ? "ipv4.route-metric" : "ipv6.route-metric"; + route_metric = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + property, + self, + 0, G_MAXUINT32, -1); + if (route_metric >= 0) + goto out; route_metric = nm_manager_device_route_metric_reserve (nm_manager_get (), nm_device_get_ip_ifindex (self), @@ -2009,21 +2177,37 @@ _get_mdns (NMDevice *self) connection = nm_device_get_applied_connection (self); if (connection) mdns = nm_setting_connection_get_mdns (nm_connection_get_setting_connection (connection)); + if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) + return mdns; - if (mdns == NM_SETTING_CONNECTION_MDNS_DEFAULT) { - gs_free char *value = NULL; + return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "connection.mdns", + self, + NM_SETTING_CONNECTION_MDNS_NO, + NM_SETTING_CONNECTION_MDNS_YES, + NM_SETTING_CONNECTION_MDNS_DEFAULT); +} - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "connection.mdns", - self); - mdns = _nm_utils_ascii_str_to_int64 (value, - 10, - NM_SETTING_CONNECTION_MDNS_NO, - NM_SETTING_CONNECTION_MDNS_YES, - NM_SETTING_CONNECTION_MDNS_DEFAULT); - } +static NMSettingConnectionLlmnr +_get_llmnr (NMDevice *self) +{ + NMConnection *connection; + NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; + + g_return_val_if_fail (NM_IS_DEVICE (self), NM_SETTING_CONNECTION_LLMNR_DEFAULT); + + connection = nm_device_get_applied_connection (self); + if (connection) + llmnr = nm_setting_connection_get_llmnr (nm_connection_get_setting_connection (connection)); + if (llmnr != NM_SETTING_CONNECTION_LLMNR_DEFAULT) + return llmnr; - return mdns; + return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "connection.llmnr", + self, + NM_SETTING_CONNECTION_LLMNR_NO, + NM_SETTING_CONNECTION_LLMNR_YES, + NM_SETTING_CONNECTION_LLMNR_DEFAULT); } guint32 @@ -2066,14 +2250,13 @@ nm_device_get_route_table (NMDevice *self, * connection. Otherwise, the connection is not active, and the * connection default doesn't matter. */ if (route_table == 0) { - gs_free char *value = NULL; + const char *property; - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - addr_family == AF_INET - ? "ipv4.route-table" - : "ipv6.route-table", - self); - route_table = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, 0); + property = addr_family == AF_INET ? "ipv4.route-table" : "ipv6.route-table"; + route_table = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + property, + self, + 0, G_MAXUINT32, 0); } } @@ -2191,6 +2374,22 @@ nm_device_get_settings_connection (NMDevice *self) } NMConnection * +nm_device_get_settings_connection_get_connection (NMDevice *self) +{ + NMSettingsConnection *sett_con; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (!priv->act_request.obj) + return NULL; + + sett_con = nm_act_request_get_settings_connection (priv->act_request.obj); + if (!sett_con) + return NULL; + + return nm_settings_connection_get_connection (sett_con); +} + +NMConnection * nm_device_get_applied_connection (NMDevice *self) { NMDevicePrivate *priv; @@ -2272,7 +2471,7 @@ concheck_is_possible (NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); if ( !nm_device_is_real (self) - || NM_FLAGS_HAS (priv->unmanaged_flags, NM_UNMANAGED_LOOPBACK)) + || is_loopback (self)) return FALSE; /* we enable periodic checks for every device state (except UNKNOWN). Especially with @@ -3306,7 +3505,8 @@ ndisc_set_router_config (NMNDisc *ndisc, NMDevice *self) guint32 lifetime, preferred; gint32 base; - if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) + if ( IN6_IS_ADDR_UNSPECIFIED (&addr->address) + || IN6_IS_ADDR_LINKLOCAL (&addr->address)) continue; if ( addr->n_ifa_flags & IFA_F_TENTATIVE @@ -3380,6 +3580,7 @@ device_link_changed (NMDevice *self) gboolean ip_ifname_changed = FALSE; nm_auto_nmpobj const NMPObject *pllink_keep_alive = NULL; const NMPlatformLink *pllink; + const char *str; int ifindex; gboolean was_up; gboolean update_unmanaged_specs = FALSE; @@ -3394,7 +3595,23 @@ device_link_changed (NMDevice *self) pllink_keep_alive = nmp_object_ref (NMP_OBJECT_UP_CAST (pllink)); - nm_device_update_from_platform_link (self, pllink); + str = nm_platform_link_get_udi (nm_device_get_platform (self), pllink->ifindex); + if (!nm_streq0 (str, priv->udi)) { + g_free (priv->udi); + priv->udi = g_strdup (str); + _notify (self, PROP_UDI); + } + + if (!nm_streq0 (pllink->driver, priv->driver)) { + g_free (priv->driver); + priv->driver = g_strdup (pllink->driver); + _notify (self, PROP_DRIVER); + } + + _set_mtu (self, pllink->mtu); + + if (ifindex == nm_device_get_ip_ifindex (self)) + _stats_update_counters_from_pllink (self, pllink); had_hw_addr = (priv->hw_addr != NULL); nm_device_update_hw_address (self); @@ -3901,7 +4118,7 @@ nm_device_update_from_platform_link (NMDevice *self, const NMPlatformLink *plink } static void -device_init_sriov_num_vfs (NMDevice *self) +device_init_static_sriov_num_vfs (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); gs_free char *value = NULL; @@ -3915,8 +4132,8 @@ device_init_sriov_num_vfs (NMDevice *self) NULL); num_vfs = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXINT32, -1); if (num_vfs >= 0) { - nm_platform_link_set_sriov_num_vfs (nm_device_get_platform (self), - priv->ifindex, num_vfs); + nm_platform_link_set_sriov_params (nm_device_get_platform (self), + priv->ifindex, num_vfs, -1); } } } @@ -3935,7 +4152,7 @@ config_changed (NMConfig *config, priv->ignore_carrier = nm_config_data_get_ignore_carrier (config_data, self); if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_VALUES)) - device_init_sriov_num_vfs (self); + device_init_static_sriov_num_vfs (self); } static void @@ -4079,7 +4296,7 @@ realize_start_setup (NMDevice *self, nm_device_set_carrier_from_platform (self); - device_init_sriov_num_vfs (self); + device_init_static_sriov_num_vfs (self); nm_assert (!priv->stats.timeout_id); real_rate = _stats_refresh_rate_real (priv->stats.refresh_rate_ms); @@ -4099,10 +4316,13 @@ realize_start_setup (NMDevice *self, NM_UNMANAGED_EXTERNAL_DOWN, is_unmanaged_external_down (self, TRUE)); - /* Unmanaged the loopback device with an explicit NM_UNMANAGED_LOOPBACK flag. + /* Unmanaged the loopback device with an explicit NM_UNMANAGED_BY_TYPE flag. * Later we might want to manage 'lo' too. Currently that doesn't work because * NetworkManager might down the interface or remove the 127.0.0.1 address. */ - nm_device_set_unmanaged_flags (self, NM_UNMANAGED_LOOPBACK, priv->ifindex == 1); + nm_device_set_unmanaged_flags (self, + NM_UNMANAGED_BY_TYPE, + is_loopback (self) + || NM_IS_DEVICE_WIREGUARD (self)); nm_device_set_unmanaged_by_user_udev (self); nm_device_set_unmanaged_by_user_conf (self); @@ -4298,7 +4518,7 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error) nm_device_set_unmanaged_flags (self, NM_UNMANAGED_PARENT | - NM_UNMANAGED_LOOPBACK | + NM_UNMANAGED_BY_TYPE | NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_USER_EXPLICIT | NM_UNMANAGED_EXTERNAL_DOWN | @@ -4379,9 +4599,23 @@ nm_device_owns_iface (NMDevice *self, const char *iface) NMConnection * nm_device_new_default_connection (NMDevice *self) { - if (NM_DEVICE_GET_CLASS (self)->new_default_connection) - return NM_DEVICE_GET_CLASS (self)->new_default_connection (self); - return NULL; + NMConnection *connection; + GError *error = NULL; + + if (!NM_DEVICE_GET_CLASS (self)->new_default_connection) + return NULL; + + connection = NM_DEVICE_GET_CLASS (self)->new_default_connection (self); + if (!connection) + return NULL; + + if (!nm_connection_normalize (connection, NULL, NULL, &error)) { + _LOGD (LOGD_DEVICE, "device generated an invalid default connection: %s", error->message); + g_error_free (error); + g_return_val_if_reached (NULL); + } + + return connection; } static void @@ -4840,11 +5074,15 @@ nm_device_removed (NMDevice *self, gboolean unconfigure_ip_config) nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); } - if (!unconfigure_ip_config) - return; - - nm_device_set_ip_config (self, AF_INET, NULL, FALSE, NULL); - nm_device_set_ip_config (self, AF_INET6, NULL, FALSE, NULL); + if (unconfigure_ip_config) { + nm_device_set_ip_config (self, AF_INET, NULL, FALSE, NULL); + nm_device_set_ip_config (self, AF_INET6, NULL, FALSE, NULL); + } else { + if (priv->dhcp4.client) + nm_dhcp_client_stop (priv->dhcp4.client, FALSE); + if (priv->dhcp6.client) + nm_dhcp_client_stop (priv->dhcp6.client, FALSE); + } } static gboolean @@ -5039,7 +5277,7 @@ nm_device_autoconnect_allowed (NMDevice *self) static gboolean can_auto_connect (NMDevice *self, - NMConnection *connection, + NMSettingsConnection *sett_conn, char **specific_object) { nm_assert (!specific_object || !*specific_object); @@ -5049,27 +5287,27 @@ can_auto_connect (NMDevice *self, /** * nm_device_can_auto_connect: * @self: an #NMDevice - * @connection: a #NMConnection + * @sett_conn: a #NMSettingsConnection * @specific_object: (out) (transfer full): on output, the path of an * object associated with the returned connection, to be passed to * nm_manager_activate_connection(), or %NULL. * - * Checks if @connection can be auto-activated on @self right now. + * Checks if @sett_conn can be auto-activated on @self right now. * This requires, at a minimum, that the connection be compatible with * @self, and that it have the #NMSettingConnection:autoconnect property * set, and that the device allow auto connections. Some devices impose * additional requirements. (Eg, a Wi-Fi connection can only be activated * if its SSID was seen in the last scan.) * - * Returns: %TRUE, if the @connection can be auto-activated. + * Returns: %TRUE, if the @sett_conn can be auto-activated. **/ gboolean nm_device_can_auto_connect (NMDevice *self, - NMConnection *connection, + NMSettingsConnection *sett_conn, char **specific_object) { g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); - g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (sett_conn), FALSE); g_return_val_if_fail (!specific_object || !*specific_object, FALSE); /* the caller must ensure that nm_device_autoconnect_allowed() returns @@ -5081,10 +5319,14 @@ nm_device_can_auto_connect (NMDevice *self, * over and over again. The caller is supposed to do that. */ nm_assert (nm_device_autoconnect_allowed (self)); - if (!nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_NONE, NULL)) + if (!nm_device_check_connection_available (self, + nm_settings_connection_get_connection (sett_conn), + NM_DEVICE_CHECK_CON_AVAILABLE_NONE, + NULL, + NULL)) return FALSE; - if (!NM_DEVICE_GET_CLASS (self)->can_auto_connect (self, connection, specific_object)) + if (!NM_DEVICE_GET_CLASS (self)->can_auto_connect (self, sett_conn, specific_object)) return FALSE; return TRUE; @@ -5205,8 +5447,10 @@ nm_device_generate_connection (NMDevice *self, NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, NM_SETTING_CONNECTION_TIMESTAMP, (guint64) time (NULL), NULL); - if (klass->connection_type) - g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, klass->connection_type, NULL); + + if (klass->connection_type_supported) + g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, klass->connection_type_supported, NULL); + nm_connection_add_setting (connection, s_con); /* If the device is a slave, update various slave settings */ @@ -5242,7 +5486,7 @@ nm_device_generate_connection (NMDevice *self, klass->update_connection (self, connection); - if (!nm_connection_verify (connection, &local)) { + if (!nm_connection_normalize (connection, NULL, NULL, error)) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "generated connection does not verify: %s", local->message); @@ -5358,9 +5602,9 @@ nm_device_match_parent (NMDevice *self, const char *parent) } gboolean -nm_device_match_hwaddr (NMDevice *device, - NMConnection *connection, - gboolean fail_if_no_hwaddr) +nm_device_match_parent_hwaddr (NMDevice *device, + NMConnection *connection, + gboolean fail_if_no_hwaddr) { NMSettingWired *s_wired; NMDevice *parent_device; @@ -5384,21 +5628,62 @@ nm_device_match_hwaddr (NMDevice *device, } static gboolean -check_connection_compatible (NMDevice *self, NMConnection *connection) +check_connection_compatible (NMDevice *self, NMConnection *connection, GError **error) { const char *device_iface = nm_device_get_iface (self); - gs_free char *conn_iface = nm_manager_get_connection_iface (nm_manager_get (), - connection, - NULL, NULL); + gs_free_error GError *local = NULL; + gs_free char *conn_iface = NULL; + NMDeviceClass *klass; + const char *const *patterns; + NMSettingMatch *s_match; + guint num_patterns; + + klass = NM_DEVICE_GET_CLASS (self); + if (klass->connection_type_check_compatible) { + if (!_nm_connection_check_main_setting (connection, + klass->connection_type_check_compatible, + error)) + return FALSE; + } else if (klass->check_connection_compatible == check_connection_compatible) { + /* the device class does not implement check_connection_compatible nor set + * connection_type_check_compatible. That means, it is by default not compatible + * with any connection type. */ + nm_utils_error_set_literal (error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, + "device does not support any connections"); + return FALSE; + } + + conn_iface = nm_manager_get_connection_iface (nm_manager_get (), + connection, + NULL, + &local); /* We always need a interface name for virtual devices, but for * physical ones a connection without interface name is fine for * any device. */ - if (!conn_iface) - return !nm_connection_is_virtual (connection); - - if (strcmp (conn_iface, device_iface) != 0) + if (!conn_iface) { + if (nm_connection_is_virtual (connection)) { + nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "cannot get interface name due to %s", local->message); + return FALSE; + } + } else if (!nm_streq0 (conn_iface, device_iface)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "mismatching interface name"); return FALSE; + } + + s_match = (NMSettingMatch *) nm_connection_get_setting (connection, + NM_TYPE_SETTING_MATCH); + if (s_match) { + patterns = nm_setting_match_get_interface_names (s_match, &num_patterns); + if (!nm_wildcard_match_check (device_iface, patterns, num_patterns)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device does not satisfy match.interface-name property"); + return FALSE; + } + } return TRUE; } @@ -5407,6 +5692,11 @@ check_connection_compatible (NMDevice *self, NMConnection *connection) * nm_device_check_connection_compatible: * @self: an #NMDevice * @connection: an #NMConnection + * @error: optional reason why it is incompatible. Note that the + * error code is set to %NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, + * if the profile is fundamentally incompatible with the device + * (most commonly, because the device-type does not support the + * connection-type). * * Checks if @connection could potentially be activated on @self. * This means only that @self has the proper capabilities, and that @@ -5419,12 +5709,12 @@ check_connection_compatible (NMDevice *self, NMConnection *connection) * @self. */ gboolean -nm_device_check_connection_compatible (NMDevice *self, NMConnection *connection) +nm_device_check_connection_compatible (NMDevice *self, NMConnection *connection, GError **error) { g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); - return NM_DEVICE_GET_CLASS (self)->check_connection_compatible (self, connection); + return NM_DEVICE_GET_CLASS (self)->check_connection_compatible (self, connection, error); } gboolean @@ -5440,7 +5730,7 @@ nm_device_check_slave_connection_compatible (NMDevice *self, NMConnection *slave return FALSE; /* All masters should have connection type set */ - connection_type = NM_DEVICE_GET_CLASS (self)->connection_type; + connection_type = NM_DEVICE_GET_CLASS (self)->connection_type_supported; g_return_val_if_fail (connection_type, FALSE); s_con = nm_connection_get_setting_connection (slave); @@ -5811,24 +6101,151 @@ lldp_rx_enabled (NMDevice *self) lldp = nm_setting_connection_get_lldp (s_con); if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) { - gs_free char *value = NULL; - - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "connection.lldp", - self); - lldp = _nm_utils_ascii_str_to_int64 (value, 10, - NM_SETTING_CONNECTION_LLDP_DEFAULT, - NM_SETTING_CONNECTION_LLDP_ENABLE_RX, - NM_SETTING_CONNECTION_LLDP_DEFAULT); + lldp = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "connection.lldp", + self, + NM_SETTING_CONNECTION_LLDP_DEFAULT, + NM_SETTING_CONNECTION_LLDP_ENABLE_RX, + NM_SETTING_CONNECTION_LLDP_DEFAULT); if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) lldp = NM_SETTING_CONNECTION_LLDP_DISABLE; } return lldp == NM_SETTING_CONNECTION_LLDP_ENABLE_RX; } +static NMPlatformVF * +sriov_vf_config_to_platform (NMDevice *self, + NMSriovVF *vf, + GError **error) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gs_free NMPlatformVF *plat_vf = NULL; + const guint *vlan_ids; + GVariant *variant; + guint i, num_vlans; + gsize length; + + g_return_val_if_fail (!error || !*error, FALSE); + + vlan_ids = nm_sriov_vf_get_vlan_ids (vf, &num_vlans); + plat_vf = g_malloc0 ( sizeof (NMPlatformVF) + + sizeof (NMPlatformVFVlan) * num_vlans); + + plat_vf->index = nm_sriov_vf_get_index (vf); + + variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK); + if (variant) + plat_vf->spoofchk = g_variant_get_boolean (variant); + else + plat_vf->spoofchk = -1; + + variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_TRUST); + if (variant) + plat_vf->trust = g_variant_get_boolean (variant); + else + plat_vf->trust = -1; + + variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_MAC); + if (variant) { + if (!_nm_utils_hwaddr_aton (g_variant_get_string (variant, NULL), + plat_vf->mac.data, + sizeof (plat_vf->mac.data), + &length)) { + g_set_error (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "invalid MAC %s", + g_variant_get_string (variant, NULL)); + return NULL; + } + if (length != priv->hw_addr_len) { + g_set_error (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "wrong MAC length %" G_GSIZE_FORMAT ", should be %u", + length, priv->hw_addr_len); + return NULL; + } + plat_vf->mac.len = length; + } + + variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_MIN_TX_RATE); + if (variant) + plat_vf->min_tx_rate = g_variant_get_uint32 (variant); + + variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_MAX_TX_RATE); + if (variant) + plat_vf->max_tx_rate = g_variant_get_uint32 (variant); + + plat_vf->num_vlans = num_vlans; + plat_vf->vlans = (NMPlatformVFVlan *) (&plat_vf[1]); + for (i = 0; i < num_vlans; i++) { + plat_vf->vlans[i].id = vlan_ids[i]; + plat_vf->vlans[i].qos = nm_sriov_vf_get_vlan_qos (vf, vlan_ids[i]); + plat_vf->vlans[i].proto_ad = nm_sriov_vf_get_vlan_protocol (vf, vlan_ids[i]) == NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD; + } + + return g_steal_pointer (&plat_vf); +} + static NMActStageReturn act_stage1_prepare (NMDevice *self, NMDeviceStateReason *out_failure_reason) { + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMSettingSriov *s_sriov; + guint i, num; + + if ( priv->ifindex > 0 + && nm_device_has_capability (self, NM_DEVICE_CAP_SRIOV) + && (s_sriov = (NMSettingSriov *) nm_device_get_applied_setting (self, NM_TYPE_SETTING_SRIOV))) { + nm_auto_freev NMPlatformVF **plat_vfs = NULL; + gs_free_error GError *error = NULL; + NMSriovVF *vf; + int autoprobe; + + autoprobe = nm_setting_sriov_get_autoprobe_drivers (s_sriov); + if (autoprobe == NM_TERNARY_DEFAULT) { + autoprobe = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "sriov.autoprobe-drivers", + self, + NM_TERNARY_FALSE, + NM_TERNARY_TRUE, + NM_TERNARY_TRUE); + } + + num = nm_setting_sriov_get_num_vfs (s_sriov); + plat_vfs = g_new0 (NMPlatformVF *, num + 1); + for (i = 0; i < num; i++) { + vf = nm_setting_sriov_get_vf (s_sriov, i); + plat_vfs[i] = sriov_vf_config_to_platform (self, vf, &error); + if (!plat_vfs[i]) { + _LOGE (LOGD_DEVICE, + "failed to apply SR-IOV VF '%s': %s", + nm_utils_sriov_vf_to_str (vf, FALSE, NULL), + error->message); + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; + } + } + + if (!nm_platform_link_set_sriov_params (nm_device_get_platform (self), + priv->ifindex, + nm_setting_sriov_get_total_vfs (s_sriov), + autoprobe)) { + _LOGE (LOGD_DEVICE, "failed to apply SR-IOV parameters"); + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; + } + + if (!nm_platform_link_set_sriov_vfs (nm_device_get_platform (self), + priv->ifindex, + (const NMPlatformVF *const *) plat_vfs)) { + _LOGE (LOGD_DEVICE, "failed to apply SR-IOV VFs"); + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; + } + } + return NM_ACT_STAGE_RETURN_SUCCESS; } @@ -6032,6 +6449,8 @@ activate_stage2_device_config (NMDevice *self) if (!nm_device_sys_iface_state_is_external_or_assume (self)) { NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; + _ethtool_state_set (self); + if (!tc_commit (self)) { _LOGW (LOGD_IP6, "failed applying traffic control rules"); nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED); @@ -6146,27 +6565,22 @@ get_ipv4_dad_timeout (NMDevice *self) { NMConnection *connection; NMSettingIPConfig *s_ip4 = NULL; - gs_free char *value = NULL; - gint ret = 0; + int timeout = -1; connection = nm_device_get_applied_connection (self); if (connection) s_ip4 = nm_connection_get_setting_ip4_config (connection); + if (s_ip4) + timeout = nm_setting_ip_config_get_dad_timeout (s_ip4); + if (timeout >= 0) + return timeout; - if (s_ip4) { - ret = nm_setting_ip_config_get_dad_timeout (s_ip4); - - if (ret < 0) { - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "ipv4.dad-timeout", self); - ret = _nm_utils_ascii_str_to_int64 (value, 10, -1, - NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, - -1); - ret = ret < 0 ? 0 : ret; - } - } - - return ret; + return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "ipv4.dad-timeout", + self, + 0, + NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, + 0); } static void @@ -6186,15 +6600,30 @@ acd_data_destroy (gpointer ptr, GClosure *closure) static void ipv4_manual_method_apply (NMDevice *self, NMIP4Config **configs, gboolean success) { + NMConnection *connection; + const char *method; NMIP4Config *empty; - if (success) { + connection = nm_device_get_applied_connection (self); + nm_assert (connection); + method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); + nm_assert (NM_IN_STRSET (method, + NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + NM_SETTING_IP4_CONFIG_METHOD_AUTO)); + + if (!success) { + nm_device_ip_method_failed (self, AF_INET, + NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE); + return; + } + + if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { empty = _ip4_config_new (self); nm_device_activate_schedule_ip4_config_result (self, empty); g_object_unref (empty); } else { - nm_device_ip_method_failed (self, AF_INET, - NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE); + if (NM_DEVICE_GET_PRIVATE (self)->ip4_state != IP_DONE) + ip_config_merge_and_apply (self, AF_INET, TRUE); } } @@ -6532,6 +6961,7 @@ ensure_con_ip_config (NMDevice *self, int addr_family) nm_ip4_config_merge_setting (NM_IP4_CONFIG (con_ip_config), nm_connection_get_setting_ip4_config (connection), _get_mdns (self), + _get_llmnr (self), nm_device_get_route_table (self, addr_family, TRUE), nm_device_get_route_metric (self, addr_family)); } else { @@ -6560,6 +6990,7 @@ dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) nm_clear_g_source (&priv->dhcp4.grace_id); g_clear_pointer (&priv->dhcp4.pac_url, g_free); + g_clear_pointer (&priv->dhcp4.root_path, g_free); if (priv->dhcp4.client) { /* Stop any ongoing DHCP transaction on this device */ @@ -6933,6 +7364,9 @@ dhcp4_state_changed (NMDhcpClient *client, priv->dhcp4.pac_url = g_strdup (g_hash_table_lookup (options, "wpad")); nm_device_set_proxy_config (self, priv->dhcp4.pac_url); + g_free (priv->dhcp4.root_path); + priv->dhcp4.root_path = g_strdup (g_hash_table_lookup (options, "root_path")); + nm_dhcp4_config_set_options (priv->dhcp4.config, options); _notify (self, PROP_DHCP4_CONFIG); @@ -6944,6 +7378,7 @@ dhcp4_state_changed (NMDhcpClient *client, nm_ip4_config_merge_setting (manual, nm_connection_get_setting_ip4_config (connection), NM_SETTING_CONNECTION_MDNS_DEFAULT, + NM_SETTING_CONNECTION_LLMNR_DEFAULT, nm_device_get_route_table (self, AF_INET, TRUE), nm_device_get_route_metric (self, AF_INET)); @@ -6998,19 +7433,14 @@ get_dhcp_timeout (NMDevice *self, int addr_family) if (timeout) return timeout; - { - gs_free char *value = NULL; - - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - addr_family == AF_INET - ? "ipv4.dhcp-timeout" - : "ipv6.dhcp-timeout", - self); - timeout = _nm_utils_ascii_str_to_int64 (value, 10, - 0, G_MAXINT32, 0); - if (timeout) - return timeout; - } + timeout = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + addr_family == AF_INET + ? "ipv4.dhcp-timeout" + : "ipv6.dhcp-timeout", + self, + 0, G_MAXINT32, 0); + if (timeout) + return timeout; klass = NM_DEVICE_GET_CLASS (self); if (klass->get_dhcp_timeout) @@ -7170,6 +7600,7 @@ dhcp4_start (NMDevice *self) gs_unref_bytes GBytes *hwaddr = NULL; gs_unref_bytes GBytes *client_id = NULL; NMConnection *connection; + GError *error = NULL; connection = nm_device_get_applied_connection (self); g_return_val_if_fail (connection, FALSE); @@ -7200,10 +7631,14 @@ dhcp4_start (NMDevice *self) client_id, get_dhcp_timeout (self, AF_INET), priv->dhcp_anycast_address, - NULL); + NULL, + &error); - if (!priv->dhcp4.client) + if (!priv->dhcp4.client) { + _LOGW (LOGD_DHCP4, "failure to start DHCP: %s", error->message); + g_clear_error (&error); return NM_ACT_STAGE_RETURN_FAILURE; + } priv->dhcp4.state_sigid = g_signal_connect (priv->dhcp4.client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, @@ -7444,30 +7879,45 @@ act_stage3_ip4_config_start (NMDevice *self, method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); - /* Start IPv4 addressing based on the method requested */ - if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0) { - ret = dhcp4_start (self); - if (ret == NM_ACT_STAGE_RETURN_FAILURE) - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_DHCP_START_FAILED); - } else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL) == 0) { - ret = ipv4ll_start (self); - if (ret == NM_ACT_STAGE_RETURN_FAILURE) - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED); - } else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL) == 0) { + if (NM_IN_STRSET (method, + NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { + NMSettingIPConfig *s_ip4; NMIP4Config **configs, *config; + guint num_addresses; - config = _ip4_config_new (self); - nm_ip4_config_merge_setting (config, - nm_connection_get_setting_ip4_config (connection), - NM_SETTING_CONNECTION_MDNS_DEFAULT, - nm_device_get_route_table (self, AF_INET, TRUE), - nm_device_get_route_metric (self, AF_INET)); + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_return_val_if_fail (s_ip4, NM_ACT_STAGE_RETURN_FAILURE); + num_addresses = nm_setting_ip_config_get_num_addresses (s_ip4); + + if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + ret = dhcp4_start (self); + if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_DHCP_START_FAILED); + return ret; + } + } else { + g_return_val_if_fail (num_addresses != 0, NM_ACT_STAGE_RETURN_FAILURE); + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } - configs = g_new0 (NMIP4Config *, 2); - configs[0] = config; - ipv4_dad_start (self, configs, ipv4_manual_method_apply); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) { + if (num_addresses) { + config = _ip4_config_new (self); + nm_ip4_config_merge_setting (config, + nm_connection_get_setting_ip4_config (connection), + NM_SETTING_CONNECTION_MDNS_DEFAULT, + NM_SETTING_CONNECTION_LLMNR_DEFAULT, + nm_device_get_route_table (self, AF_INET, TRUE), + nm_device_get_route_metric (self, AF_INET)); + configs = g_new0 (NMIP4Config *, 2); + configs[0] = config; + ipv4_dad_start (self, configs, ipv4_manual_method_apply); + } + } else if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { + ret = ipv4ll_start (self); + if (ret == NM_ACT_STAGE_RETURN_FAILURE) + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED); + } else if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { if (out_config) { *out_config = shared4_new_config (self, connection); if (*out_config) { @@ -7479,7 +7929,7 @@ act_stage3_ip4_config_start (NMDevice *self, } } else g_return_val_if_reached (NM_ACT_STAGE_RETURN_FAILURE); - } else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0) + } else if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) ret = NM_ACT_STAGE_RETURN_SUCCESS; else _LOGW (LOGD_IP4, "unhandled IPv4 config method '%s'; will fail", method); @@ -7744,35 +8194,35 @@ static GBytes * generate_duid_llt (const guint8 *hwaddr /* ETH_ALEN bytes */, gint64 time) { - GByteArray *duid_arr; + guint8 *arr; const guint16 duid_type = htons (1); const guint16 hw_type = htons (ARPHRD_ETHER); const guint32 duid_time = htonl (NM_MAX (0, time - EPOCH_DATETIME_200001010000)); - duid_arr = g_byte_array_sized_new (2 + 4 + 2 + ETH_ALEN); + arr = g_new (guint8, 2 + 2 + 4 + ETH_ALEN); - g_byte_array_append (duid_arr, (const guint8 *) &duid_type, 2); - g_byte_array_append (duid_arr, (const guint8 *) &hw_type, 2); - g_byte_array_append (duid_arr, (const guint8 *) &duid_time, 4); - g_byte_array_append (duid_arr, hwaddr, ETH_ALEN); + memcpy (&arr[0], &duid_type, 2); + memcpy (&arr[2], &hw_type, 2); + memcpy (&arr[4], &duid_time, 4); + memcpy (&arr[8], hwaddr, ETH_ALEN); - return g_byte_array_free_to_bytes (duid_arr); + return g_bytes_new_take (arr, 2 + 2 + 4 + ETH_ALEN); } static GBytes * generate_duid_ll (const guint8 *hwaddr /* ETH_ALEN bytes */) { - GByteArray *duid_arr; + guint8 *arr; const guint16 duid_type = htons (3); const guint16 hw_type = htons (ARPHRD_ETHER); - duid_arr = g_byte_array_sized_new (2 + 2 + ETH_ALEN); + arr = g_new (guint8, 2 + 2 + ETH_ALEN); - g_byte_array_append (duid_arr, (const guint8 *) &duid_type, 2); - g_byte_array_append (duid_arr, (const guint8 *) &hw_type, 2); - g_byte_array_append (duid_arr, hwaddr, ETH_ALEN); + memcpy (&arr[0], &duid_type, 2); + memcpy (&arr[2], &hw_type, 2); + memcpy (&arr[4], hwaddr, ETH_ALEN); - return g_byte_array_free_to_bytes (duid_arr); + return g_bytes_new_take (arr, 2 + 2 + ETH_ALEN); } static GBytes * @@ -7990,6 +8440,7 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) gs_unref_bytes GBytes *hwaddr = NULL; gs_unref_bytes GBytes *duid = NULL; gboolean enforce_duid = FALSE; + GError *error = NULL; const NMPlatformIP6Address *ll_addr = NULL; @@ -8029,23 +8480,29 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) priv->dhcp_anycast_address, (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)), - priv->dhcp6.needed_prefixes); - - if (priv->dhcp6.client) { - priv->dhcp6.state_sigid = g_signal_connect (priv->dhcp6.client, - NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, - G_CALLBACK (dhcp6_state_changed), - self); - priv->dhcp6.prefix_sigid = g_signal_connect (priv->dhcp6.client, - NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED, - G_CALLBACK (dhcp6_prefix_delegated), - self); + priv->dhcp6.needed_prefixes, + &error); + if (!priv->dhcp6.client) { + _LOGW (LOGD_DHCP6, "failure to start DHCPv6: %s", error->message); + g_clear_error (&error); + if (nm_device_sys_iface_state_is_external_or_assume (self)) + priv->dhcp6.was_active = TRUE; + return FALSE; } + priv->dhcp6.state_sigid = g_signal_connect (priv->dhcp6.client, + NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, + G_CALLBACK (dhcp6_state_changed), + self); + priv->dhcp6.prefix_sigid = g_signal_connect (priv->dhcp6.client, + NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED, + G_CALLBACK (dhcp6_prefix_delegated), + self); + if (nm_device_sys_iface_state_is_external_or_assume (self)) priv->dhcp6.was_active = TRUE; - return !!priv->dhcp6.client; + return TRUE; } static gboolean @@ -8368,10 +8825,10 @@ gint64 nm_device_get_configured_mtu_from_connection_default (NMDevice *self, const char *property_name) { - gs_free char *str = NULL; - - str = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, property_name, self); - return _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXUINT32, -1); + return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + property_name, + self, + 0, G_MAXUINT32, -1); } guint32 @@ -9024,7 +9481,8 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable) _LOGD (LOGD_IP6, "will %s userland IPv6LL", detail); plerr = nm_platform_link_set_user_ipv6ll_enabled (nm_device_get_platform (self), ifindex, enable); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { - _NMLOG (plerr == NM_PLATFORM_ERROR_NOT_FOUND ? LOGL_DEBUG : LOGL_WARN, + _NMLOG (( plerr == NM_PLATFORM_ERROR_NOT_FOUND + || plerr == NM_PLATFORM_ERROR_OPNOTSUPP) ? LOGL_DEBUG : LOGL_WARN, LOGD_IP6, "failed to %s userspace IPv6LL address handling (%s)", detail, @@ -9067,7 +9525,6 @@ static NMSettingIP6ConfigPrivacy _ip6_privacy_get (NMDevice *self) { NMSettingIP6ConfigPrivacy ip6_privacy; - gs_free char *value = NULL; NMConnection *connection; g_return_val_if_fail (self, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); @@ -9086,14 +9543,13 @@ _ip6_privacy_get (NMDevice *self) } } - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "ipv6.ip6-privacy", self); - /* 2.) use the default value from the configuration. */ - ip6_privacy = _nm_utils_ascii_str_to_int64 (value, 10, - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, - NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); + ip6_privacy = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "ipv6.ip6-privacy", + self, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, + NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, + NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) return ip6_privacy; @@ -10323,6 +10779,7 @@ nm_device_reactivate_ip4_config (NMDevice *self, nm_ip4_config_merge_setting (priv->con_ip_config_4, s_ip4_new, _get_mdns (self), + _get_llmnr (self), nm_device_get_route_table (self, AF_INET, TRUE), nm_device_get_route_metric (self, AF_INET)); @@ -10362,8 +10819,10 @@ nm_device_reactivate_ip4_config (NMDevice *self, nm_ip4_config_update_routes_metric ((NMIP4Config *) priv->wwan_ip_config_4.orig, nm_device_get_route_metric (self, AF_INET)); } - if (priv->dhcp4.client) - nm_dhcp_client_set_route_metric (priv->dhcp4.client, metric_new); + if (priv->dhcp4.client) { + nm_dhcp_client_set_route_metric (priv->dhcp4.client, + nm_device_get_route_metric (self, AF_INET)); + } } } @@ -10433,8 +10892,10 @@ nm_device_reactivate_ip6_config (NMDevice *self, nm_ip6_config_update_routes_metric ((NMIP6Config *) priv->wwan_ip_config_6.orig, nm_device_get_route_metric (self, AF_INET6)); } - if (priv->dhcp6.client) - nm_dhcp_client_set_route_metric (priv->dhcp6.client, metric_new); + if (priv->dhcp6.client) { + nm_dhcp_client_set_route_metric (priv->dhcp6.client, + nm_device_get_route_metric (self, AF_INET6)); + } } } @@ -10494,7 +10955,9 @@ can_reapply_change (NMDevice *self, const char *setting_name, NM_SETTING_CONNECTION_AUTOCONNECT, NM_SETTING_CONNECTION_ZONE, NM_SETTING_CONNECTION_METERED, - NM_SETTING_CONNECTION_LLDP); + NM_SETTING_CONNECTION_LLDP, + NM_SETTING_CONNECTION_MDNS, + NM_SETTING_CONNECTION_LLMNR); } else if (NM_IN_STRSET (setting_name, NM_SETTING_PROXY_SETTING_NAME)) { return TRUE; @@ -10738,7 +11201,7 @@ reapply_cb (NMDevice *self, nm_device_sys_iface_state_set (self, NM_DEVICE_SYS_IFACE_STATE_MANAGED); if (!check_and_reapply_connection (self, - connection ? : (NMConnection *) nm_device_get_settings_connection (self), + connection ?: nm_device_get_settings_connection_get_connection (self), version_id, &audit_args, &local)) { @@ -11225,7 +11688,7 @@ _carrier_wait_check_act_request_must_queue (NMDevice *self, NMActRequest *req) if (!connection_requires_carrier (connection)) return FALSE; - if (!nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL, NULL)) { + if (!nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL, NULL, NULL)) { /* We passed all @flags we have, and no @specific_object. * This equals maximal availability, if a connection is not available * in this case, it is not waiting for carrier. @@ -11236,7 +11699,9 @@ _carrier_wait_check_act_request_must_queue (NMDevice *self, NMActRequest *req) return FALSE; } - if (nm_device_check_connection_available (self, connection, NM_DEVICE_CHECK_CON_AVAILABLE_ALL & ~_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER, NULL)) { + if (nm_device_check_connection_available (self, connection, + NM_DEVICE_CHECK_CON_AVAILABLE_ALL & ~_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER, + NULL, NULL)) { /* The connection was available with flags ALL, and it is still available * if we pretend not to wait for carrier. That means that the * connection is available now, and does not wait for carrier. @@ -11524,7 +11989,8 @@ nm_device_set_ip_config (NMDevice *self, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED) && nm_active_connection_get_activation_type (NM_ACTIVE_CONNECTION (priv->act_request.obj)) == NM_ACTIVATION_TYPE_EXTERNAL) { g_object_freeze_notify (G_OBJECT (settings_connection)); - nm_connection_add_setting (NM_CONNECTION (settings_connection), + /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */ + nm_connection_add_setting (nm_settings_connection_get_connection (settings_connection), IS_IPv4 ? nm_ip4_config_create_setting (priv->ip_config_4) : nm_ip6_config_create_setting (priv->ip_config_6)); @@ -11733,11 +12199,11 @@ spawn_ping (NMDevice *self) gboolean ret; args[6] = str_timeout = g_strdup_printf ("%u", priv->gw_ping.deadline); - tmp_str = g_strjoinv (" ", (gchar **) args); + tmp_str = g_strjoinv (" ", (char **) args); _LOGD (priv->gw_ping.log_domain, "ping: running '%s'", tmp_str); ret = g_spawn_async ("/", - (gchar **) args, + (char **) args, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, @@ -11773,7 +12239,7 @@ respawn_ping_cb (gpointer user_data) } static void -ip_check_ping_watch_cb (GPid pid, gint status, gpointer user_data) +ip_check_ping_watch_cb (GPid pid, int status, gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -12098,7 +12564,9 @@ nm_device_get_firmware_missing (NMDevice *self) } static void -intersect_ext_config (NMDevice *self, AppliedConfig *config) +intersect_ext_config (NMDevice *self, + AppliedConfig *config, + gboolean intersect_routes) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMIPConfig *ext; @@ -12115,10 +12583,11 @@ intersect_ext_config (NMDevice *self, AppliedConfig *config) : (NMIPConfig *) priv->ext_ip_config_6; if (config->current) - nm_ip_config_intersect (config->current, ext, penalty); + nm_ip_config_intersect (config->current, ext, intersect_routes, penalty); else { config->current = nm_ip_config_intersect_alloc (config->orig, ext, + intersect_routes, penalty); } } @@ -12129,6 +12598,7 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_config NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); int ifindex; GSList *iter; + gboolean is_up; nm_assert_addr_family (addr_family); @@ -12136,6 +12606,8 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_config if (!ifindex) return FALSE; + is_up = nm_platform_link_is_up (nm_device_get_platform (self), ifindex); + if (addr_family == AF_INET) { g_clear_object (&priv->ext_ip_config_4); @@ -12150,14 +12622,15 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_config * by the user. */ if (priv->con_ip_config_4) { nm_ip4_config_intersect (priv->con_ip_config_4, priv->ext_ip_config_4, + is_up, default_route_metric_penalty_get (self, AF_INET)); } - intersect_ext_config (self, &priv->dev_ip4_config); - intersect_ext_config (self, &priv->wwan_ip_config_4); + intersect_ext_config (self, &priv->dev_ip4_config, is_up); + intersect_ext_config (self, &priv->wwan_ip_config_4, is_up); for (iter = priv->vpn_configs_4; iter; iter = iter->next) - nm_ip4_config_intersect (iter->data, priv->ext_ip_config_4, 0); + nm_ip4_config_intersect (iter->data, priv->ext_ip_config_4, is_up, 0); } /* Remove parts from ext_ip_config_4 to only contain the information that @@ -12201,15 +12674,16 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_config * by the user. */ if (priv->con_ip_config_6) { nm_ip6_config_intersect (priv->con_ip_config_6, priv->ext_ip_config_6, + is_up, default_route_metric_penalty_get (self, AF_INET6)); } - intersect_ext_config (self, &priv->ac_ip6_config); - intersect_ext_config (self, &priv->dhcp6.ip6_config); - intersect_ext_config (self, &priv->wwan_ip_config_6); + intersect_ext_config (self, &priv->ac_ip6_config, is_up); + intersect_ext_config (self, &priv->dhcp6.ip6_config, is_up); + intersect_ext_config (self, &priv->wwan_ip_config_6, is_up); for (iter = priv->vpn_configs_6; iter; iter = iter->next) - nm_ip6_config_intersect (iter->data, priv->ext_ip_config_6, 0); + nm_ip6_config_intersect (iter->data, priv->ext_ip_config_6, is_up, 0); if ( priv->ipv6ll_has && !nm_ip6_config_lookup_address (priv->ext_ip_config_6, &priv->ipv6ll_addr)) @@ -12469,7 +12943,7 @@ NM_UTILS_FLAGS2STR_DEFINE (nm_unmanaged_flags2str, NMUnmanagedFlags, NM_UTILS_FLAGS2STR (NM_UNMANAGED_SLEEPING, "sleeping"), NM_UTILS_FLAGS2STR (NM_UNMANAGED_QUITTING, "quitting"), NM_UTILS_FLAGS2STR (NM_UNMANAGED_PARENT, "parent"), - NM_UTILS_FLAGS2STR (NM_UNMANAGED_LOOPBACK, "loopback"), + NM_UTILS_FLAGS2STR (NM_UNMANAGED_BY_TYPE, "by-type"), NM_UTILS_FLAGS2STR (NM_UNMANAGED_PLATFORM_INIT, "platform-init"), NM_UTILS_FLAGS2STR (NM_UNMANAGED_USER_EXPLICIT, "user-explicit"), NM_UTILS_FLAGS2STR (NM_UNMANAGED_BY_DEFAULT, "by-default"), @@ -12983,7 +13457,7 @@ nm_device_reapply_settings_immediately (NMDevice *self) NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY)) return; - s_con_settings = nm_connection_get_setting_connection ((NMConnection *) settings_connection); + s_con_settings = nm_connection_get_setting_connection (nm_settings_connection_get_connection (settings_connection)); s_con_applied = nm_connection_get_setting_connection (applied_connection); if (g_strcmp0 ((zone = nm_setting_connection_get_zone (s_con_settings)), @@ -13093,42 +13567,102 @@ nm_device_update_metered (NMDevice *self) } } +static NMDeviceCheckDevAvailableFlags +_device_check_dev_available_flags_from_con (NMDeviceCheckConAvailableFlags con_flags) +{ + NMDeviceCheckDevAvailableFlags dev_flags; + + dev_flags = NM_DEVICE_CHECK_DEV_AVAILABLE_NONE; + + if (NM_FLAGS_HAS (con_flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)) + dev_flags |= _NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER; + + return dev_flags; +} + static gboolean _nm_device_check_connection_available (NMDevice *self, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMDeviceState state; + GError *local = NULL; /* an unrealized software device is always available, hardware devices never. */ if (!nm_device_is_real (self)) { - if (nm_device_is_software (self)) - return nm_device_check_connection_compatible (self, connection); + if (nm_device_is_software (self)) { + if (!nm_device_check_connection_compatible (self, connection, + error ? &local : NULL)) { + if (error) { + g_return_val_if_fail (local, FALSE); + nm_utils_error_set (error, + local->domain == NM_UTILS_ERROR + ? local->code + : NM_UTILS_ERROR_UNKNOWN, + "profile is not compatible with software device (%s)", + local->message); + g_error_free (local); + } + return FALSE; + } + return TRUE; + } + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, + "hardware device is not realized"); return FALSE; } state = nm_device_get_state (self); - if (state < NM_DEVICE_STATE_UNMANAGED) - return FALSE; - if ( state < NM_DEVICE_STATE_UNAVAILABLE - && ( ( !NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST) - && !nm_device_get_managed (self, FALSE)) - || ( NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST) - && !nm_device_get_managed (self, TRUE)))) + if (state < NM_DEVICE_STATE_UNMANAGED) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, + "device is in unknown state"); return FALSE; + } + if (state < NM_DEVICE_STATE_UNAVAILABLE) { + if (!nm_device_get_managed (self, TRUE)) { + if (!nm_device_get_managed (self, FALSE)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, + "device is strictly unmanaged"); + return FALSE; + } + if (!NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_OVERRULE_UNMANAGED)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, + "device is currently unmanaged"); + return FALSE; + } + } + } if ( state < NM_DEVICE_STATE_DISCONNECTED - && !nm_device_is_software (self) - && ( ( !NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST) - && !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) - || ( NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST) - && !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_FOR_USER_REQUEST)))) - return FALSE; + && !nm_device_is_software (self)) { + if (!nm_device_is_available (self, _device_check_dev_available_flags_from_con (flags))) { + if (NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device is not available"); + } else { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device is not available for internal request"); + } + return FALSE; + } + } - if (!nm_device_check_connection_compatible (self, connection)) + if (!nm_device_check_connection_compatible (self, connection, + error ? &local : NULL)) { + if (error) { + nm_utils_error_set (error, + local->domain == NM_UTILS_ERROR + ? local->code + : NM_UTILS_ERROR_UNKNOWN, + "profile is not compatible with device (%s)", + local->message); + g_error_free (local); + } return FALSE; + } - return NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, flags, specific_object); + return NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, flags, specific_object, error); } /** @@ -13141,6 +13675,7 @@ _nm_device_check_connection_available (NMDevice *self, * @specific_object: a device type dependent argument to further * filter the result. Passing a non %NULL specific object can only reduce * the availability of a connection. + * @error: optionally give reason why not available. * * Check if @connection is available to be activated on @self. * @@ -13150,11 +13685,12 @@ gboolean nm_device_check_connection_available (NMDevice *self, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { gboolean available; - available = _nm_device_check_connection_available (self, connection, flags, specific_object); + available = _nm_device_check_connection_available (self, connection, flags, specific_object, error); #if NM_MORE_ASSERTS >= 2 { @@ -13164,7 +13700,7 @@ nm_device_check_connection_available (NMDevice *self, gboolean available_all[NM_DEVICE_CHECK_CON_AVAILABLE_ALL + 1] = { FALSE }; for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++) - available_all[i] = _nm_device_check_connection_available (self, connection, i, specific_object); + available_all[i] = _nm_device_check_connection_available (self, connection, i, specific_object, NULL); for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++) { for (j = 1; j <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; j <<= 1) { @@ -13191,22 +13727,23 @@ available_connections_del_all (NMDevice *self) } static gboolean -available_connections_add (NMDevice *self, NMConnection *connection) +available_connections_add (NMDevice *self, NMSettingsConnection *sett_conn) { - return g_hash_table_add (self->_priv->available_connections, g_object_ref (connection)); + return g_hash_table_add (self->_priv->available_connections, g_object_ref (sett_conn)); } static gboolean -available_connections_del (NMDevice *self, NMConnection *connection) +available_connections_del (NMDevice *self, NMSettingsConnection *sett_conn) { - return g_hash_table_remove (self->_priv->available_connections, connection); + return g_hash_table_remove (self->_priv->available_connections, sett_conn); } static gboolean check_connection_available (NMDevice *self, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); @@ -13232,6 +13769,8 @@ check_connection_available (NMDevice *self, if (nm_device_is_master (self)) return TRUE; + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has no carrier"); return FALSE; } @@ -13242,7 +13781,7 @@ nm_device_recheck_available_connections (NMDevice *self) NMSettingsConnection *const*connections; gboolean changed = FALSE; GHashTableIter h_iter; - NMConnection *connection; + NMSettingsConnection *sett_conn; guint i; gs_unref_hashtable GHashTable *prune_list = NULL; @@ -13253,29 +13792,30 @@ nm_device_recheck_available_connections (NMDevice *self) if (g_hash_table_size (priv->available_connections) > 0) { prune_list = g_hash_table_new (nm_direct_hash, NULL); g_hash_table_iter_init (&h_iter, priv->available_connections); - while (g_hash_table_iter_next (&h_iter, (gpointer *) &connection, NULL)) - g_hash_table_add (prune_list, connection); + while (g_hash_table_iter_next (&h_iter, (gpointer *) &sett_conn, NULL)) + g_hash_table_add (prune_list, sett_conn); } connections = nm_settings_get_connections (priv->settings, NULL); for (i = 0; connections[i]; i++) { - connection = (NMConnection *) connections[i]; + sett_conn = connections[i]; if (nm_device_check_connection_available (self, - connection, + nm_settings_connection_get_connection (sett_conn), NM_DEVICE_CHECK_CON_AVAILABLE_NONE, + NULL, NULL)) { - if (available_connections_add (self, connection)) + if (available_connections_add (self, sett_conn)) changed = TRUE; if (prune_list) - g_hash_table_remove (prune_list, connection); + g_hash_table_remove (prune_list, sett_conn); } } if (prune_list) { g_hash_table_iter_init (&h_iter, prune_list); - while (g_hash_table_iter_next (&h_iter, (gpointer *) &connection, NULL)) { - if (available_connections_del (self, connection)) + while (g_hash_table_iter_next (&h_iter, (gpointer *) &sett_conn, NULL)) { + if (available_connections_del (self, sett_conn)) changed = TRUE; } } @@ -13302,7 +13842,7 @@ nm_device_get_best_connection (NMDevice *self, GError **error) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMSettingsConnection *connection = NULL; + NMSettingsConnection *sett_conn = NULL; NMSettingsConnection *candidate; guint64 best_timestamp = 0; GHashTableIter iter; @@ -13316,42 +13856,44 @@ nm_device_get_best_connection (NMDevice *self, */ if ( specific_object /* << Optimization: we know that the connection is available without @specific_object. */ && !nm_device_check_connection_available (self, - NM_CONNECTION (candidate), + nm_settings_connection_get_connection (candidate), _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, - specific_object)) + specific_object, + NULL)) continue; nm_settings_connection_get_timestamp (candidate, &candidate_timestamp); - if (!connection || (candidate_timestamp > best_timestamp)) { - connection = candidate; + if (!sett_conn || (candidate_timestamp > best_timestamp)) { + sett_conn = candidate; best_timestamp = candidate_timestamp; } } - if (!connection) { + if (!sett_conn) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, "The device '%s' has no connections available for activation.", nm_device_get_iface (self)); } - return connection; + return sett_conn; } static void -cp_connection_added_or_updated (NMDevice *self, NMConnection *connection) +cp_connection_added_or_updated (NMDevice *self, NMSettingsConnection *sett_conn) { gboolean changed; g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (sett_conn)); if (nm_device_check_connection_available (self, - connection, + nm_settings_connection_get_connection (sett_conn), _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, + NULL, NULL)) - changed = available_connections_add (self, connection); + changed = available_connections_add (self, sett_conn); else - changed = available_connections_del (self, connection); + changed = available_connections_del (self, sett_conn); if (changed) { _notify (self, PROP_AVAILABLE_CONNECTIONS); @@ -13360,25 +13902,25 @@ cp_connection_added_or_updated (NMDevice *self, NMConnection *connection) } static void -cp_connection_added (NMSettings *settings, NMConnection *connection, gpointer user_data) +cp_connection_added (NMSettings *settings, NMSettingsConnection *sett_conn, gpointer user_data) { - cp_connection_added_or_updated (user_data, connection); + cp_connection_added_or_updated (user_data, sett_conn); } static void -cp_connection_updated (NMSettings *settings, NMConnection *connection, gboolean by_user, gpointer user_data) +cp_connection_updated (NMSettings *settings, NMSettingsConnection *sett_conn, gboolean by_user, gpointer user_data) { - cp_connection_added_or_updated (user_data, connection); + cp_connection_added_or_updated (user_data, sett_conn); } static void -cp_connection_removed (NMSettings *settings, NMConnection *connection, gpointer user_data) +cp_connection_removed (NMSettings *settings, NMSettingsConnection *sett_conn, gpointer user_data) { NMDevice *self = user_data; g_return_if_fail (NM_IS_DEVICE (self)); - if (available_connections_del (self, connection)) { + if (available_connections_del (self, sett_conn)) { _notify (self, PROP_AVAILABLE_CONNECTIONS); available_connections_check_delete_unrealized (self); } @@ -13737,6 +14279,8 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean priv->ip6_mtu_initial = 0; } + _ethtool_state_reset (self); + _cleanup_generic_post (self, cleanup_type); } @@ -14016,7 +14560,7 @@ _set_state_full (NMDevice *self, NMDeviceState old_state; NMActRequest *req; gboolean no_firmware = FALSE; - NMSettingsConnection *connection; + NMSettingsConnection *sett_conn; g_return_if_fail (NM_IS_DEVICE (self)); @@ -14275,10 +14819,10 @@ _set_state_full (NMDevice *self, break; } - connection = nm_device_get_settings_connection (self); + sett_conn = nm_device_get_settings_connection (self); _LOGW (LOGD_DEVICE | LOGD_WIFI, "Activation: failed for connection '%s'", - connection ? nm_settings_connection_get_id (connection) : "<unknown>"); + sett_conn ? nm_settings_connection_get_id (sett_conn) : "<unknown>"); /* Notify any slaves of the unexpected failure */ nm_device_master_release_slaves (self); @@ -14288,8 +14832,8 @@ _set_state_full (NMDevice *self, * failed (zero timestamp), connections that succeeded (non-zero timestamp), * and those we haven't tried yet (no timestamp). */ - if (connection && !nm_settings_connection_get_timestamp (connection, NULL)) - nm_settings_connection_update_timestamp (connection, (guint64) 0, TRUE); + if (sett_conn && !nm_settings_connection_get_timestamp (sett_conn, NULL)) + nm_settings_connection_update_timestamp (sett_conn, (guint64) 0, TRUE); /* Schedule the transition to DISCONNECTED. The device can't transition * immediately because we can't change states again from the state @@ -15203,8 +15747,7 @@ nm_device_get_supplicant_timeout (NMDevice *self) { NMConnection *connection; NMSetting8021x *s_8021x; - gs_free char *value = NULL; - gint timeout; + int timeout; #define SUPPLICANT_DEFAULT_TIMEOUT 25 g_return_val_if_fail (NM_IS_DEVICE (self), SUPPLICANT_DEFAULT_TIMEOUT); @@ -15218,11 +15761,12 @@ nm_device_get_supplicant_timeout (NMDevice *self) return timeout; } - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "802-1x.auth-timeout", - self); - return _nm_utils_ascii_str_to_int64 (value, 10, 1, G_MAXINT32, - SUPPLICANT_DEFAULT_TIMEOUT); + return nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "802-1x.auth-timeout", + self, + 1, + G_MAXINT32, + SUPPLICANT_DEFAULT_TIMEOUT); } gboolean @@ -15245,12 +15789,10 @@ nm_device_auth_retries_try_next (NMDevice *self) auth_retries = nm_setting_connection_get_auth_retries (s_con); if (auth_retries == -1) { - gs_free char *value = NULL; - - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "connection.auth-retries", - self); - auth_retries = _nm_utils_ascii_str_to_int64 (value, 10, -1, G_MAXINT32, -1); + auth_retries = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "connection.auth-retries", + self, + -1, G_MAXINT32, -1); } if (auth_retries == 0) diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index d145f8fc..8f376b20 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -167,14 +167,34 @@ typedef enum NMActStageReturn NMActStageReturn; typedef enum { /*< skip >*/ NM_DEVICE_CHECK_CON_AVAILABLE_NONE = 0, + /* since NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST is a collection of flags with more fine grained + * parts, this flag in general indicates that this is a user-request. */ _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST = (1L << 0), + + /* we also consider devices which have no carrier but are still waiting for the driver + * to detect carrier. Usually, such devices are not yet available, however for a user-request + * they are. They might fail later if carrier doesn't come. */ _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER = (1L << 1), + + /* usually, a profile is only available if the Wi-Fi AP is in range. For an + * explicit user request, we also consider profiles for APs that are not (yet) + * visible. */ _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP = (1L << 2), + + /* a device can be marked as unmanaged for various reasons. Some of these reasons + * are authorative, others not. Non-authoritative reasons can be overruled by + * `nmcli device set $DEVICE managed yes`. Also, for an explicit user activation + * request we may want to consider the device as managed. This flag makes devices + * that are unmanaged appear available. */ + _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_OVERRULE_UNMANAGED = (1L << 3), + + /* a collection of flags, that are commonly set for an explict user-request. */ NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST = _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST | _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER - | _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP, + | _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP + | _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_OVERRULE_UNMANAGED, - NM_DEVICE_CHECK_CON_AVAILABLE_ALL = (1L << 3) - 1, + NM_DEVICE_CHECK_CON_AVAILABLE_ALL = (1L << 4) - 1, } NMDeviceCheckConAvailableFlags; struct _NMDevicePrivate; @@ -190,7 +210,12 @@ struct _NMDevice { typedef enum { /*< skip >*/ NM_DEVICE_CHECK_DEV_AVAILABLE_NONE = 0, + /* the device is considered available, even if it has no carrier. + * + * For various device types (software devices) we ignore carrier based + * on the type. So, for them, this flag has no effect anyway. */ _NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER = (1L << 0), + NM_DEVICE_CHECK_DEV_AVAILABLE_FOR_USER_REQUEST = _NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER, NM_DEVICE_CHECK_DEV_AVAILABLE_ALL = (1L << 1) - 1, @@ -202,7 +227,12 @@ typedef struct _NMDeviceClass { struct _NMDeviceClass *default_type_description_klass; const char *default_type_description; - const char *connection_type; + const char *connection_type_supported; + + /* most device types, can only handle profiles of a particular type. This + * is the connection.type setting, as checked by nm_device_check_connection_compatible() */ + const char *connection_type_check_compatible; + const NMLinkType *link_types; /* Whether the device type is a master-type. This depends purely on the @@ -292,7 +322,7 @@ typedef struct _NMDeviceClass { gboolean (* get_autoconnect_allowed) (NMDevice *self); gboolean (* can_auto_connect) (NMDevice *self, - NMConnection *connection, + NMSettingsConnection *sett_conn, char **specific_object); guint32 (*get_configured_mtu) (NMDevice *self, NMDeviceMtuSource *out_source); @@ -301,7 +331,9 @@ typedef struct _NMDeviceClass { * only the devices type and characteristics. Does not use any live * network information like WiFi scan lists etc. */ - gboolean (* check_connection_compatible) (NMDevice *self, NMConnection *connection); + gboolean (* check_connection_compatible) (NMDevice *self, + NMConnection *connection, + GError **error); /* Checks whether the connection is likely available to be activated, * including any live network information like scan lists. The connection @@ -317,7 +349,8 @@ typedef struct _NMDeviceClass { gboolean (* check_connection_available) (NMDevice *self, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object); + const char *specific_object, + GError **error); gboolean (* complete_connection) (NMDevice *self, NMConnection *connection, @@ -493,6 +526,9 @@ gboolean nm_device_parent_notify_changed (NMDevice *self, NMDevice *change_candidate, gboolean device_removed); +const char *nm_device_parent_find_for_connection (NMDevice *self, + const char *current_setting_parent); + /* Master */ gboolean nm_device_is_master (NMDevice *dev); @@ -501,6 +537,7 @@ NMDevice * nm_device_get_master (NMDevice *dev); NMActRequest * nm_device_get_act_request (NMDevice *dev); NMSettingsConnection *nm_device_get_settings_connection (NMDevice *dev); +NMConnection * nm_device_get_settings_connection_get_connection (NMDevice *self); NMConnection * nm_device_get_applied_connection (NMDevice *dev); gboolean nm_device_has_unmodified_applied_connection (NMDevice *self, NMSettingCompareFlags compare_flags); @@ -524,7 +561,7 @@ gboolean nm_device_master_update_slave_connection (NMDevice *master, GError **error); gboolean nm_device_can_auto_connect (NMDevice *self, - NMConnection *connection, + NMSettingsConnection *sett_conn, char **specific_object); gboolean nm_device_complete_connection (NMDevice *device, @@ -533,7 +570,10 @@ gboolean nm_device_complete_connection (NMDevice *device, NMConnection *const*existing_connections, GError **error); -gboolean nm_device_check_connection_compatible (NMDevice *device, NMConnection *connection); +gboolean nm_device_check_connection_compatible (NMDevice *device, + NMConnection *connection, + GError **error); + gboolean nm_device_check_slave_connection_compatible (NMDevice *device, NMConnection *connection); gboolean nm_device_unmanage_on_quit (NMDevice *self); @@ -568,7 +608,7 @@ void nm_device_copy_ip6_dns_config (NMDevice *self, NMDevice *from_device); * @NM_UNMANAGED_SLEEPING: %TRUE when unmanaged because NM is sleeping. * @NM_UNMANAGED_QUITTING: %TRUE when unmanaged because NM is shutting down. * @NM_UNMANAGED_PARENT: %TRUE when unmanaged due to parent device being unmanaged - * @NM_UNMANAGED_LOOPBACK: %TRUE for unmanaging loopback device + * @NM_UNMANAGED_BY_TYPE: %TRUE for unmanaging device by type, like loopback. * @NM_UNMANAGED_PLATFORM_INIT: %TRUE when unmanaged because platform link not * yet initialized. Unrealized device are also unmanaged for this reason. * @NM_UNMANAGED_USER_EXPLICIT: %TRUE when unmanaged by explicit user decision @@ -599,7 +639,7 @@ typedef enum { /*< skip >*/ NM_UNMANAGED_SLEEPING = (1LL << 0), NM_UNMANAGED_QUITTING = (1LL << 1), NM_UNMANAGED_PARENT = (1LL << 2), - NM_UNMANAGED_LOOPBACK = (1LL << 3), + NM_UNMANAGED_BY_TYPE = (1LL << 3), NM_UNMANAGED_PLATFORM_INIT = (1LL << 4), NM_UNMANAGED_USER_EXPLICIT = (1LL << 5), NM_UNMANAGED_USER_SETTINGS = (1LL << 6), @@ -742,7 +782,8 @@ NMSettingsConnection *nm_device_get_best_connection (NMDevice *device, gboolean nm_device_check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object); + const char *specific_object, + GError **error); gboolean nm_device_notify_component_added (NMDevice *device, GObject *component); diff --git a/src/devices/ovs/meson.build b/src/devices/ovs/meson.build index f4edd57c..9d637fe9 100644 --- a/src/devices/ovs/meson.build +++ b/src/devices/ovs/meson.build @@ -15,7 +15,6 @@ libnm_device_plugin_ovs = shared_module( 'nm-device-plugin-ovs', sources: sources, dependencies: deps, - c_args: '-DRUNSTATEDIR="@0@"'.format(nm_runstatedir), link_args: ldflags_linker_script_devices, link_depends: linker_script_devices, install: true, @@ -24,10 +23,10 @@ libnm_device_plugin_ovs = shared_module( core_plugins += libnm_device_plugin_ovs -run_target( +test( 'check-local-devices-ovs', - command: [check_exports, libnm_device_plugin_ovs.full_path(), linker_script_devices], - depends: libnm_device_plugin_ovs + check_exports, + args: [libnm_device_plugin_ovs.full_path(), linker_script_devices], ) # FIXME: check_so_symbols replacement diff --git a/src/devices/ovs/nm-device-ovs-bridge.c b/src/devices/ovs/nm-device-ovs-bridge.c index 2e4d1cbd..eff355a3 100644 --- a/src/devices/ovs/nm-device-ovs-bridge.c +++ b/src/devices/ovs/nm-device-ovs-bridge.c @@ -76,21 +76,6 @@ get_generic_capabilities (NMDevice *device) return NM_DEVICE_CAP_IS_SOFTWARE; } -static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - const char *connection_type; - - if (!NM_DEVICE_CLASS (nm_device_ovs_bridge_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - connection_type = nm_connection_get_connection_type (connection); - if (!nm_streq0 (connection_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME)) - return FALSE; - - return TRUE; -} - static NMActStageReturn act_stage3_ip4_config_start (NMDevice *device, NMIP4Config **out_config, @@ -152,13 +137,15 @@ nm_device_ovs_bridge_class_init (NMDeviceOvsBridgeClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ovs_bridge); - device_class->connection_type = NM_SETTING_OVS_BRIDGE_SETTING_NAME; + device_class->connection_type_supported = NM_SETTING_OVS_BRIDGE_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_OVS_BRIDGE_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (); + device_class->is_master = TRUE; device_class->get_type_description = get_type_description; device_class->create_and_realize = create_and_realize; device_class->unrealize = unrealize; device_class->get_generic_capabilities = get_generic_capabilities; - device_class->check_connection_compatible = check_connection_compatible; device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; device_class->enslave_slave = enslave_slave; diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c index c59af7a6..2b48fae6 100644 --- a/src/devices/ovs/nm-device-ovs-interface.c +++ b/src/devices/ovs/nm-device-ovs-interface.c @@ -85,25 +85,20 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { - NMSettingConnection *s_con; NMSettingOvsInterface *s_ovs_iface; - if (!NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->check_connection_compatible (device, connection)) + if (!NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_ovs_iface = nm_connection_get_setting_ovs_interface (connection); - if (!s_ovs_iface) - return FALSE; - if (!NM_IN_STRSET (nm_setting_ovs_interface_get_interface_type (s_ovs_iface), - "internal", "patch")) { - return FALSE; - } - s_con = nm_connection_get_setting_connection (connection); - if (g_strcmp0 (nm_setting_connection_get_connection_type (s_con), - NM_SETTING_OVS_INTERFACE_SETTING_NAME) != 0) { + if (!NM_IN_STRSET (nm_setting_ovs_interface_get_interface_type (s_ovs_iface), + "internal", + "patch")) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "unsupported OVS interface type in profile"); return FALSE; } @@ -199,11 +194,12 @@ nm_device_ovs_interface_class_init (NMDeviceOvsInterfaceClass *klass) NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_OPENVSWITCH); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ovs_interface); - device_class->connection_type = NM_SETTING_OVS_INTERFACE_SETTING_NAME; + device_class->connection_type_supported = NM_SETTING_OVS_INTERFACE_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_OVS_INTERFACE_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_OPENVSWITCH); + device_class->get_type_description = get_type_description; device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; diff --git a/src/devices/ovs/nm-device-ovs-port.c b/src/devices/ovs/nm-device-ovs-port.c index a9a2b24a..1f9afbab 100644 --- a/src/devices/ovs/nm-device-ovs-port.c +++ b/src/devices/ovs/nm-device-ovs-port.c @@ -70,26 +70,6 @@ get_generic_capabilities (NMDevice *device) return NM_DEVICE_CAP_IS_SOFTWARE; } -static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingConnection *s_con; - const char *connection_type; - - if (!NM_DEVICE_CLASS (nm_device_ovs_port_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_con = nm_connection_get_setting_connection (connection); - connection_type = nm_setting_connection_get_connection_type (s_con); - if (!connection_type) - return FALSE; - - if (strcmp (connection_type, NM_SETTING_OVS_PORT_SETTING_NAME) == 0) - return TRUE; - - return FALSE; -} - static NMActStageReturn act_stage3_ip4_config_start (NMDevice *device, NMIP4Config **out_config, @@ -198,12 +178,14 @@ nm_device_ovs_port_class_init (NMDeviceOvsPortClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_ovs_port); - device_class->connection_type = NM_SETTING_OVS_PORT_SETTING_NAME; + device_class->connection_type_supported = NM_SETTING_OVS_PORT_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_OVS_PORT_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (); + device_class->is_master = TRUE; device_class->get_type_description = get_type_description; device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; - device_class->check_connection_compatible = check_connection_compatible; device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; device_class->enslave_slave = enslave_slave; diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c index a9cb5703..b00397cf 100644 --- a/src/devices/ovs/nm-ovsdb.c +++ b/src/devices/ovs/nm-ovsdb.c @@ -139,7 +139,7 @@ typedef struct { static void _call_trace (const char *comment, OvsdbMethodCall *call, json_t *msg) { -#ifdef NM_MORE_LOGGING +#if NM_MORE_LOGGING char *str = NULL; if (msg) diff --git a/src/devices/team/meson.build b/src/devices/team/meson.build index 159c182a..0f0763bd 100644 --- a/src/devices/team/meson.build +++ b/src/devices/team/meson.build @@ -21,10 +21,10 @@ libnm_device_plugin_team = shared_module( core_plugins += libnm_device_plugin_team -run_target( +test( 'check-local-devices-team', - command: [check_exports, libnm_device_plugin_team.full_path(), linker_script_devices], - depends: libnm_device_plugin_team + check_exports, + args: [libnm_device_plugin_team.full_path(), linker_script_devices], ) # FIXME: check_so_symbols replacement diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index f83ba22b..899932fd 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -1,8 +1,6 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * - * Copyright (C) 2013 Jiri Pirko <jiri@resnulli.us> - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -16,6 +14,9 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2013 Jiri Pirko <jiri@resnulli.us> + * Copyright (C) 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -84,23 +85,6 @@ get_generic_capabilities (NMDevice *device) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingTeam *s_team; - - if (!NM_DEVICE_CLASS (nm_device_team_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_team = nm_connection_get_setting_team (connection); - if (!s_team || !nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME)) - return FALSE; - - /* FIXME: match team properties like mode, etc? */ - - return TRUE; -} - -static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, @@ -367,8 +351,8 @@ teamd_timeout_cb (gpointer user_data) static void teamd_dbus_appeared (GDBusConnection *connection, - const gchar *name, - const gchar *name_owner, + const char *name, + const char *name_owner, gpointer user_data) { NMDeviceTeam *self = NM_DEVICE_TEAM (user_data); @@ -430,7 +414,7 @@ teamd_dbus_appeared (GDBusConnection *connection, static void teamd_dbus_vanished (GDBusConnection *dbus_connection, - const gchar *name, + const char *name, gpointer user_data) { NMDeviceTeam *self = NM_DEVICE_TEAM (user_data); @@ -463,7 +447,7 @@ teamd_dbus_vanished (GDBusConnection *dbus_connection, } static void -teamd_process_watch_cb (GPid pid, gint status, gpointer user_data) +teamd_process_watch_cb (GPid pid, int status, gpointer user_data) { NMDeviceTeam *self = NM_DEVICE_TEAM (user_data); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); @@ -516,7 +500,7 @@ teamd_kill (NMDeviceTeam *self, const char *teamd_binary, GError **error) g_ptr_array_add (argv, (gpointer) nm_device_get_iface (NM_DEVICE (self))); g_ptr_array_add (argv, NULL); - _LOGD (LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata))); + _LOGD (LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv (" ", (char **) argv->pdata))); return g_spawn_sync ("/", (char **) argv->pdata, NULL, 0, teamd_child_setup, NULL, NULL, NULL, NULL, error); } @@ -604,7 +588,7 @@ teamd_start (NMDevice *device, NMConnection *connection) g_ptr_array_add (argv, (gpointer) "-gg"); g_ptr_array_add (argv, NULL); - _LOGD (LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv (" ", (gchar **) argv->pdata))); + _LOGD (LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv (" ", (char **) argv->pdata))); if (!g_spawn_async ("/", (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD, teamd_child_setup, NULL, &priv->teamd_pid, &error)) { _LOGW (LOGD_TEAM, "Activation: (team) failed to start teamd: %s", error->message); @@ -703,7 +687,7 @@ enslave_slave (NMDevice *device, { NMDeviceTeam *self = NM_DEVICE_TEAM (device); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - gboolean success = TRUE, no_firmware = FALSE; + gboolean success = TRUE; const char *slave_iface = nm_device_get_ip_iface (slave); NMSettingTeamPort *s_team_port; @@ -738,7 +722,7 @@ enslave_slave (NMDevice *device, success = nm_platform_link_enslave (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)); - nm_device_bring_up (slave, TRUE, &no_firmware); + nm_device_bring_up (slave, TRUE, NULL); if (!success) return FALSE; @@ -762,7 +746,7 @@ release_slave (NMDevice *device, { NMDeviceTeam *self = NM_DEVICE_TEAM (device); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (self); - gboolean success, no_firmware = FALSE; + gboolean success; if (configure) { success = nm_platform_link_release (nm_device_get_platform (device), @@ -778,7 +762,7 @@ release_slave (NMDevice *device, * IFF_UP), so we must bring it back up here to ensure carrier changes and * other state is noticed by the now-released port. */ - if (!nm_device_bring_up (slave, TRUE, &no_firmware)) + if (!nm_device_bring_up (slave, TRUE, NULL)) _LOGW (LOGD_TEAM, "released team port %s could not be brought up", nm_device_get_ip_iface (slave)); @@ -910,9 +894,7 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_TEAM_SETTING_NAME, NM_LINK_TYPE_TEAM) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructed = constructed; object_class->dispose = dispose; @@ -920,19 +902,22 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_team); - parent_class->is_master = TRUE; - parent_class->create_and_realize = create_and_realize; - parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->complete_connection = complete_connection; - parent_class->update_connection = update_connection; - parent_class->master_update_slave_connection = master_update_slave_connection; - - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; - parent_class->deactivate = deactivate; - parent_class->enslave_slave = enslave_slave; - parent_class->release_slave = release_slave; + device_class->connection_type_supported = NM_SETTING_TEAM_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_TEAM_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_TEAM); + + device_class->is_master = TRUE; + device_class->create_and_realize = create_and_realize; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->complete_connection = complete_connection; + device_class->update_connection = update_connection; + device_class->master_update_slave_connection = master_update_slave_connection; + + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; + device_class->deactivate = deactivate; + device_class->enslave_slave = enslave_slave; + device_class->release_slave = release_slave; obj_properties[PROP_CONFIG] = g_param_spec_string (NM_DEVICE_TEAM_CONFIG, "", "", diff --git a/src/devices/wifi/meson.build b/src/devices/wifi/meson.build index a27f8e6a..2745040b 100644 --- a/src/devices/wifi/meson.build +++ b/src/devices/wifi/meson.build @@ -33,10 +33,10 @@ libnm_device_plugin_wifi = shared_module( core_plugins += libnm_device_plugin_wifi -run_target( +test( 'check-local-devices-wifi', - command: [check_exports, libnm_device_plugin_wifi.full_path(), linker_script_devices], - depends: libnm_device_plugin_wifi + check_exports, + args: [libnm_device_plugin_wifi.full_path(), linker_script_devices], ) # FIXME: check_so_symbols replacement diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index 7667816a..1d1be742 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -67,7 +67,8 @@ static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { GDBusObject * dbus_obj; - GDBusProxy * dbus_proxy; + GDBusProxy * dbus_device_proxy; + GDBusProxy * dbus_station_proxy; CList aps_lst_head; NMWifiAP * current_ap; GCancellable * cancellable; @@ -204,11 +205,11 @@ remove_all_aps (NMDeviceIwd *self) } static GVariant * -vardict_from_network_type (const gchar *type) +vardict_from_network_type (const char *type) { GVariantBuilder builder; - const gchar *key_mgmt = ""; - const gchar *pairwise = "ccmp"; + const char *key_mgmt = ""; + const char *pairwise = "ccmp"; if (!strcmp (type, "psk")) key_mgmt = "wpa-psk"; @@ -228,6 +229,78 @@ vardict_from_network_type (const gchar *type) } static void +insert_ap_from_network (GHashTable *aps, const char *path, int16_t signal, uint32_t ap_id) +{ + gs_unref_object GDBusProxy *network_proxy = NULL; + gs_unref_variant GVariant *name_value = NULL, *type_value = NULL; + const char *name, *type; + GVariantBuilder builder; + gs_unref_variant GVariant *props = NULL; + GVariant *rsn; + uint8_t bssid[6]; + NMWifiAP *ap; + + network_proxy = nm_iwd_manager_get_dbus_interface (nm_iwd_manager_get (), + path, + NM_IWD_NETWORK_INTERFACE); + if (!network_proxy) + return; + + name_value = g_dbus_proxy_get_cached_property (network_proxy, "Name"); + type_value = g_dbus_proxy_get_cached_property (network_proxy, "Type"); + if ( !name_value + || !g_variant_is_of_type (name_value, G_VARIANT_TYPE_STRING) + || !type_value + || !g_variant_is_of_type (type_value, G_VARIANT_TYPE_STRING)) + return; + + name = g_variant_get_string (name_value, NULL); + type = g_variant_get_string (type_value, NULL); + + /* What we get from IWD are networks, or ESSs, that may contain + * multiple APs, or BSSs, each. We don't get information about any + * specific BSSs within an ESS but we can safely present each ESS + * as an individual BSS to NM, which will be seen as ESSs comprising + * a single BSS each. NM won't be able to handle roaming but IWD + * already does that. We fake the BSSIDs as they don't play any + * role either. + */ + bssid[0] = 0x00; + bssid[1] = 0x01; + bssid[2] = 0x02; + bssid[3] = ap_id >> 16; + bssid[4] = ap_id >> 8; + bssid[5] = ap_id; + + /* WEP not supported */ + if (nm_streq (type, "wep")) + return; + + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&builder, "{sv}", "BSSID", + g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, bssid, 6, 1)); + g_variant_builder_add (&builder, "{sv}", "Mode", + g_variant_new_string ("infrastructure")); + + rsn = vardict_from_network_type (type); + if (rsn) + g_variant_builder_add (&builder, "{sv}", "RSN", rsn); + + props = g_variant_new ("a{sv}", &builder); + + ap = nm_wifi_ap_new_from_properties (path, props); + + nm_wifi_ap_set_ssid_arr (ap, + (const guint8 *) name, + NM_MIN (32, strlen (name))); + + nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (signal / 100)); + nm_wifi_ap_set_freq (ap, 2417); + nm_wifi_ap_set_max_bitrate (ap, 65000); + g_hash_table_insert (aps, (gpointer) nm_wifi_ap_get_supplicant_path (ap), ap); +} + +static void get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) { NMDeviceIwd *self = user_data; @@ -235,75 +308,39 @@ get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) gs_free_error GError *error = NULL; gs_unref_variant GVariant *variant = NULL; GVariantIter *networks; - const gchar *path, *name, *type; + const char *path, *name, *type; int16_t signal; NMWifiAP *ap, *ap_safe, *new_ap; gboolean changed = FALSE; GHashTableIter ap_iter; gs_unref_hashtable GHashTable *new_aps = NULL; + /* Depending on whether we're using the Station interface or the Device + * interface for compatibility with IWD <= 0.7, the return signature of + * GetOrderedNetworks will be different. + */ + gboolean compat = priv->dbus_station_proxy == priv->dbus_device_proxy; + const char *return_sig = compat ? "(a(osns))" : "(a(on))"; + static uint32_t ap_id = 0; variant = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, - G_VARIANT_TYPE ("(a(osns))"), + G_VARIANT_TYPE (return_sig), &error); if (!variant) { - _LOGE (LOGD_WIFI, "Device.GetOrderedNetworks failed: %s", + _LOGE (LOGD_WIFI, "Station.GetOrderedNetworks failed: %s", error->message); return; } new_aps = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref); - g_variant_get (variant, "(a(osns))", &networks); - - while (g_variant_iter_next (networks, "(&o&sn&s)", &path, &name, &signal, &type)) { - GVariantBuilder builder; - gs_unref_variant GVariant *props = NULL; - GVariant *rsn; - static uint32_t ap_id = 0; - uint8_t bssid[6]; + g_variant_get (variant, return_sig, &networks); - /* - * What we get from IWD are networks, or ESSs, that may - * contain multiple APs, or BSSs, each. We don't get - * information about any specific BSSs within an ESS but - * we can safely present each ESS as an individual BSS to - * NM, which will be seen as ESSs comprising a single BSS - * each. NM won't be able to handle roaming but IWD already - * does that. We fake the BSSIDs as they don't play any - * role either. - */ - bssid[0] = 0x00; - bssid[1] = 0x01; - bssid[2] = 0x02; - bssid[3] = ap_id >> 16; - bssid[4] = ap_id >> 8; - bssid[5] = ap_id++; - - /* WEP not supported */ - if (!strcmp (type, "wep")) - continue; - - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add (&builder, "{sv}", "BSSID", - g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, bssid, 6, 1)); - g_variant_builder_add (&builder, "{sv}", "Mode", - g_variant_new_string ("infrastructure")); - - rsn = vardict_from_network_type (type); - if (rsn) - g_variant_builder_add (&builder, "{sv}", "RSN", rsn); - - props = g_variant_new ("a{sv}", &builder); - - ap = nm_wifi_ap_new_from_properties (path, props); - if (name[0] != '\0') - nm_wifi_ap_set_ssid (ap, (const guint8 *) name, strlen (name)); - nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (signal / 100)); - nm_wifi_ap_set_freq (ap, 2417); - nm_wifi_ap_set_max_bitrate (ap, 65000); - g_hash_table_insert (new_aps, - (gpointer) nm_wifi_ap_get_supplicant_path (ap), - ap); + if (compat) { + while (g_variant_iter_next (networks, "(&o&sn&s)", &path, &name, &signal, &type)) + insert_ap_from_network (new_aps, path, signal, ap_id++); + } else { + while (g_variant_iter_next (networks, "(&on)", &path, &signal)) + insert_ap_from_network (new_aps, path, signal, ap_id++); } g_variant_iter_free (networks); @@ -355,7 +392,7 @@ update_aps (NMDeviceIwd *self) if (!priv->cancellable) priv->cancellable = g_cancellable_new (); - g_dbus_proxy_call (priv->dbus_proxy, "GetOrderedNetworks", + g_dbus_proxy_call (priv->dbus_station_proxy, "GetOrderedNetworks", g_variant_new ("()"), G_DBUS_CALL_FLAGS_NONE, 2000, priv->cancellable, get_ordered_networks_cb, self); @@ -366,7 +403,7 @@ send_disconnect (NMDeviceIwd *self) { NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - g_dbus_proxy_call (priv->dbus_proxy, "Disconnect", g_variant_new ("()"), + g_dbus_proxy_call (priv->dbus_station_proxy, "Disconnect", g_variant_new ("()"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); } @@ -389,7 +426,7 @@ cleanup_association_attempt (NMDeviceIwd *self, gboolean disconnect) set_current_ap (self, NULL, TRUE); - if (disconnect && priv->dbus_obj) + if (disconnect && priv->dbus_station_proxy) send_disconnect (self); } @@ -405,7 +442,7 @@ deactivate_async_finish (NMDevice *device, GAsyncResult *res, GError **error) NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (NM_DEVICE_IWD (device)); gs_unref_variant GVariant *variant = NULL; - variant = g_dbus_proxy_call_finish (priv->dbus_proxy, res, error); + variant = g_dbus_proxy_call_finish (priv->dbus_station_proxy, res, error); return variant != NULL; } @@ -441,39 +478,18 @@ deactivate_async (NMDevice *device, ctx->callback = callback; ctx->user_data = user_data; - g_dbus_proxy_call (priv->dbus_proxy, "Disconnect", g_variant_new ("()"), + g_dbus_proxy_call (priv->dbus_station_proxy, "Disconnect", g_variant_new ("()"), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, disconnect_cb, ctx); } -static NMIwdNetworkSecurity -get_connection_iwd_security (NMConnection *connection) -{ - NMSettingWirelessSecurity *s_wireless_sec; - const char *key_mgmt = NULL; - - s_wireless_sec = nm_connection_get_setting_wireless_security (connection); - if (!s_wireless_sec) - return NM_IWD_NETWORK_SECURITY_NONE; - - key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec); - nm_assert (key_mgmt); - - if (!strcmp (key_mgmt, "none") || !strcmp (key_mgmt, "ieee8021x")) - return NM_IWD_NETWORK_SECURITY_WEP; - - if (!strcmp (key_mgmt, "wpa-psk")) - return NM_IWD_NETWORK_SECURITY_PSK; - - nm_assert (!strcmp (key_mgmt, "wpa-eap")); - return NM_IWD_NETWORK_SECURITY_8021X; -} - static gboolean is_connection_known_network (NMConnection *connection) { NMSettingWireless *s_wireless; + NMIwdNetworkSecurity security; + gboolean security_ok; GBytes *ssid; - gs_free gchar *str_ssid = NULL; + gs_free char *ssid_utf8 = NULL; s_wireless = nm_connection_get_setting_wireless (connection); if (!s_wireless) @@ -483,68 +499,73 @@ is_connection_known_network (NMConnection *connection) if (!ssid) return FALSE; - str_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), - g_bytes_get_size (ssid)); + ssid_utf8 = _nm_utils_ssid_to_utf8 (ssid); + + security = nm_wifi_connection_get_iwd_security (connection, &security_ok); + if (!security_ok) + return FALSE; return nm_iwd_manager_is_known_network (nm_iwd_manager_get (), - str_ssid, - get_connection_iwd_security (connection)); + ssid_utf8, security); } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { - NMSettingConnection *s_con; NMSettingWireless *s_wireless; const char *mac; const char * const *mac_blacklist; int i; - const char *mode; const char *perm_hw_addr; - if (!NM_DEVICE_CLASS (nm_device_iwd_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME)) + if (!NM_DEVICE_CLASS (nm_device_iwd_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_wireless = nm_connection_get_setting_wireless (connection); - if (!s_wireless) - return FALSE; perm_hw_addr = nm_device_get_permanent_hw_address (device); mac = nm_setting_wireless_get_mac_address (s_wireless); if (perm_hw_addr) { - if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) + if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device MAC address does not match the profile"); return FALSE; + } /* Check for MAC address blacklist */ mac_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); for (i = 0; mac_blacklist[i]; i++) { - if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { - g_warn_if_reached (); - return FALSE; - } + nm_assert (nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)); - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) + if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "MAC address blacklisted"); return FALSE; + } } - } else if (mac) + } else if (mac) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has no valid MAC address as required by profile"); return FALSE; + } - mode = nm_setting_wireless_get_mode (s_wireless); - if (mode && g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0) + if (!NM_IN_STRSET (nm_setting_wireless_get_mode (s_wireless), + NULL, + NM_SETTING_WIRELESS_MODE_INFRA)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "IWD only support infrastructure type profiles"); return FALSE; + } /* 8021x networks can only be used if they've been provisioned on the IWD side and * thus are Known Networks. */ - if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_connection_known_network (connection)) + if (nm_wifi_connection_get_iwd_security (connection, NULL) == NM_IWD_NETWORK_SECURITY_8021X) { + if (!is_connection_known_network (connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "802.1x profile is not a known network"); return FALSE; + } } return TRUE; @@ -554,7 +575,8 @@ static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMDeviceIwd *self = NM_DEVICE_IWD (device); NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); @@ -566,19 +588,28 @@ check_connection_available (NMDevice *device, /* Only Infrastrusture mode at this time */ mode = nm_setting_wireless_get_mode (s_wifi); - if (mode && g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0) + if (!NM_IN_STRSET (mode, NULL, NM_SETTING_WIRELESS_MODE_INFRA)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "iwd only supports infrastructure mode connections"); return FALSE; + } /* Hidden SSIDs not supported yet */ - if (nm_setting_wireless_get_hidden (s_wifi)) + if (nm_setting_wireless_get_hidden (s_wifi)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "hidden networks not supported by iwd"); return FALSE; + } /* 8021x networks can only be used if they've been provisioned on the IWD side and * thus are Known Networks. */ - if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_connection_known_network (connection)) + if (nm_wifi_connection_get_iwd_security (connection, NULL) == NM_IWD_NETWORK_SECURITY_8021X) { + if (!is_connection_known_network (connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "network is not known to iwd"); return FALSE; + } } /* a connection that is available for a certain @specific_object, MUST @@ -588,14 +619,29 @@ check_connection_available (NMDevice *device, NMWifiAP *ap; ap = nm_wifi_ap_lookup_for_device (NM_DEVICE (self), specific_object); - return ap ? nm_wifi_ap_check_compatible (ap, connection) : FALSE; + if (!ap) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "requested access point not found"); + return FALSE; + } + if (!nm_wifi_ap_check_compatible (ap, connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "requested access point is not compatible with profile"); + return FALSE; + } + return TRUE; } if (NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) return TRUE; - /* Check at least one AP is compatible with this connection */ - return !!nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection); + if (!nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "no compatible access point found"); + return FALSE; + } + + return TRUE; } static gboolean @@ -609,10 +655,9 @@ complete_connection (NMDevice *device, NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); NMSettingWireless *s_wifi; const char *setting_mac; - char *str_ssid = NULL; + gs_free char *ssid_utf8 = NULL; NMWifiAP *ap; - const GByteArray *ssid = NULL; - GByteArray *tmp_ssid = NULL; + GBytes *ssid; GBytes *setting_ssid = NULL; const char *perm_hw_addr; const char *mode; @@ -676,8 +721,7 @@ complete_connection (NMDevice *device, } ssid = nm_wifi_ap_get_ssid (ap); - - if (ssid == NULL) { + if (!ssid) { g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, @@ -688,30 +732,23 @@ complete_connection (NMDevice *device, if (!nm_wifi_ap_complete_connection (ap, connection, nm_wifi_utils_is_manf_default_ssid (ssid), - error)) { - if (tmp_ssid) - g_byte_array_unref (tmp_ssid); + error)) return FALSE; - } - - str_ssid = nm_utils_ssid_to_utf8 (ssid->data, ssid->len); + ssid_utf8 = _nm_utils_ssid_to_utf8 (ssid); nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_WIRELESS_SETTING_NAME, existing_connections, - str_ssid, - str_ssid, + ssid_utf8, + ssid_utf8, NULL, TRUE); - g_free (str_ssid); - if (tmp_ssid) - g_byte_array_unref (tmp_ssid); /* 8021x networks can only be used if they've been provisioned on the IWD side and * thus are Known Networks. */ - if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) { + if (nm_wifi_connection_get_iwd_security (connection, NULL) == NM_IWD_NETWORK_SECURITY_8021X) { if (!is_connection_known_network (connection)) { g_set_error_literal (error, NM_CONNECTION_ERROR, @@ -753,17 +790,38 @@ complete_connection (NMDevice *device, } static gboolean +get_variant_boolean (GVariant *v, const char *property) +{ + if (!v || !g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN)) { + nm_log_warn (LOGD_DEVICE | LOGD_WIFI, + "Property %s not cached or not boolean type", property); + + return FALSE; + } + + return g_variant_get_boolean (v); +} + +static const char * +get_variant_state (GVariant *v) +{ + if (!v || !g_variant_is_of_type (v, G_VARIANT_TYPE_STRING)) { + nm_log_warn (LOGD_DEVICE | LOGD_WIFI, + "State property not cached or not a string"); + + return "unknown"; + } + + return g_variant_get_string (v, NULL); +} + +static gboolean is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) { NMDeviceIwd *self = NM_DEVICE_IWD (device); NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - gs_unref_variant GVariant *value = NULL; - - if (!priv->enabled || !priv->dbus_obj) - return FALSE; - value = g_dbus_proxy_get_cached_property (priv->dbus_proxy, "Powered"); - return g_variant_get_boolean (value); + return priv->enabled && priv->dbus_station_proxy; } static gboolean @@ -777,11 +835,12 @@ get_autoconnect_allowed (NMDevice *device) static gboolean can_auto_connect (NMDevice *device, - NMConnection *connection, + NMSettingsConnection *sett_conn, char **specific_object) { NMDeviceIwd *self = NM_DEVICE_IWD (device); NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + NMConnection *connection; NMSettingWireless *s_wifi; NMWifiAP *ap; const char *mode; @@ -789,9 +848,11 @@ can_auto_connect (NMDevice *device, nm_assert (!specific_object || !*specific_object); - if (!NM_DEVICE_CLASS (nm_device_iwd_parent_class)->can_auto_connect (device, connection, NULL)) + if (!NM_DEVICE_CLASS (nm_device_iwd_parent_class)->can_auto_connect (device, sett_conn, NULL)) return FALSE; + connection = nm_settings_connection_get_connection (sett_conn); + s_wifi = nm_connection_get_setting_wireless (connection); g_return_val_if_fail (s_wifi, FALSE); @@ -804,7 +865,7 @@ can_auto_connect (NMDevice *device, * but haven't been successful, since these are often accidental choices * from the menu and the user may not know the password. */ - if (nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (connection), ×tamp)) { + if (nm_settings_connection_get_timestamp (sett_conn, ×tamp)) { if (timestamp == 0) return FALSE; } @@ -812,7 +873,7 @@ can_auto_connect (NMDevice *device, /* 8021x networks can only be used if they've been provisioned on the IWD side and * thus are Known Networks. */ - if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) { + if (nm_wifi_connection_get_iwd_security (connection, NULL) == NM_IWD_NETWORK_SECURITY_8021X) { if (!is_connection_known_network (connection)) return FALSE; } @@ -897,8 +958,7 @@ dbus_request_scan_cb (NMDevice *device, priv = NM_DEVICE_IWD_GET_PRIVATE (self); - if ( !priv->enabled - || !priv->dbus_obj + if ( !priv->can_scan || nm_device_get_state (device) < NM_DEVICE_STATE_DISCONNECTED || nm_device_is_activating (device)) { g_dbus_method_invocation_return_error_literal (context, @@ -921,7 +981,7 @@ dbus_request_scan_cb (NMDevice *device, } if (!priv->scanning && !priv->scan_requested) { - g_dbus_proxy_call (priv->dbus_proxy, "Scan", + g_dbus_proxy_call (priv->dbus_station_proxy, "Scan", g_variant_new ("()"), G_DBUS_CALL_FLAGS_NONE, -1, priv->cancellable, scan_cb, self); @@ -939,8 +999,7 @@ _nm_device_iwd_request_scan (NMDeviceIwd *self, NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); - if ( !priv->enabled - || !priv->dbus_obj + if ( !priv->can_scan || nm_device_get_state (device) < NM_DEVICE_STATE_DISCONNECTED || nm_device_is_activating (device)) { g_dbus_method_invocation_return_error_literal (invocation, @@ -1005,11 +1064,11 @@ static gboolean try_reply_agent_request (NMDeviceIwd *self, NMConnection *connection, GDBusMethodInvocation *invocation, - const gchar **setting_name, - const gchar **setting_key, + const char **setting_name, + const char **setting_key, gboolean *replied) { - const gchar *method_name = g_dbus_method_invocation_get_method_name (invocation); + const char *method_name = g_dbus_method_invocation_get_method_name (invocation); NMSettingWirelessSecurity *s_wireless_sec; NMSetting8021x *s_8021x; @@ -1019,7 +1078,7 @@ try_reply_agent_request (NMDeviceIwd *self, *replied = FALSE; if (!strcmp (method_name, "RequestPassphrase")) { - const gchar *psk; + const char *psk; if (!s_wireless_sec) return FALSE; @@ -1039,7 +1098,7 @@ try_reply_agent_request (NMDeviceIwd *self, *setting_key = NM_SETTING_WIRELESS_SECURITY_PSK; return TRUE; } else if (!strcmp (method_name, "RequestPrivateKeyPassphrase")) { - const gchar *password; + const char *password; if (!s_8021x) return FALSE; @@ -1059,7 +1118,7 @@ try_reply_agent_request (NMDeviceIwd *self, *setting_key = NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD; return TRUE; } else if (!strcmp (method_name, "RequestUserNameAndPassword")) { - const gchar *identity, *password; + const char *identity, *password; if (!s_8021x) return FALSE; @@ -1083,7 +1142,7 @@ try_reply_agent_request (NMDeviceIwd *self, *setting_key = NM_SETTING_802_1X_PASSWORD; return TRUE; } else if (!strcmp (method_name, "RequestUserPassword")) { - const gchar *password; + const char *password; if (!s_8021x) return FALSE; @@ -1124,8 +1183,8 @@ wifi_secrets_cb (NMActRequest *req, NMDeviceIwdPrivate *priv; NMDevice *device; GDBusMethodInvocation *invocation; - const gchar *setting_name; - const gchar *setting_key; + const char *setting_name; + const char *setting_key; gboolean replied; NMSecretAgentGetSecretsFlags get_secret_flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; @@ -1182,12 +1241,7 @@ secrets_error: g_dbus_method_invocation_return_error_literal (invocation, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, "NM secrets request failed"); - - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - - cleanup_association_attempt (self, TRUE); + /* Now wait for the Connect callback to update device state */ } static void @@ -1219,16 +1273,19 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) { NMDeviceIwd *self = user_data; NMDevice *device = NM_DEVICE (self); + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); gs_free_error GError *error = NULL; NMConnection *connection; NMSettingWireless *s_wifi; GBytes *ssid; - gs_free gchar *str_ssid = NULL; + gs_free char *ssid_utf8 = NULL; + NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED; + GVariant *value; if (!_nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, G_VARIANT_TYPE ("()"), &error)) { - gs_free gchar *dbus_error = NULL; + gs_free char *dbus_error = NULL; /* Connection failed; radio problems or if the network wasn't * open, the passwords or certificates may be wrong. @@ -1238,6 +1295,12 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) "Activation: (wifi) Network.Connect failed: %s", error->message); + if (nm_utils_error_is_cancelled (error, TRUE)) + return; + + if (!NM_IN_SET (nm_device_get_state (device), NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_NEED_AUTH)) + return; + connection = nm_device_get_applied_connection (device); if (!connection) goto failed; @@ -1245,20 +1308,17 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) dbus_error = g_dbus_error_get_remote_error (error); - /* If secrets were wrong, we'd be getting a net.connman.iwd.Failed */ if (nm_streq0 (dbus_error, "net.connman.iwd.Failed")) { nm_connection_clear_secrets (connection); - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - } else if ( !nm_utils_error_is_cancelled (error, TRUE) - && nm_device_is_activating (device)) - goto failed; - - /* Call Disconnect to make sure IWD's autoconnect is disabled */ - cleanup_association_attempt (self, TRUE); + /* If secrets were wrong, we'd be getting a net.connman.iwd.Failed */ + reason = NM_DEVICE_STATE_REASON_NO_SECRETS; + } else if (nm_streq0 (dbus_error, "net.connman.iwd.Aborted")) { + /* If agent call was cancelled we'd be getting a net.connman.iwd.Aborted */ + reason = NM_DEVICE_STATE_REASON_NO_SECRETS; + } - return; + goto failed; } nm_assert (nm_device_get_state (device) == NM_DEVICE_STATE_CONFIG); @@ -1275,23 +1335,27 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) if (!ssid) goto failed; - str_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), - g_bytes_get_size (ssid)); + ssid_utf8 = _nm_utils_ssid_to_utf8 (ssid); _LOGI (LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) Stage 2 of 5 (Device Configure) successful. Connected to '%s'.", - str_ssid); + ssid_utf8); nm_device_activate_schedule_stage3_ip_config_start (device); - nm_iwd_manager_network_connected (nm_iwd_manager_get (), str_ssid, - get_connection_iwd_security (connection)); - return; failed: - cleanup_association_attempt (self, FALSE); - nm_device_queue_state (device, NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + /* Call Disconnect to make sure IWD's autoconnect is disabled */ + cleanup_association_attempt (self, TRUE); + + nm_device_queue_state (device, NM_DEVICE_STATE_FAILED, reason); + + value = g_dbus_proxy_get_cached_property (priv->dbus_station_proxy, "State"); + if (!priv->can_connect && nm_streq0 (get_variant_state (value), "disconnected")) { + priv->can_connect = true; + nm_device_emit_recheck_auto_activate (device); + } + g_variant_unref (value); } static void @@ -1299,7 +1363,7 @@ set_powered (NMDeviceIwd *self, gboolean powered) { NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - g_dbus_proxy_call (priv->dbus_proxy, + g_dbus_proxy_call (priv->dbus_device_proxy, "org.freedesktop.DBus.Properties.Set", g_variant_new ("(ssv)", NM_IWD_DEVICE_INTERFACE, "Powered", @@ -1361,7 +1425,6 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) NMActRequest *req; NMWifiAP *ap; NMConnection *connection; - GError *error = NULL; GDBusProxy *network_proxy; req = nm_device_get_act_request (device); @@ -1391,21 +1454,13 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) goto out; } - /* Locate the IWD Network object */ - network_proxy = g_dbus_proxy_new_for_bus_sync (NM_IWD_BUS_TYPE, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, - NULL, - NM_IWD_SERVICE, - nm_wifi_ap_get_supplicant_path (ap), - NM_IWD_NETWORK_INTERFACE, - NULL, &error); + network_proxy = nm_iwd_manager_get_dbus_interface (nm_iwd_manager_get (), + nm_wifi_ap_get_supplicant_path (ap), + NM_IWD_NETWORK_INTERFACE); if (!network_proxy) { _LOGE (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) could not get Network interface proxy for %s: %s", - nm_wifi_ap_get_supplicant_path (ap), - error->message); - g_clear_error (&error); + "Activation: (wifi) could not get Network interface proxy for %s", + nm_wifi_ap_get_supplicant_path (ap)); NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); goto out; } @@ -1452,7 +1507,7 @@ periodic_scan_timeout_cb (gpointer user_data) if (priv->scanning || priv->scan_requested) return FALSE; - g_dbus_proxy_call (priv->dbus_proxy, "Scan", g_variant_new ("()"), + g_dbus_proxy_call (priv->dbus_station_proxy, "Scan", g_variant_new ("()"), G_DBUS_CALL_FLAGS_NONE, -1, priv->cancellable, scan_cb, self); priv->scan_requested = TRUE; @@ -1506,7 +1561,7 @@ device_state_changed (NMDevice *device, * transition to DISCONNECTED because the device is now * ready to use. */ - if (priv->enabled && priv->dbus_obj) { + if (priv->enabled && priv->dbus_station_proxy) { nm_device_queue_recheck_available (device, NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); @@ -1556,17 +1611,18 @@ set_enabled (NMDevice *device, gboolean enabled) return; } - if (priv->dbus_proxy) + if (priv->dbus_obj) set_powered (self, enabled); if (enabled) { if (state != NM_DEVICE_STATE_UNAVAILABLE) _LOGW (LOGD_CORE, "not in expected unavailable state!"); - if (priv->dbus_obj) + if (priv->dbus_station_proxy) { nm_device_queue_recheck_available (device, NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + } } else { nm_device_state_changed (device, NM_DEVICE_STATE_UNAVAILABLE, @@ -1667,7 +1723,7 @@ set_property (GObject *object, guint prop_id, /*****************************************************************************/ static void -state_changed (NMDeviceIwd *self, const gchar *new_state) +state_changed (NMDeviceIwd *self, const char *new_state) { NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); @@ -1684,13 +1740,6 @@ state_changed (NMDeviceIwd *self, const gchar *new_state) /* Don't allow scanning while connecting, disconnecting or roaming */ priv->can_scan = NM_IN_STRSET (new_state, "connected", "disconnected"); - /* Don't allow new connection until iwd exits disconnecting */ - can_connect = NM_IN_STRSET (new_state, "disconnected"); - if (can_connect != priv->can_connect) { - priv->can_connect = can_connect; - nm_device_emit_recheck_auto_activate (device); - } - if (NM_IN_STRSET (new_state, "connecting", "connected", "roaming")) { /* If we were connecting, do nothing, the confirmation of * a connection success is handled in the Device.Connect @@ -1704,39 +1753,39 @@ state_changed (NMDeviceIwd *self, const gchar *new_state) _LOGW (LOGD_DEVICE | LOGD_WIFI, "Unsolicited connection success, asking IWD to disconnect"); send_disconnect (self); - - return; } else if (NM_IN_STRSET (new_state, "disconnecting", "disconnected")) { - if (!iwd_connection) - return; - /* Call Disconnect on the IWD device object to make sure it * disables its own autoconnect. - * - * Note we could instead call net.connman.iwd.KnownNetworks.ForgetNetwork - * and leave the device in autoconnect. This way if NetworkManager - * changes any settings for this connection, they'd be taken into - * account on the next connection attempt. But both methods are - * a hack, we'll perhaps need an IWD API to "connect once" without - * storing anything. */ send_disconnect (self); /* - * If IWD is still handling the Connect call, let our callback - * for the dbus method handle the failure. + * If IWD is still handling the Connect call, let our Connect + * callback for the dbus method handle the failure. The main + * reason we can't handle the failure here is because the method + * callback will have more information on the specific failure + * reason. */ if (dev_state == NM_DEVICE_STATE_CONFIG) return; - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - + if (iwd_connection) + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); + } else if (!nm_streq (new_state, "unknown")) { + _LOGE (LOGD_WIFI, "State %s unknown", new_state); return; } - _LOGE (LOGD_WIFI, "State %s unknown", new_state); + /* Don't allow new connection until iwd exits disconnecting and no + * Connect callback is pending. + */ + can_connect = NM_IN_STRSET (new_state, "disconnected"); + if (can_connect != priv->can_connect) { + priv->can_connect = can_connect; + nm_device_emit_recheck_auto_activate (device); + } } static void @@ -1761,32 +1810,112 @@ scanning_changed (NMDeviceIwd *self, gboolean new_scanning) } static void +station_properties_changed (GDBusProxy *proxy, GVariant *changed_properties, + GStrv invalidate_properties, gpointer user_data) +{ + NMDeviceIwd *self = user_data; + GVariantIter *iter; + const char *key; + GVariant *value; + + g_variant_get (changed_properties, "a{sv}", &iter); + while (g_variant_iter_next (iter, "{&sv}", &key, &value)) { + if (!strcmp (key, "State")) + state_changed (self, get_variant_state (value)); + + if (!strcmp (key, "Scanning")) + scanning_changed (self, get_variant_boolean (value, "Scanning")); + + g_variant_unref (value); + } + + g_variant_iter_free (iter); +} + +static void powered_changed (NMDeviceIwd *self, gboolean new_powered) { + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + nm_device_queue_recheck_available (NM_DEVICE (self), NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + + if (new_powered) { + GDBusInterface *interface; + GVariant *value; + + if (priv->dbus_station_proxy) + return; + + interface = g_dbus_object_get_interface (priv->dbus_obj, NM_IWD_STATION_INTERFACE); + if (!interface) { + /* No Station interface on the device object. Check if the + * "State" property is present on the Device interface, that + * would mean we're dealing with an IWD version from before the + * Device/Station split (0.7 or earlier) and we can easily + * handle that by making priv->dbus_device_proxy and + * priv->dbus_station_proxy both point at the Device interface. + */ + value = g_dbus_proxy_get_cached_property (priv->dbus_device_proxy, "State"); + if (!value) { + _LOGE (LOGD_WIFI, "Interface %s not found on obj %s", + NM_IWD_STATION_INTERFACE, + g_dbus_object_get_object_path (priv->dbus_obj)); + return; + } + + g_variant_unref (value); + interface = g_object_ref (priv->dbus_device_proxy); + } + + priv->dbus_station_proxy = G_DBUS_PROXY (interface); + + value = g_dbus_proxy_get_cached_property (priv->dbus_station_proxy, "Scanning"); + priv->scanning = get_variant_boolean (value, "Scanning"); + g_variant_unref (value); + + value = g_dbus_proxy_get_cached_property (priv->dbus_station_proxy, "State"); + state_changed (self, get_variant_state (value)); + g_variant_unref (value); + + g_signal_connect (priv->dbus_station_proxy, "g-properties-changed", + G_CALLBACK (station_properties_changed), self); + + /* Call Disconnect to make sure IWD's autoconnect is disabled. + * Autoconnect is the default state after device is brought UP. + */ + if (priv->enabled) + send_disconnect (self); + } else { + if (!priv->dbus_station_proxy) + return; + + g_signal_handlers_disconnect_by_func (priv->dbus_station_proxy, + station_properties_changed, self); + g_clear_object (&priv->dbus_station_proxy); + + priv->can_scan = FALSE; + priv->scanning = FALSE; + priv->scan_requested = FALSE; + priv->can_connect = FALSE; + cleanup_association_attempt (self, FALSE); + } } static void -properties_changed (GDBusProxy *proxy, GVariant *changed_properties, - GStrv invalidate_properties, gpointer user_data) +device_properties_changed (GDBusProxy *proxy, GVariant *changed_properties, + GStrv invalidate_properties, gpointer user_data) { NMDeviceIwd *self = user_data; GVariantIter *iter; - const gchar *key; + const char *key; GVariant *value; g_variant_get (changed_properties, "a{sv}", &iter); while (g_variant_iter_next (iter, "{&sv}", &key, &value)) { - if (!strcmp (key, "State")) - state_changed (self, g_variant_get_string (value, NULL)); - - if (!strcmp (key, "Scanning")) - scanning_changed (self, g_variant_get_boolean (value)); - if (!strcmp (key, "Powered")) - powered_changed (self, g_variant_get_boolean (value)); + powered_changed (self, get_variant_boolean (value, "Powered")); g_variant_unref (value); } @@ -1800,51 +1929,50 @@ nm_device_iwd_set_dbus_object (NMDeviceIwd *self, GDBusObject *object) NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); GDBusInterface *interface; GVariant *value; + gboolean powered; if (!nm_g_object_ref_set ((GObject **) &priv->dbus_obj, (GObject *) object)) return; - if (priv->dbus_proxy) { - g_signal_handlers_disconnect_by_func (priv->dbus_proxy, - properties_changed, self); - - g_clear_object (&priv->dbus_proxy); - } - - if (priv->enabled) + if (priv->enabled && priv->dbus_station_proxy) { nm_device_queue_recheck_available (NM_DEVICE (self), NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + } - if (!object) { - priv->can_scan = FALSE; + if (priv->dbus_device_proxy) { + g_signal_handlers_disconnect_by_func (priv->dbus_device_proxy, + device_properties_changed, self); + g_clear_object (&priv->dbus_device_proxy); - cleanup_association_attempt (self, FALSE); - return; + powered_changed (self, FALSE); } - interface = g_dbus_object_get_interface (object, NM_IWD_DEVICE_INTERFACE); - priv->dbus_proxy = G_DBUS_PROXY (interface); + if (!object) + return; - value = g_dbus_proxy_get_cached_property (priv->dbus_proxy, "Scanning"); - priv->scanning = g_variant_get_boolean (value); - g_variant_unref (value); - priv->scan_requested = FALSE; + interface = g_dbus_object_get_interface (object, NM_IWD_DEVICE_INTERFACE); + if (!interface) { + _LOGE (LOGD_WIFI, "Interface %s not found on obj %s", + NM_IWD_DEVICE_INTERFACE, + g_dbus_object_get_object_path (object)); + g_clear_object (&priv->dbus_obj); + return; + } - value = g_dbus_proxy_get_cached_property (priv->dbus_proxy, "State"); - state_changed (self, g_variant_get_string (value, NULL)); - g_variant_unref (value); + priv->dbus_device_proxy = G_DBUS_PROXY (interface); - g_signal_connect (priv->dbus_proxy, "g-properties-changed", - G_CALLBACK (properties_changed), self); + g_signal_connect (priv->dbus_device_proxy, "g-properties-changed", + G_CALLBACK (device_properties_changed), self); - set_powered (self, priv->enabled); + value = g_dbus_proxy_get_cached_property (priv->dbus_device_proxy, "Powered"); + powered = get_variant_boolean (value, "Powered"); + g_variant_unref (value); - /* Call Disconnect to make sure IWD's autoconnect is disabled. - * Autoconnect is the default state after device is brought UP. - */ - if (priv->enabled) - send_disconnect (self); + if (powered != priv->enabled) + set_powered (self, priv->enabled); + else if (powered) + powered_changed (self, TRUE); } gboolean @@ -1852,8 +1980,8 @@ nm_device_iwd_agent_query (NMDeviceIwd *self, GDBusMethodInvocation *invocation) { NMActRequest *req; - const gchar *setting_name; - const gchar *setting_key; + const char *setting_name; + const char *setting_key; gboolean replied; NMSecretAgentGetSecretsFlags get_secret_flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; @@ -1937,7 +2065,8 @@ dispose (GObject *object) cleanup_association_attempt (self, TRUE); - g_clear_object (&priv->dbus_proxy); + g_clear_object (&priv->dbus_device_proxy); + g_clear_object (&priv->dbus_station_proxy); g_clear_object (&priv->dbus_obj); remove_all_aps (self); @@ -1952,9 +2081,7 @@ nm_device_iwd_class_init (NMDeviceIwdClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_WIRELESS_SETTING_NAME, NM_LINK_TYPE_WIFI) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->get_property = get_property; object_class->set_property = set_property; @@ -1962,25 +2089,29 @@ nm_device_iwd_class_init (NMDeviceIwdClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&nm_interface_info_device_wireless); - parent_class->can_auto_connect = can_auto_connect; - parent_class->is_available = is_available; - parent_class->get_autoconnect_allowed = get_autoconnect_allowed; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->check_connection_available = check_connection_available; - parent_class->complete_connection = complete_connection; - parent_class->get_enabled = get_enabled; - parent_class->set_enabled = set_enabled; - parent_class->get_type_description = get_type_description; - - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage2_config = act_stage2_config; - parent_class->get_configured_mtu = get_configured_mtu; - parent_class->deactivate = deactivate; - parent_class->deactivate_async = deactivate_async; - parent_class->deactivate_async_finish = deactivate_async_finish; - parent_class->can_reapply_change = can_reapply_change; - - parent_class->state_changed = device_state_changed; + device_class->connection_type_supported = NM_SETTING_WIRELESS_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_WIRELESS_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_WIFI); + + device_class->can_auto_connect = can_auto_connect; + device_class->is_available = is_available; + device_class->get_autoconnect_allowed = get_autoconnect_allowed; + device_class->check_connection_compatible = check_connection_compatible; + device_class->check_connection_available = check_connection_available; + device_class->complete_connection = complete_connection; + device_class->get_enabled = get_enabled; + device_class->set_enabled = set_enabled; + device_class->get_type_description = get_type_description; + + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->get_configured_mtu = get_configured_mtu; + device_class->deactivate = deactivate; + device_class->deactivate_async = deactivate_async; + device_class->deactivate_async_finish = deactivate_async_finish; + device_class->can_reapply_change = can_reapply_change; + + device_class->state_changed = device_state_changed; klass->scanning_prohibited = scanning_prohibited; diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c index fd7bf3f7..9ae81139 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.c +++ b/src/devices/wifi/nm-device-olpc-mesh.c @@ -80,28 +80,6 @@ G_DEFINE_TYPE (NMDeviceOlpcMesh, nm_device_olpc_mesh, NM_TYPE_DEVICE) /*****************************************************************************/ static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingConnection *s_con; - NMSettingOlpcMesh *s_mesh; - - if (!NM_DEVICE_CLASS (nm_device_olpc_mesh_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_OLPC_MESH_SETTING_NAME)) - return FALSE; - - s_mesh = nm_connection_get_setting_olpc_mesh (connection); - if (!s_mesh) - return FALSE; - - return TRUE; -} - -static gboolean get_autoconnect_allowed (NMDevice *device) { return FALSE; @@ -117,7 +95,6 @@ complete_connection (NMDevice *device, GError **error) { NMSettingOlpcMesh *s_mesh; - GByteArray *tmp; s_mesh = nm_connection_get_setting_olpc_mesh (connection); if (!s_mesh) { @@ -126,10 +103,10 @@ complete_connection (NMDevice *device, } if (!nm_setting_olpc_mesh_get_ssid (s_mesh)) { - tmp = g_byte_array_sized_new (strlen (DEFAULT_SSID)); - g_byte_array_append (tmp, (const guint8 *) DEFAULT_SSID, strlen (DEFAULT_SSID)); - g_object_set (G_OBJECT (s_mesh), NM_SETTING_OLPC_MESH_SSID, tmp, NULL); - g_byte_array_free (tmp, TRUE); + gs_unref_bytes GBytes *ssid = NULL; + + ssid = g_bytes_new_static (DEFAULT_SSID, NM_STRLEN (DEFAULT_SSID)); + g_object_set (G_OBJECT (s_mesh), NM_SETTING_OLPC_MESH_SSID, ssid, NULL); } if (!nm_setting_olpc_mesh_get_dhcp_anycast_address (s_mesh)) { @@ -302,7 +279,7 @@ companion_state_changed_cb (NMDeviceWifi *companion, } static gboolean -companion_scan_prohibited_cb (NMDeviceWifi *companion, gpointer user_data) +companion_scan_prohibited_cb (NMDeviceWifi *companion, gboolean periodic, gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); NMDeviceState state = nm_device_get_state (NM_DEVICE (self)); @@ -369,7 +346,7 @@ device_added_cb (NMManager *manager, NMDevice *other, gpointer user_data) nm_device_queue_recheck_available (NM_DEVICE (self), NM_DEVICE_STATE_REASON_NONE, NM_DEVICE_STATE_REASON_NONE); - nm_device_remove_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_COMPANION, TRUE); + nm_device_remove_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_COMPANION, FALSE); } } @@ -515,9 +492,7 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_OLPC_MESH_SETTING_NAME, NM_LINK_TYPE_OLPC_MESH) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructed = constructed; object_class->get_property = get_property; @@ -525,14 +500,17 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_olpc_mesh); - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->get_autoconnect_allowed = get_autoconnect_allowed; - parent_class->complete_connection = complete_connection; - parent_class->is_available = is_available; - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage2_config = act_stage2_config; - parent_class->state_changed = state_changed; - parent_class->get_dhcp_timeout = get_dhcp_timeout; + device_class->connection_type_supported = NM_SETTING_OLPC_MESH_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_OLPC_MESH_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_OLPC_MESH); + + device_class->get_autoconnect_allowed = get_autoconnect_allowed; + device_class->complete_connection = complete_connection; + device_class->is_available = is_available; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->state_changed = state_changed; + device_class->get_dhcp_timeout = get_dhcp_timeout; obj_properties[PROP_COMPANION] = g_param_spec_string (NM_DEVICE_OLPC_MESH_COMPANION, "", "", diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 0dd6fa74..2ce84618 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -96,6 +96,7 @@ typedef struct { bool requested_scan:1; bool ssid_found:1; bool is_scanning:1; + bool hidden_probe_scan_warn:1; gint64 last_scan; /* milliseconds */ gint32 scheduled_scan_time; /* seconds */ @@ -121,6 +122,8 @@ typedef struct { gint32 hw_addr_scan_expire; guint wps_timeout_id; + + NMSettingWirelessWakeOnWLan wowlan_restore; } NMDeviceWifiPrivate; struct _NMDeviceWifi @@ -436,7 +439,7 @@ periodic_update (NMDeviceWifi *self) percent = nm_platform_wifi_get_quality (nm_device_get_platform (NM_DEVICE (self)), ifindex); if (percent >= 0 || ++priv->invalid_strength_counter > 3) { if (nm_wifi_ap_set_strength (priv->current_ap, (gint8) percent)) { -#ifdef NM_MORE_LOGGING +#if NM_MORE_LOGGING _ap_dump (self, LOGL_TRACE, priv->current_ap, "updated", 0); #endif } @@ -508,6 +511,22 @@ remove_all_aps (NMDeviceWifi *self) nm_device_recheck_available_connections (NM_DEVICE (self)); } +static gboolean +wake_on_wlan_restore (NMDeviceWifi *self) +{ + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + NMSettingWirelessWakeOnWLan w; + + w = priv->wowlan_restore; + if (w == NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) + return TRUE; + + priv->wowlan_restore = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; + return nm_platform_wifi_set_wake_on_wlan (NM_PLATFORM_GET, + nm_device_get_ifindex (NM_DEVICE (self)), + w); +} + static void deactivate (NMDevice *device) { @@ -524,6 +543,9 @@ deactivate (NMDevice *device) set_current_ap (self, NULL, TRUE); + if (!wake_on_wlan_restore (self)) + _LOGW (LOGD_DEVICE | LOGD_WIFI, "Cannot unconfigure WoWLAN."); + /* Clear any critical protocol notification in the Wi-Fi stack */ nm_platform_wifi_indicate_addressing_running (nm_device_get_platform (device), ifindex, FALSE); @@ -583,11 +605,10 @@ is_adhoc_wpa (NMConnection *connection) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - NMSettingConnection *s_con; NMSettingWireless *s_wireless; const char *mac; const char * const *mac_blacklist; @@ -595,24 +616,19 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) const char *mode; const char *perm_hw_addr; - if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_WIRELESS_SETTING_NAME)) + if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; s_wireless = nm_connection_get_setting_wireless (connection); - if (!s_wireless) - return FALSE; perm_hw_addr = nm_device_get_permanent_hw_address (device); mac = nm_setting_wireless_get_mac_address (s_wireless); if (perm_hw_addr) { - if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) + if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device MAC address does not match the profile"); return FALSE; + } /* Check for MAC address blacklist */ mac_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); @@ -622,27 +638,45 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return FALSE; } - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) + if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "MAC address blacklisted"); return FALSE; + } } - } else if (mac) + } else if (mac) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has no valid MAC address as required by profile"); return FALSE; + } - if (is_adhoc_wpa (connection)) + if (is_adhoc_wpa (connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "Ad-Hoc WPA networks are not supported"); return FALSE; + } /* Early exit if supplicant or device doesn't support requested mode */ mode = nm_setting_wireless_get_mode (s_wireless); if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC) == 0) { - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_ADHOC)) + if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_ADHOC)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "the device does not support Ad-Hoc networks"); return FALSE; + } } else if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_AP) == 0) { - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_AP)) + if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_AP)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "the device does not support Access Point mode"); return FALSE; + } if (priv->sup_iface) { - if (nm_supplicant_interface_get_ap_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_NO) + if (nm_supplicant_interface_get_ap_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_NO) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "wpa_supplicant does not support Access Point mode"); return FALSE; + } } } @@ -657,7 +691,8 @@ static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); @@ -674,7 +709,17 @@ check_connection_available (NMDevice *device, NMWifiAP *ap; ap = nm_wifi_ap_lookup_for_device (NM_DEVICE (self), specific_object); - return ap ? nm_wifi_ap_check_compatible (ap, connection) : FALSE; + if (!ap) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "requested access point not found"); + return FALSE; + } + if (!nm_wifi_ap_check_compatible (ap, connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "requested access point is not compatible with profile"); + return FALSE; + } + return TRUE; } /* Ad-Hoc and AP connections are always available because they may be @@ -693,11 +738,17 @@ check_connection_available (NMDevice *device, * activating but the network isn't available let the device recheck * availability. */ - if (nm_setting_wireless_get_hidden (s_wifi) || NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) + if ( nm_setting_wireless_get_hidden (s_wifi) + || NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) return TRUE; - /* check at least one AP is compatible with this connection */ - return !!nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection); + if (!nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "no compatible access point found"); + return FALSE; + } + + return TRUE; } static gboolean @@ -711,10 +762,9 @@ complete_connection (NMDevice *device, NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMSettingWireless *s_wifi; const char *setting_mac; - char *str_ssid = NULL; + gs_free char *ssid_utf8 = NULL; NMWifiAP *ap; - const GByteArray *ssid = NULL; - GByteArray *tmp_ssid = NULL; + GBytes *ssid = NULL; GBytes *setting_ssid = NULL; gboolean hidden = FALSE; const char *perm_hw_addr; @@ -786,19 +836,14 @@ complete_connection (NMDevice *device, if (ap) ssid = nm_wifi_ap_get_ssid (ap); + if (ssid == NULL) { /* The AP must be hidden. Connecting to a WiFi AP requires the SSID * as part of the initial handshake, so check the connection details * for the SSID. The AP object will still be used for encryption * settings and such. */ - setting_ssid = nm_setting_wireless_get_ssid (s_wifi); - if (setting_ssid) { - ssid = tmp_ssid = g_byte_array_new (); - g_byte_array_append (tmp_ssid, - g_bytes_get_data (setting_ssid, NULL), - g_bytes_get_size (setting_ssid)); - } + ssid = nm_setting_wireless_get_ssid (s_wifi); } if (ssid == NULL) { @@ -821,11 +866,8 @@ complete_connection (NMDevice *device, if (!nm_wifi_ap_complete_connection (ap, connection, nm_wifi_utils_is_manf_default_ssid (ssid), - error)) { - if (tmp_ssid) - g_byte_array_unref (tmp_ssid); + error)) return FALSE; - } } /* The kernel doesn't support Ad-Hoc WPA connections well at this time, @@ -838,24 +880,18 @@ complete_connection (NMDevice *device, NM_CONNECTION_ERROR_INVALID_SETTING, _("WPA Ad-Hoc disabled due to kernel bugs")); g_prefix_error (error, "%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME); - if (tmp_ssid) - g_byte_array_unref (tmp_ssid); return FALSE; } - str_ssid = nm_utils_ssid_to_utf8 (ssid->data, ssid->len); - + ssid_utf8 = _nm_utils_ssid_to_utf8 (ssid); nm_utils_complete_generic (nm_device_get_platform (device), connection, NM_SETTING_WIRELESS_SETTING_NAME, existing_connections, - str_ssid, - str_ssid, + ssid_utf8, + ssid_utf8, NULL, TRUE); - g_free (str_ssid); - if (tmp_ssid) - g_byte_array_unref (tmp_ssid); if (hidden) g_object_set (s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); @@ -923,11 +959,12 @@ get_autoconnect_allowed (NMDevice *device) static gboolean can_auto_connect (NMDevice *device, - NMConnection *connection, + NMSettingsConnection *sett_conn, char **specific_object) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + NMConnection *connection; NMSettingWireless *s_wifi; NMWifiAP *ap; const char *method, *mode; @@ -935,26 +972,28 @@ can_auto_connect (NMDevice *device, nm_assert (!specific_object || !*specific_object); - if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->can_auto_connect (device, connection, NULL)) + if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->can_auto_connect (device, sett_conn, NULL)) return FALSE; + connection = nm_settings_connection_get_connection (sett_conn); + s_wifi = nm_connection_get_setting_wireless (connection); g_return_val_if_fail (s_wifi, FALSE); /* Always allow autoconnect for AP and non-autoconf Ad-Hoc */ method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); mode = nm_setting_wireless_get_mode (s_wifi); - if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_AP) == 0) + if (nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_AP)) return TRUE; - else if ( g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC) == 0 - && g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) != 0) + else if ( nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC) + && !nm_streq0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) return TRUE; /* Don't autoconnect to networks that have been tried at least once * but haven't been successful, since these are often accidental choices * from the menu and the user may not know the password. */ - if (nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (connection), ×tamp)) { + if (nm_settings_connection_get_timestamp (sett_conn, ×tamp)) { if (timestamp == 0) return FALSE; } @@ -1033,7 +1072,6 @@ static GPtrArray * ssids_options_to_ptrarray (GVariant *value, GError **error) { GPtrArray *ssids = NULL; - GByteArray *ssid_array; GVariant *v; const guint8 *bytes; gsize len; @@ -1049,7 +1087,7 @@ ssids_options_to_ptrarray (GVariant *value, GError **error) } if (num_ssids) { - ssids = g_ptr_array_new_full (num_ssids, (GDestroyNotify) g_byte_array_unref); + ssids = g_ptr_array_new_full (num_ssids, (GDestroyNotify) g_bytes_unref); for (i = 0; i < num_ssids; i++) { v = g_variant_get_child_value (value, i); bytes = g_variant_get_fixed_array (v, &len, sizeof (guint8)); @@ -1062,9 +1100,7 @@ ssids_options_to_ptrarray (GVariant *value, GError **error) return NULL; } - ssid_array = g_byte_array_new (); - g_byte_array_append (ssid_array, bytes, len); - g_ptr_array_add (ssids, ssid_array); + g_ptr_array_add (ssids, g_bytes_new (bytes, len)); } } return ssids; @@ -1232,14 +1268,15 @@ check_scanning_prohibited (NMDeviceWifi *self, gboolean periodic) static gboolean hidden_filter_func (NMSettings *settings, - NMSettingsConnection *connection, + NMSettingsConnection *set_con, gpointer user_data) { + NMConnection *connection = nm_settings_connection_get_connection (set_con); NMSettingWireless *s_wifi; - if (!nm_connection_is_type (NM_CONNECTION (connection), NM_SETTING_WIRELESS_SETTING_NAME)) + if (!nm_connection_is_type (connection, NM_SETTING_WIRELESS_SETTING_NAME)) return FALSE; - s_wifi = nm_connection_get_setting_wireless (NM_CONNECTION (connection)); + s_wifi = nm_connection_get_setting_wireless (connection); if (!s_wifi) return FALSE; if (nm_streq0 (nm_setting_wireless_get_mode (s_wifi), NM_SETTING_WIRELESS_MODE_AP)) @@ -1255,7 +1292,7 @@ build_hidden_probe_list (NMDeviceWifi *self) gs_free NMSettingsConnection **connections = NULL; guint i, len; GPtrArray *ssids = NULL; - static GByteArray *nullssid = NULL; + static GBytes *nullssid = NULL; /* Need at least two: wildcard SSID and one or more hidden SSIDs */ if (max_scan_ssids < 2) @@ -1270,30 +1307,23 @@ build_hidden_probe_list (NMDeviceWifi *self) g_qsort_with_data (connections, len, sizeof (NMSettingsConnection *), nm_settings_connection_cmp_timestamp_p_with_data, NULL); - ssids = g_ptr_array_new_full (max_scan_ssids, (GDestroyNotify) g_byte_array_unref); + ssids = g_ptr_array_new_full (max_scan_ssids, (GDestroyNotify) g_bytes_unref); /* Add wildcard SSID using a static wildcard SSID used for every scan */ if (G_UNLIKELY (nullssid == NULL)) - nullssid = g_byte_array_new (); - g_ptr_array_add (ssids, g_byte_array_ref (nullssid)); + nullssid = g_bytes_new_static ("", 0); + g_ptr_array_add (ssids, g_bytes_ref (nullssid)); for (i = 0; connections[i]; i++) { NMSettingWireless *s_wifi; GBytes *ssid; - GByteArray *ssid_array; if (i >= max_scan_ssids - 1) break; - s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (NM_CONNECTION (connections[i])); - g_assert (s_wifi); + s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (nm_settings_connection_get_connection (connections[i])); ssid = nm_setting_wireless_get_ssid (s_wifi); - g_assert (ssid); - ssid_array = g_byte_array_new (); - g_byte_array_append (ssid_array, - g_bytes_get_data (ssid, NULL), - g_bytes_get_size (ssid)); - g_ptr_array_add (ssids, ssid_array); + g_ptr_array_add (ssids, g_bytes_ref (ssid)); } return ssids; @@ -1321,23 +1351,30 @@ request_wireless_scan (NMDeviceWifi *self, _LOGD (LOGD_WIFI, "wifi-scan: scanning requested"); if (!ssids) { - ssids = hidden_ssids = build_hidden_probe_list (self); + hidden_ssids = build_hidden_probe_list (self); + if (hidden_ssids) { + if (priv->hidden_probe_scan_warn) { + priv->hidden_probe_scan_warn = FALSE; + _LOGW (LOGD_WIFI, "wifi-scan: active scanning for networks due to profiles with wifi.hidden=yes. This makes you trackable"); + } + ssids = hidden_ssids; + } else + priv->hidden_probe_scan_warn = TRUE; } if (_LOGD_ENABLED (LOGD_WIFI)) { if (ssids) { - const GByteArray *ssid; guint i; - char *foo; for (i = 0; i < ssids->len; i++) { - ssid = g_ptr_array_index (ssids, i); - foo = ssid->len > 0 - ? nm_utils_ssid_to_utf8 (ssid->data, ssid->len) - : NULL; - _LOGD (LOGD_WIFI, "wifi-scan: (%u) probe scanning SSID %s%s%s", - i, NM_PRINT_FMT_QUOTED (foo, "\"", foo, "\"", "*any*")); - g_free (foo); + gs_free char *ssid_str = NULL; + GBytes *ssid = ssids->pdata[i]; + + ssid_str = g_bytes_get_size (ssid) > 0 + ? _nm_utils_ssid_to_string (ssid) + : NULL; + _LOGD (LOGD_WIFI, "wifi-scan: (%u) probe scanning SSID %s", + i, ssid_str ?: "*any*"); } } else _LOGD (LOGD_WIFI, "wifi-scan: no SSIDs to probe scan"); @@ -1345,7 +1382,9 @@ request_wireless_scan (NMDeviceWifi *self, _hw_addr_set_scanning (self, FALSE); - nm_supplicant_interface_request_scan (priv->sup_iface, ssids); + nm_supplicant_interface_request_scan (priv->sup_iface, + ssids ? (GBytes *const*) ssids->pdata : NULL, + ssids ? ssids->len : 0u); request_started = TRUE; } else _LOGD (LOGD_WIFI, "wifi-scan: scanning requested but not allowed at this time"); @@ -1484,17 +1523,13 @@ try_fill_ssid_for_hidden_ap (NMDeviceWifi *self, * and if a match is found, copy over the SSID */ connections = nm_settings_get_connections (nm_device_get_settings ((NMDevice *) self), NULL); for (i = 0; connections[i]; i++) { - NMConnection *connection = (NMConnection *) connections[i]; + NMSettingsConnection *sett_conn = connections[i]; NMSettingWireless *s_wifi; - s_wifi = nm_connection_get_setting_wireless (connection); + s_wifi = nm_connection_get_setting_wireless (nm_settings_connection_get_connection (sett_conn)); if (s_wifi) { - if (nm_settings_connection_has_seen_bssid (NM_SETTINGS_CONNECTION (connection), bssid)) { - GBytes *ssid = nm_setting_wireless_get_ssid (s_wifi); - - nm_wifi_ap_set_ssid (ap, - g_bytes_get_data (ssid, NULL), - g_bytes_get_size (ssid)); + if (nm_settings_connection_has_seen_bssid (sett_conn, bssid)) { + nm_wifi_ap_set_ssid (ap, nm_setting_wireless_get_ssid (s_wifi)); break; } } @@ -1510,7 +1545,7 @@ supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMDeviceState state; NMWifiAP *found_ap = NULL; - const GByteArray *ssid; + GBytes *ssid; g_return_if_fail (self != NULL); g_return_if_fail (properties != NULL); @@ -1539,15 +1574,19 @@ supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, /* Let the manager try to fill in the SSID from seen-bssids lists */ ssid = nm_wifi_ap_get_ssid (ap); - if (!ssid || nm_utils_is_empty_ssid (ssid->data, ssid->len)) { + if (!ssid || _nm_utils_is_empty_ssid (ssid)) { /* Try to fill the SSID from the AP database */ try_fill_ssid_for_hidden_ap (self, ap); ssid = nm_wifi_ap_get_ssid (ap); - if (ssid && (nm_utils_is_empty_ssid (ssid->data, ssid->len) == FALSE)) { + if ( ssid + && !_nm_utils_is_empty_ssid (ssid)) { + gs_free char *s = NULL; + /* Yay, matched it, no longer treat as hidden */ - _LOGD (LOGD_WIFI, "matched hidden AP %s => '%s'", - nm_wifi_ap_get_address (ap), nm_utils_escape_ssid (ssid->data, ssid->len)); + _LOGD (LOGD_WIFI, "matched hidden AP %s => %s", + nm_wifi_ap_get_address (ap), + (s = _nm_utils_ssid_to_string (ssid))); } else { /* Didn't have an entry for this AP in the database */ _LOGD (LOGD_WIFI, "failed to match hidden AP %s", @@ -1859,7 +1898,7 @@ need_new_8021x_secrets (NMDeviceWifi *self, static gboolean need_new_wpa_psk (NMDeviceWifi *self, NMSupplicantInterfaceState old_state, - gint disconnect_reason, + int disconnect_reason, const char **setting_name) { NMSettingWirelessSecurity *s_wsec; @@ -2004,6 +2043,7 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, NMConnection *connection; NMSettingWireless *s_wifi; GBytes *ssid; + gs_free char *ssid_str = NULL; connection = nm_device_get_applied_connection (NM_DEVICE (self)); g_return_if_fail (connection); @@ -2015,11 +2055,11 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, g_return_if_fail (ssid); _LOGI (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) Stage 2 of 5 (Device Configure) successful. %s '%s'.", - priv->mode == NM_802_11_MODE_AP ? "Started Wi-Fi Hotspot" : - "Connected to wireless network", - ssid ? nm_utils_escape_ssid (g_bytes_get_data (ssid, NULL), - g_bytes_get_size (ssid)) : "(none)"); + "Activation: (wifi) Stage 2 of 5 (Device Configure) successful. %s %s", + priv->mode == NM_802_11_MODE_AP + ? "Started Wi-Fi Hotspot" + : "Connected to wireless network", + (ssid_str = _nm_utils_ssid_to_string (ssid))); nm_device_activate_schedule_stage3_ip_config_start (device); } else if (devstate == NM_DEVICE_STATE_ACTIVATED) periodic_update (self); @@ -2127,9 +2167,11 @@ supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, if (new_ap != priv->current_ap) { const char *new_bssid = NULL; - const GByteArray *new_ssid = NULL; + GBytes *new_ssid = NULL; const char *old_bssid = NULL; - const GByteArray *old_ssid = NULL; + GBytes *old_ssid = NULL; + gs_free char *new_ssid_s = NULL; + gs_free char *old_ssid_s = NULL; /* Don't ever replace a "fake" current AP if we don't know about the * supplicant's current BSS yet. It'll get replaced when we receive @@ -2150,9 +2192,9 @@ supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, _LOGD (LOGD_WIFI, "roamed from BSSID %s (%s) to %s (%s)", old_bssid ?: "(none)", - old_ssid ? nm_utils_escape_ssid (old_ssid->data, old_ssid->len) : "(none)", + (old_ssid_s = _nm_utils_ssid_to_string (old_ssid)), new_bssid ?: "(none)", - new_ssid ? nm_utils_escape_ssid (new_ssid->data, new_ssid->len) : "(none)"); + (new_ssid_s = _nm_utils_ssid_to_string (new_ssid))); set_current_ap (self, new_ap, TRUE); } @@ -2332,7 +2374,6 @@ build_supplicant_config (NMDeviceWifi *self, NMSettingWirelessSecurity *s_wireless_sec; NMSettingWirelessSecurityPmf pmf; NMSettingWirelessSecurityFils fils; - gs_free char *value = NULL; g_return_val_if_fail (priv->sup_iface, NULL); @@ -2374,25 +2415,23 @@ build_supplicant_config (NMDeviceWifi *self, /* Configure PMF (802.11w) */ pmf = nm_setting_wireless_security_get_pmf (s_wireless_sec); if (pmf == NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT) { - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "wifi-sec.pmf", - NM_DEVICE (self)); - pmf = _nm_utils_ascii_str_to_int64 (value, 10, - NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE, - NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED, - NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL); + pmf = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "wifi-sec.pmf", + NM_DEVICE (self), + NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE, + NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED, + NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL); } /* Configure FILS (802.11ai) */ fils = nm_setting_wireless_security_get_fils (s_wireless_sec); if (fils == NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT) { - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "wifi-sec.fils", - NM_DEVICE (self)); - fils = _nm_utils_ascii_str_to_int64 (value, 10, - NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE, - NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED, - NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL); + fils = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "wifi-sec.fils", + NM_DEVICE (self), + NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE, + NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED, + NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL); } s_8021x = nm_connection_get_setting_802_1x (connection); @@ -2426,9 +2465,9 @@ error: static gboolean wake_on_wlan_enable (NMDeviceWifi *self) { + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMSettingWirelessWakeOnWLan wowl; NMSettingWireless *s_wireless; - gs_free char *value = NULL; s_wireless = (NMSettingWireless *) nm_device_get_applied_setting (NM_DEVICE (self), NM_TYPE_SETTING_WIRELESS); if (s_wireless) { @@ -2437,32 +2476,39 @@ wake_on_wlan_enable (NMDeviceWifi *self) goto found; } - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "wifi.wake-on-wlan", - NM_DEVICE (self)); - - if (value) { - wowl = _nm_utils_ascii_str_to_int64 (value, 10, - NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE, - G_MAXINT32, - NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT); + wowl = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "wifi.wake-on-wlan", + NM_DEVICE (self), + NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE, + G_MAXINT32, + NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT); - if (NM_FLAGS_ANY (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_EXCLUSIVE_FLAGS)) { - if (!nm_utils_is_power_of_two (wowl)) { - _LOGD (LOGD_WIFI, "invalid default value %u for wake-on-wlan: " - "'default' and 'ignore' are exclusive flags", (guint) wowl); - wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT; - } - } else if (NM_FLAGS_ANY (wowl, ~NM_SETTING_WIRELESS_WAKE_ON_WLAN_ALL)) { - _LOGD (LOGD_WIFI, "invalid default value %u for wake-on-wlan", (guint) wowl); + if (NM_FLAGS_ANY (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_EXCLUSIVE_FLAGS)) { + if (!nm_utils_is_power_of_two (wowl)) { + _LOGD (LOGD_WIFI, "invalid default value %u for wake-on-wlan: " + "'default' and 'ignore' are exclusive flags", (guint) wowl); wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT; } - if (wowl != NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT) - goto found; + } else if (NM_FLAGS_ANY (wowl, ~NM_SETTING_WIRELESS_WAKE_ON_WLAN_ALL)) { + _LOGD (LOGD_WIFI, "invalid default value %u for wake-on-wlan", (guint) wowl); + wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT; } + if (wowl != NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT) + goto found; + wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; found: - return nm_platform_wifi_set_wake_on_wlan (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), wowl); + if (wowl == NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) { + priv->wowlan_restore = wowl; + return TRUE; + } + + priv->wowlan_restore = nm_platform_wifi_get_wake_on_wlan (NM_PLATFORM_GET, + nm_device_get_ifindex (NM_DEVICE (self))); + + return nm_platform_wifi_set_wake_on_wlan (NM_PLATFORM_GET, + nm_device_get_ifindex (NM_DEVICE (self)), + wowl); } static NMActStageReturn @@ -2598,31 +2644,29 @@ set_powersave (NMDevice *device) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMSettingWireless *s_wireless; - NMSettingWirelessPowersave powersave; - gs_free char *value = NULL; + NMSettingWirelessPowersave val; s_wireless = (NMSettingWireless *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRELESS); g_return_if_fail (s_wireless); - powersave = nm_setting_wireless_get_powersave (s_wireless); - if (powersave == NM_SETTING_WIRELESS_POWERSAVE_DEFAULT) { - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "wifi.powersave", - device); - powersave = _nm_utils_ascii_str_to_int64 (value, 10, - NM_SETTING_WIRELESS_POWERSAVE_IGNORE, - NM_SETTING_WIRELESS_POWERSAVE_ENABLE, - NM_SETTING_WIRELESS_POWERSAVE_IGNORE); + val = nm_setting_wireless_get_powersave (s_wireless); + if (val == NM_SETTING_WIRELESS_POWERSAVE_DEFAULT) { + val = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "wifi.powersave", + device, + NM_SETTING_WIRELESS_POWERSAVE_IGNORE, + NM_SETTING_WIRELESS_POWERSAVE_ENABLE, + NM_SETTING_WIRELESS_POWERSAVE_IGNORE); } - _LOGT (LOGD_WIFI, "powersave is set to %u", (unsigned) powersave); + _LOGT (LOGD_WIFI, "powersave is set to %u", (unsigned) val); - if (powersave == NM_SETTING_WIRELESS_POWERSAVE_IGNORE) + if (val == NM_SETTING_WIRELESS_POWERSAVE_IGNORE) return; nm_platform_wifi_set_powersave (nm_device_get_platform (device), nm_device_get_ifindex (device), - powersave == NM_SETTING_WIRELESS_POWERSAVE_ENABLE); + val == NM_SETTING_WIRELESS_POWERSAVE_ENABLE); } static NMActStageReturn @@ -2659,8 +2703,6 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) s_wireless = nm_connection_get_setting_wireless (connection); g_assert (s_wireless); - wake_on_wlan_enable (self); - /* If we need secrets, get them */ setting_name = nm_connection_need_secrets (connection, NULL); if (setting_name) { @@ -2677,6 +2719,9 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) goto out; } + if (!wake_on_wlan_enable (self)) + _LOGW (LOGD_DEVICE | LOGD_WIFI, "Cannot configure WoWLAN."); + /* have secrets, or no secrets required */ if (nm_connection_get_setting_wireless_security (connection)) { _LOGI (LOGD_DEVICE | LOGD_WIFI, @@ -2727,8 +2772,10 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) ret = NM_ACT_STAGE_RETURN_POSTPONE; out: - if (ret == NM_ACT_STAGE_RETURN_FAILURE) + if (ret == NM_ACT_STAGE_RETURN_FAILURE) { cleanup_association_attempt (self, TRUE); + wake_on_wlan_restore (self); + } if (config) { /* Supplicant interface object refs the config; we no longer care about @@ -3134,7 +3181,8 @@ reapply_connection (NMDevice *device, NMConnection *con_old, NMConnection *con_n _LOGD (LOGD_DEVICE, "reapplying wireless settings"); - wake_on_wlan_enable (self); + if (!wake_on_wlan_enable (self)) + _LOGW (LOGD_DEVICE | LOGD_WIFI, "Cannot configure WoWLAN."); } /*****************************************************************************/ @@ -3206,7 +3254,9 @@ nm_device_wifi_init (NMDeviceWifi *self) c_list_init (&priv->aps_lst_head); + priv->hidden_probe_scan_warn = TRUE; priv->mode = NM_802_11_MODE_INFRA; + priv->wowlan_restore = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; } static void @@ -3274,9 +3324,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); - NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_WIRELESS_SETTING_NAME, NM_LINK_TYPE_WIFI) + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); object_class->constructed = constructed; object_class->get_property = get_property; @@ -3286,29 +3334,33 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&nm_interface_info_device_wireless); - parent_class->can_auto_connect = can_auto_connect; - parent_class->get_autoconnect_allowed = get_autoconnect_allowed; - parent_class->is_available = is_available; - parent_class->check_connection_compatible = check_connection_compatible; - parent_class->check_connection_available = check_connection_available; - parent_class->complete_connection = complete_connection; - parent_class->get_enabled = get_enabled; - parent_class->set_enabled = set_enabled; - - parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage2_config = act_stage2_config; - parent_class->get_configured_mtu = get_configured_mtu; - parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - parent_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; - parent_class->act_stage4_ip4_config_timeout = act_stage4_ip4_config_timeout; - parent_class->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout; - parent_class->deactivate = deactivate; - parent_class->deactivate_reset_hw_addr = deactivate_reset_hw_addr; - parent_class->unmanaged_on_quit = unmanaged_on_quit; - parent_class->can_reapply_change = can_reapply_change; - parent_class->reapply_connection = reapply_connection; - - parent_class->state_changed = device_state_changed; + device_class->connection_type_supported = NM_SETTING_WIRELESS_SETTING_NAME; + device_class->connection_type_check_compatible = NM_SETTING_WIRELESS_SETTING_NAME; + device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_WIFI); + + device_class->can_auto_connect = can_auto_connect; + device_class->get_autoconnect_allowed = get_autoconnect_allowed; + device_class->is_available = is_available; + device_class->check_connection_compatible = check_connection_compatible; + device_class->check_connection_available = check_connection_available; + device_class->complete_connection = complete_connection; + device_class->get_enabled = get_enabled; + device_class->set_enabled = set_enabled; + + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->act_stage2_config = act_stage2_config; + device_class->get_configured_mtu = get_configured_mtu; + device_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; + device_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; + device_class->act_stage4_ip4_config_timeout = act_stage4_ip4_config_timeout; + device_class->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout; + device_class->deactivate = deactivate; + device_class->deactivate_reset_hw_addr = deactivate_reset_hw_addr; + device_class->unmanaged_on_quit = unmanaged_on_quit; + device_class->can_reapply_change = can_reapply_change; + device_class->reapply_connection = reapply_connection; + + device_class->state_changed = device_state_changed; klass->scanning_prohibited = scanning_prohibited; diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c index d6511296..a3da9791 100644 --- a/src/devices/wifi/nm-iwd-manager.c +++ b/src/devices/wifi/nm-iwd-manager.c @@ -29,13 +29,21 @@ #include "nm-core-internal.h" #include "nm-manager.h" #include "nm-device-iwd.h" +#include "nm-wifi-utils.h" #include "nm-utils/nm-random-utils.h" +#include "settings/nm-settings.h" /*****************************************************************************/ typedef struct { - gchar *name; + const char *name; NMIwdNetworkSecurity security; + char buf[0]; +} KnownNetworkId; + +typedef struct { + GDBusProxy *known_network; + NMSettingsConnection *mirror_connection; } KnownNetworkData; typedef struct { @@ -44,8 +52,8 @@ typedef struct { gboolean running; GDBusObjectManager *object_manager; guint agent_id; - gchar *agent_path; - GSList *known_networks; + char *agent_path; + GHashTable *known_networks; } NMIwdManagerPrivate; struct _NMIwdManager { @@ -83,20 +91,49 @@ G_DEFINE_TYPE (NMIwdManager, nm_iwd_manager, G_TYPE_OBJECT) /*****************************************************************************/ +static void mirror_8021x_connection_take_and_delete (NMSettingsConnection *sett_conn); + +/*****************************************************************************/ + +static const char * +get_variant_string_or_null (GVariant *v) +{ + if (!v) + return NULL; + + if ( !g_variant_is_of_type (v, G_VARIANT_TYPE_STRING) + && !g_variant_is_of_type (v, G_VARIANT_TYPE_OBJECT_PATH)) + return NULL; + + return g_variant_get_string (v, NULL); +} + +static const char * +get_property_string_or_null (GDBusProxy *proxy, const char *property) +{ + gs_unref_variant GVariant *value = NULL; + + if (!proxy || !property) + return NULL; + + value = g_dbus_proxy_get_cached_property (proxy, property); + + return get_variant_string_or_null (value); +} + static void agent_dbus_method_cb (GDBusConnection *connection, - const gchar *sender, const gchar *object_path, - const gchar *interface_name, const gchar *method_name, + const char *sender, const char *object_path, + const char *interface_name, const char *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data) { NMIwdManager *self = user_data; NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - const gchar *network_path, *device_path, *ifname; + const char *network_path, *device_path, *ifname; gs_unref_object GDBusInterface *network = NULL, *device_obj = NULL; - gs_unref_variant GVariant *value = NULL; - gint ifindex; + int ifindex; NMDevice *device; gs_free char *name_owner = NULL; @@ -113,9 +150,8 @@ agent_dbus_method_cb (GDBusConnection *connection, network = g_dbus_object_manager_get_interface (priv->object_manager, network_path, NM_IWD_NETWORK_INTERFACE); - value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (network), "Device"); - device_path = g_variant_get_string (value, NULL); + device_path = get_property_string_or_null (G_DBUS_PROXY (network), "Device"); if (!device_path) { _LOGD ("agent-request: device not cached for network %s in IWD Agent request", network_path); @@ -125,10 +161,8 @@ agent_dbus_method_cb (GDBusConnection *connection, device_obj = g_dbus_object_manager_get_interface (priv->object_manager, device_path, NM_IWD_DEVICE_INTERFACE); - g_variant_unref (value); - value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (device_obj), "Name"); - ifname = g_variant_get_string (value, NULL); + ifname = get_property_string_or_null (G_DBUS_PROXY (device_obj), "Name"); if (!ifname) { _LOGD ("agent-request: name not cached for device %s in IWD Agent request", device_path); @@ -207,12 +241,12 @@ static const GDBusInterfaceInfo iwd_agent_iface_info = NM_DEFINE_GDBUS_INTERFACE static guint iwd_agent_export (GDBusConnection *connection, gpointer user_data, - gchar **agent_path, GError **error) + char **agent_path, GError **error) { static const GDBusInterfaceVTable vtable = { .method_call = agent_dbus_method_cb, }; - gchar path[50]; + char path[50]; unsigned int rnd; guint id; @@ -251,38 +285,68 @@ register_agent (NMIwdManager *self) /*****************************************************************************/ -static void -set_device_dbus_object (NMIwdManager *self, GDBusInterface *interface, - GDBusObject *object) +static KnownNetworkId * +known_network_id_new (const char *name, NMIwdNetworkSecurity security) { - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - GDBusProxy *proxy; - GVariant *value; - const char *ifname; - gint ifindex; - NMDevice *device; + KnownNetworkId *id; + gsize strsize = strlen (name) + 1; - if (!priv->running) - return; + id = g_malloc (sizeof (KnownNetworkId) + strsize); + id->name = id->buf; + id->security = security; + memcpy (id->buf, name, strsize); - g_return_if_fail (G_IS_DBUS_PROXY (interface)); + return id; +} - proxy = G_DBUS_PROXY (interface); +static guint +known_network_id_hash (KnownNetworkId *id) +{ + NMHashState h; - if (strcmp (g_dbus_proxy_get_interface_name (proxy), - NM_IWD_DEVICE_INTERFACE)) + nm_hash_init (&h, 1947951703u); + nm_hash_update_val (&h, id->security); + nm_hash_update_str (&h, id->name); + return nm_hash_complete (&h); +} + +static gboolean +known_network_id_equal (KnownNetworkId *a, KnownNetworkId *b) +{ + return a->security == b->security + && nm_streq (a->name, b->name); +} + +static void +known_network_data_free (KnownNetworkData *network) +{ + if (!network) return; - value = g_dbus_proxy_get_cached_property (proxy, "Name"); - if (!value) { + g_object_unref (network->known_network); + mirror_8021x_connection_take_and_delete (network->mirror_connection); + g_slice_free (KnownNetworkData, network); +} + +/*****************************************************************************/ + +static void +set_device_dbus_object (NMIwdManager *self, GDBusProxy *proxy, + GDBusObject *object) +{ + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); + const char *ifname; + int ifindex; + NMDevice *device; + + ifname = get_property_string_or_null (proxy, "Name"); + if (!ifname) { _LOGE ("Name not cached for Device at %s", g_dbus_proxy_get_object_path (proxy)); return; } - ifname = g_variant_get_string (value, NULL); ifindex = if_nametoindex (ifname); - g_variant_unref (value); if (!ifindex) { _LOGE ("if_nametoindex failed for Name %s for Device at %s: %i", @@ -299,13 +363,192 @@ set_device_dbus_object (NMIwdManager *self, GDBusInterface *interface, nm_device_iwd_set_dbus_object (NM_DEVICE_IWD (device), object); } +/* Create an in-memory NMConnection for a WPA2-Enterprise network that + * has been preprovisioned with an IWD config file so that NM autoconnect + * mechanism and the clients know this networks needs no additional EAP + * configuration from the user. Only do this if no existing connection + * SSID and security type match that network yet. + */ +static NMSettingsConnection * +mirror_8021x_connection (NMIwdManager *self, + const char *name) +{ + NMSettings *settings = NM_SETTINGS_GET; + NMSettingsConnection *const*iter; + gs_unref_object NMConnection *connection = NULL; + NMSettingsConnection *settings_connection; + char uuid[37]; + NMSetting *setting; + GError *error = NULL; + gs_unref_bytes GBytes *new_ssid = NULL; + + for (iter = nm_settings_get_connections (settings, NULL); *iter; iter++) { + NMSettingsConnection *sett_conn = *iter; + NMConnection *conn = nm_settings_connection_get_connection (sett_conn); + NMIwdNetworkSecurity security; + gs_free char *ssid_name = NULL; + NMSettingWireless *s_wifi; + + security = nm_wifi_connection_get_iwd_security (conn, NULL); + if (security != NM_IWD_NETWORK_SECURITY_8021X) + continue; + + s_wifi = nm_connection_get_setting_wireless (conn); + if (!s_wifi) + continue; + + ssid_name = _nm_utils_ssid_to_utf8 (nm_setting_wireless_get_ssid (s_wifi)); + + /* We already have an NMSettingsConnection matching this + * KnownNetwork, whether it's saved or an in-memory connection + * potentially created by ourselves. Nothing to do here. + */ + if (nm_streq (ssid_name, name)) + return NULL; + } + + connection = nm_simple_connection_new (); + + setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_CONNECTION, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, + NM_SETTING_CONNECTION_ID, name, + NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_buf (uuid), + NM_SETTING_CONNECTION_READ_ONLY, TRUE, + NULL)); + nm_connection_add_setting (connection, setting); + + new_ssid = g_bytes_new (name, strlen (name)); + setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_WIRELESS, + NM_SETTING_WIRELESS_SSID, new_ssid, + NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_INFRA, + NULL)); + nm_connection_add_setting (connection, setting); + + setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_WIRELESS_SECURITY, + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", + NULL)); + nm_connection_add_setting (connection, setting); + + /* "password" and "private-key-password" may be requested by the IWD agent + * from NM and IWD will implement a specific secret cache policy so by + * default respect that policy and don't save copies of those secrets in + * NM settings. The saved values can not be used anyway because of our + * use of NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW. + */ + setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_802_1X, + NM_SETTING_802_1X_PASSWORD_FLAGS, NM_SETTING_SECRET_FLAG_NOT_SAVED, + NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS, NM_SETTING_SECRET_FLAG_NOT_SAVED, + NULL)); + nm_setting_802_1x_add_eap_method (NM_SETTING_802_1X (setting), "external"); + nm_connection_add_setting (connection, setting); + + if (!nm_connection_normalize (connection, NULL, NULL, NULL)) + return NULL; + + settings_connection = nm_settings_add_connection (settings, connection, + FALSE, &error); + if (!settings_connection) { + _LOGW ("failed to add a mirror NMConnection for IWD's Known Network '%s': %s", + name, error->message); + g_error_free (error); + return NULL; + } + + nm_settings_connection_set_flags (settings_connection, + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED | + NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED, + TRUE); + return settings_connection; +} + +static void +mirror_8021x_connection_take_and_delete (NMSettingsConnection *sett_conn) +{ + NMSettingsConnectionIntFlags flags; + + if (!sett_conn) + return; + + flags = nm_settings_connection_get_flags (sett_conn); + + /* If connection has not been saved since we created it + * in interface_added it too can be removed now. */ + if (NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) + nm_settings_connection_delete (sett_conn, NULL); + + g_object_unref (sett_conn); +} + static void interface_added (GDBusObjectManager *object_manager, GDBusObject *object, GDBusInterface *interface, gpointer user_data) { NMIwdManager *self = user_data; + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); + GDBusProxy *proxy; + const char *iface_name; + + if (!priv->running) + return; - set_device_dbus_object (self, interface, object); + g_return_if_fail (G_IS_DBUS_PROXY (interface)); + + proxy = G_DBUS_PROXY (interface); + iface_name = g_dbus_proxy_get_interface_name (proxy); + + if (nm_streq (iface_name, NM_IWD_DEVICE_INTERFACE)) { + set_device_dbus_object (self, proxy, object); + return; + } + + if (nm_streq (iface_name, NM_IWD_KNOWN_NETWORK_INTERFACE)) { + KnownNetworkId *id; + KnownNetworkData *data; + NMIwdNetworkSecurity security; + const char *type_str, *name; + NMSettingsConnection *sett_conn = NULL; + + type_str = get_property_string_or_null (proxy, "Type"); + name = get_property_string_or_null (proxy, "Name"); + if (!type_str || !name) + return; + + if (nm_streq (type_str, "open")) + security = NM_IWD_NETWORK_SECURITY_NONE; + else if (nm_streq (type_str, "psk")) + security = NM_IWD_NETWORK_SECURITY_PSK; + else if (nm_streq (type_str, "8021x")) + security = NM_IWD_NETWORK_SECURITY_8021X; + else + return; + + id = known_network_id_new (name, security); + + data = g_hash_table_lookup (priv->known_networks, id); + if (data) + g_free (id); + else { + data = g_slice_new0 (KnownNetworkData); + data->known_network = g_object_ref (proxy); + g_hash_table_insert (priv->known_networks, id, data); + } + + if (security == NM_IWD_NETWORK_SECURITY_8021X) { + sett_conn = mirror_8021x_connection (self, name); + + if ( sett_conn + && sett_conn != data->mirror_connection) { + NMSettingsConnection *sett_conn_old = data->mirror_connection; + + data->mirror_connection = nm_g_object_ref (sett_conn); + mirror_8021x_connection_take_and_delete (sett_conn_old); + } + } else + mirror_8021x_connection_take_and_delete (g_steal_pointer (&data->mirror_connection)); + + return; + } } static void @@ -313,15 +556,41 @@ interface_removed (GDBusObjectManager *object_manager, GDBusObject *object, GDBusInterface *interface, gpointer user_data) { NMIwdManager *self = user_data; + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); + GDBusProxy *proxy; + const char *iface_name; - /* - * TODO: we may need to save the GDBusInterface or GDBusObject - * pointer in the hash table because we may be no longer able to - * access the Name property or map the name to ifindex with - * if_nametoindex at this point. - */ + g_return_if_fail (G_IS_DBUS_PROXY (interface)); + + proxy = G_DBUS_PROXY (interface); + iface_name = g_dbus_proxy_get_interface_name (proxy); - set_device_dbus_object (self, interface, NULL); + if (nm_streq (iface_name, NM_IWD_DEVICE_INTERFACE)) { + set_device_dbus_object (self, proxy, NULL); + return; + } + + if (nm_streq (iface_name, NM_IWD_KNOWN_NETWORK_INTERFACE)) { + KnownNetworkId id; + const char *type_str; + + type_str = get_property_string_or_null (proxy, "Type"); + id.name = get_property_string_or_null (proxy, "Name"); + if (!type_str || !id.name) + return; + + if (nm_streq (type_str, "open")) + id.security = NM_IWD_NETWORK_SECURITY_NONE; + else if (nm_streq (type_str, "psk")) + id.security = NM_IWD_NETWORK_SECURITY_PSK; + else if (nm_streq (type_str, "8021x")) + id.security = NM_IWD_NETWORK_SECURITY_8021X; + else + return; + + g_hash_table_remove (priv->known_networks, &id); + return; + } } static gboolean @@ -341,106 +610,42 @@ object_added (NMIwdManager *self, GDBusObject *object) GList *interfaces, *iter; interfaces = g_dbus_object_get_interfaces (object); + for (iter = interfaces; iter; iter = iter->next) { GDBusInterface *interface = G_DBUS_INTERFACE (iter->data); - set_device_dbus_object (self, interface, object); + interface_added (NULL, object, interface, self); } g_list_free_full (interfaces, g_object_unref); } static void -known_network_free (KnownNetworkData *network) -{ - g_free (network->name); - g_free (network); -} - -static void -list_known_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) +release_object_manager (NMIwdManager *self) { - NMIwdManager *self = user_data; NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *variant = NULL; - GVariantIter *networks, *props; - - variant = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, - G_VARIANT_TYPE ("(aa{sv})"), - &error); - if (!variant) { - _LOGE ("ListKnownNetworks() failed: %s", error->message); - return; - } - - g_slist_free_full (priv->known_networks, (GDestroyNotify) known_network_free); - priv->known_networks = NULL; - - g_variant_get (variant, "(aa{sv})", &networks); - - while (g_variant_iter_next (networks, "a{sv}", &props)) { - const gchar *key; - const gchar *name = NULL; - const gchar *type = NULL; - GVariant *val; - KnownNetworkData *network_data; - while (g_variant_iter_next (props, "{&sv}", &key, &val)) { - if (!strcmp (key, "Name")) - name = g_variant_get_string (val, NULL); - - if (!strcmp (key, "Type")) - type = g_variant_get_string (val, NULL); - - g_variant_unref (val); - } + if (!priv->object_manager) + return; - if (!name || !type) - goto next; + g_signal_handlers_disconnect_by_data (priv->object_manager, self); - network_data = g_new (KnownNetworkData, 1); - network_data->name = g_strdup (name); - if (!strcmp (type, "open")) - network_data->security = NM_IWD_NETWORK_SECURITY_NONE; - else if (!strcmp (type, "psk")) - network_data->security = NM_IWD_NETWORK_SECURITY_PSK; - else if (!strcmp (type, "8021x")) - network_data->security = NM_IWD_NETWORK_SECURITY_8021X; + if (priv->agent_id) { + GDBusConnection *agent_connection; + GDBusObjectManagerClient *omc = G_DBUS_OBJECT_MANAGER_CLIENT (priv->object_manager); - priv->known_networks = g_slist_append (priv->known_networks, - network_data); + agent_connection = g_dbus_object_manager_client_get_connection (omc); -next: - g_variant_iter_free (props); + /* We're is called when we're shutting down (i.e. our DBus connection + * is being closed, and IWD will detect this) or IWD was stopped so + * in either case calling UnregisterAgent will not do anything. + */ + g_dbus_connection_unregister_object (agent_connection, priv->agent_id); + priv->agent_id = 0; + nm_clear_g_free (&priv->agent_path); } - g_variant_iter_free (networks); - - /* For completness we may want to call nm_device_emit_recheck_auto_activate - * and nm_device_recheck_available_connections for all affected devices - * now but the ListKnownNetworks call should have been really fast, - * faster than any scan on any newly created devices could have happened. - */ -} - -static void -update_known_networks (NMIwdManager *self) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - GDBusInterface *known_networks_if; - - known_networks_if = g_dbus_object_manager_get_interface (priv->object_manager, - "/", - NM_IWD_KNOWN_NETWORKS_INTERFACE); - - g_dbus_proxy_call (G_DBUS_PROXY (known_networks_if), - "ListKnownNetworks", - g_variant_new ("()"), - G_DBUS_CALL_FLAGS_NONE, -1, - priv->cancellable, list_known_networks_cb, self); - - g_object_unref (known_networks_if); + g_clear_object (&priv->object_manager); } static void prepare_object_manager (NMIwdManager *self); @@ -455,8 +660,7 @@ name_owner_changed (GObject *object, GParamSpec *pspec, gpointer user_data) nm_assert (object_manager == priv->object_manager); if (_om_has_name_owner (object_manager)) { - g_signal_handlers_disconnect_by_data (object_manager, self); - g_clear_object (&priv->object_manager); + release_object_manager (self); prepare_object_manager (self); } else { const CList *tmp_lst; @@ -492,28 +696,14 @@ device_added (NMManager *manager, NMDevice *device, gpointer user_data) objects = g_dbus_object_manager_get_objects (priv->object_manager); for (iter = objects; iter; iter = iter->next) { GDBusObject *object = G_DBUS_OBJECT (iter->data); - GDBusInterface *interface; - GDBusProxy *proxy; - GVariant *value; + gs_unref_object GDBusInterface *interface = NULL; const char *obj_ifname; interface = g_dbus_object_get_interface (object, NM_IWD_DEVICE_INTERFACE); - if (!interface) - continue; - - proxy = G_DBUS_PROXY (interface); - value = g_dbus_proxy_get_cached_property (proxy, "Name"); - if (!value) { - g_object_unref (interface); - continue; - } - - obj_ifname = g_variant_get_string (value, NULL); - g_variant_unref (value); - g_object_unref (interface); + obj_ifname = get_property_string_or_null ((GDBusProxy *) interface, "Name"); - if (strcmp (nm_device_get_iface (device), obj_ifname)) + if (!obj_ifname || strcmp (nm_device_get_iface (device), obj_ifname)) continue; nm_device_iwd_set_dbus_object (NM_DEVICE_IWD (device), object); @@ -535,7 +725,7 @@ got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data) object_manager = g_dbus_object_manager_client_new_for_bus_finish (result, &error); if (object_manager == NULL) { _LOGE ("failed to acquire IWD Object Manager: Wi-Fi will not be available (%s)", - NM_G_ERROR_MSG (error)); + error->message); g_clear_error (&error); return; } @@ -549,11 +739,13 @@ got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data) connection = g_dbus_object_manager_client_get_connection (G_DBUS_OBJECT_MANAGER_CLIENT (object_manager)); - priv->agent_id = iwd_agent_export (connection, self, - &priv->agent_path, &error); + priv->agent_id = iwd_agent_export (connection, + self, + &priv->agent_path, + &error); if (!priv->agent_id) { - _LOGE ("failed to export the IWD Agent: PSK/8021x WiFi networks will not work: %s", - NM_G_ERROR_MSG (error)); + _LOGE ("failed to export the IWD Agent: PSK/8021x WiFi networks may not work: %s", + error->message); g_clear_error (&error); } @@ -567,6 +759,8 @@ got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data) g_signal_connect (priv->object_manager, "interface-removed", G_CALLBACK (interface_removed), self); + g_hash_table_remove_all (priv->known_networks); + objects = g_dbus_object_manager_get_objects (object_manager); for (iter = objects; iter; iter = iter->next) object_added (self, G_DBUS_OBJECT (iter->data)); @@ -575,8 +769,6 @@ got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data) if (priv->agent_id) register_agent (self); - - update_known_networks (self); } } @@ -594,36 +786,28 @@ prepare_object_manager (NMIwdManager *self) } gboolean -nm_iwd_manager_is_known_network (NMIwdManager *self, const gchar *name, +nm_iwd_manager_is_known_network (NMIwdManager *self, const char *name, NMIwdNetworkSecurity security) { NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - const GSList *iter; - - for (iter = priv->known_networks; iter; iter = g_slist_next (iter)) { - const KnownNetworkData *network = iter->data; - - if (!strcmp (network->name, name) && network->security == security) - return true; - } + KnownNetworkId kn_id = { name, security }; - return false; + return g_hash_table_contains (priv->known_networks, &kn_id); } -void -nm_iwd_manager_network_connected (NMIwdManager *self, const gchar *name, - NMIwdNetworkSecurity security) +GDBusProxy * +nm_iwd_manager_get_dbus_interface (NMIwdManager *self, const char *path, + const char *name) { NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - KnownNetworkData *network_data; + GDBusInterface *interface; - if (nm_iwd_manager_is_known_network (self, name, security)) - return; + if (!priv->object_manager) + return NULL; + + interface = g_dbus_object_manager_get_interface (priv->object_manager, path, name); - network_data = g_new (KnownNetworkData, 1); - network_data->name = g_strdup (name); - network_data->security = security; - priv->known_networks = g_slist_append (priv->known_networks, network_data); + return interface ? G_DBUS_PROXY (interface) : NULL; } /*****************************************************************************/ @@ -642,6 +826,11 @@ nm_iwd_manager_init (NMIwdManager *self) priv->cancellable = g_cancellable_new (); + priv->known_networks = g_hash_table_new_full ((GHashFunc) known_network_id_hash, + (GEqualFunc) known_network_id_equal, + g_free, + (GDestroyNotify) known_network_data_free); + prepare_object_manager (self); } @@ -651,30 +840,11 @@ dispose (GObject *object) NMIwdManager *self = (NMIwdManager *) object; NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - if (priv->object_manager) { - if (priv->agent_id) { - GDBusConnection *connection; - GDBusObjectManagerClient *omc = G_DBUS_OBJECT_MANAGER_CLIENT (priv->object_manager); - - /* No need to unregister the agent as IWD will detect - * our DBus connection being closed. - */ - - connection = g_dbus_object_manager_client_get_connection (omc); - - g_dbus_connection_unregister_object (connection, priv->agent_id); - priv->agent_id = 0; - } - - g_clear_object (&priv->object_manager); - } - - nm_clear_g_free (&priv->agent_path); + release_object_manager (self); nm_clear_g_cancellable (&priv->cancellable); - g_slist_free_full (priv->known_networks, (GDestroyNotify) known_network_free); - priv->known_networks = NULL; + nm_clear_pointer (&priv->known_networks, g_hash_table_destroy); if (priv->manager) { g_signal_handlers_disconnect_by_data (priv->manager, self); diff --git a/src/devices/wifi/nm-iwd-manager.h b/src/devices/wifi/nm-iwd-manager.h index 8e6b66ff..57b7007a 100644 --- a/src/devices/wifi/nm-iwd-manager.h +++ b/src/devices/wifi/nm-iwd-manager.h @@ -22,6 +22,7 @@ #define __NETWORKMANAGER_IWD_MANAGER_H__ #include "devices/nm-device.h" +#include "nm-wifi-utils.h" #define NM_IWD_BUS_TYPE G_BUS_TYPE_SYSTEM #define NM_IWD_SERVICE "net.connman.iwd" @@ -33,15 +34,11 @@ #define NM_IWD_AGENT_INTERFACE "net.connman.iwd.Agent" #define NM_IWD_WSC_INTERFACE \ "net.connman.iwd.WiFiSimpleConfiguration" -#define NM_IWD_KNOWN_NETWORKS_INTERFACE "net.connman.iwd.KnownNetworks" +#define NM_IWD_KNOWN_NETWORK_INTERFACE "net.connman.iwd.KnownNetwork" #define NM_IWD_SIGNAL_AGENT_INTERFACE "net.connman.iwd.SignalLevelAgent" - -typedef enum { - NM_IWD_NETWORK_SECURITY_NONE, - NM_IWD_NETWORK_SECURITY_WEP, - NM_IWD_NETWORK_SECURITY_PSK, - NM_IWD_NETWORK_SECURITY_8021X, -} NMIwdNetworkSecurity; +#define NM_IWD_AP_INTERFACE "net.connman.iwd.AccessPoint" +#define NM_IWD_ADHOC_INTERFACE "net.connman.iwd.AdHoc" +#define NM_IWD_STATION_INTERFACE "net.connman.iwd.Station" #define NM_TYPE_IWD_MANAGER (nm_iwd_manager_get_type ()) #define NM_IWD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IWD_MANAGER, NMIwdManager)) @@ -57,9 +54,10 @@ GType nm_iwd_manager_get_type (void); NMIwdManager *nm_iwd_manager_get (void); -gboolean nm_iwd_manager_is_known_network (NMIwdManager *self, const gchar *name, +gboolean nm_iwd_manager_is_known_network (NMIwdManager *self, const char *name, NMIwdNetworkSecurity security); -void nm_iwd_manager_network_connected (NMIwdManager *self, const gchar *name, - NMIwdNetworkSecurity security); + +GDBusProxy *nm_iwd_manager_get_dbus_interface (NMIwdManager *self, const char *path, + const char *name); #endif /* __NETWORKMANAGER_IWD_MANAGER_H__ */ diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index dd6d1deb..e5573383 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -58,7 +58,7 @@ struct _NMWifiAPPrivate { char *supplicant_path; /* D-Bus object path of this AP from wpa_supplicant */ /* Scanned or cached values */ - GByteArray * ssid; + GBytes * ssid; char * address; NM80211Mode mode; guint8 strength; @@ -95,7 +95,7 @@ nm_wifi_ap_get_supplicant_path (NMWifiAP *ap) return NM_WIFI_AP_GET_PRIVATE (ap)->supplicant_path; } -const GByteArray * +GBytes * nm_wifi_ap_get_ssid (const NMWifiAP *ap) { g_return_val_if_fail (NM_IS_WIFI_AP (ap), NULL); @@ -103,43 +103,57 @@ nm_wifi_ap_get_ssid (const NMWifiAP *ap) return NM_WIFI_AP_GET_PRIVATE (ap)->ssid; } -static GVariant * -nm_wifi_ap_get_ssid_as_variant (const NMWifiAP *self) +gboolean +nm_wifi_ap_set_ssid_arr (NMWifiAP *ap, + const guint8 *ssid, + gsize ssid_len) { - const NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (self); + NMWifiAPPrivate *priv; + + g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); + + if (ssid_len > 32) + g_return_val_if_reached (FALSE); + + priv = NM_WIFI_AP_GET_PRIVATE (ap); + + if (nm_utils_gbytes_equal_mem (priv->ssid, ssid, ssid_len)) + return FALSE; + + nm_clear_pointer (&priv->ssid, g_bytes_unref); + if (ssid_len > 0) + priv->ssid = g_bytes_new (ssid, ssid_len); - if (priv->ssid) { - return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - priv->ssid->data, priv->ssid->len, 1); - } else - return g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0); + _notify (ap, PROP_SSID); + return TRUE; } gboolean -nm_wifi_ap_set_ssid (NMWifiAP *ap, const guint8 *ssid, gsize len) +nm_wifi_ap_set_ssid (NMWifiAP *ap, GBytes *ssid) { NMWifiAPPrivate *priv; + gsize l; g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); - g_return_val_if_fail (ssid == NULL || len > 0, FALSE); - priv = NM_WIFI_AP_GET_PRIVATE (ap); - - /* same SSID */ - if ((ssid && priv->ssid) && (len == priv->ssid->len)) { - if (!memcmp (ssid, priv->ssid->data, len)) - return FALSE; + if (ssid) { + l = g_bytes_get_size (ssid); + if (l == 0 || l > 32) + g_return_val_if_reached (FALSE); } - if (priv->ssid) { - g_byte_array_free (priv->ssid, TRUE); - priv->ssid = NULL; - } + priv = NM_WIFI_AP_GET_PRIVATE (ap); - if (ssid) { - priv->ssid = g_byte_array_new (); - g_byte_array_append (priv->ssid, ssid, len); - } + if (ssid == priv->ssid) + return FALSE; + if ( ssid + && priv->ssid + && g_bytes_equal (ssid, priv->ssid)) + return FALSE; + + nm_clear_pointer (&priv->ssid, g_bytes_unref); + if (ssid) + priv->ssid = g_bytes_ref (ssid); _notify (ap, PROP_SSID); return TRUE; @@ -814,10 +828,16 @@ nm_wifi_ap_update_from_properties (NMWifiAP *ap, len = MIN (32, len); /* Stupid ieee80211 layer uses <hidden> */ - if ( bytes && len - && !(((len == 8) || (len == 9)) && !memcmp (bytes, "<hidden>", 8)) - && !nm_utils_is_empty_ssid (bytes, len)) - changed |= nm_wifi_ap_set_ssid (ap, bytes, len); + if ( bytes + && len + && !( NM_IN_SET (len, 8, 9) + && memcmp (bytes, "<hidden>", len) == 0) + && !nm_utils_is_empty_ssid (bytes, len)) { + /* good */ + } else + len = 0; + + changed |= nm_wifi_ap_set_ssid_arr (ap, bytes, len); g_variant_unref (v); } @@ -961,7 +981,7 @@ nm_wifi_ap_to_string (const NMWifiAP *self, const char *supplicant_id = "-"; const char *export_path; guint32 chan; - char b1[200]; + gs_free char *ssid_to_free = NULL; g_return_val_if_fail (NM_IS_WIFI_AP (self), NULL); @@ -977,10 +997,9 @@ nm_wifi_ap_to_string (const NMWifiAP *self, export_path = "/"; g_snprintf (str_buf, buf_len, - "%17s %-32s [ %c %3u %3u%% %c W:%04X R:%04X ] %3us sup:%s [nm:%s]", + "%17s %-35s [ %c %3u %3u%% %c W:%04X R:%04X ] %3us sup:%s [nm:%s]", priv->address ?: "(none)", - nm_sprintf_buf (b1, "%s%s%s", - NM_PRINT_FMT_QUOTED (priv->ssid, "\"", nm_utils_escape_ssid (priv->ssid->data, priv->ssid->len), "\"", "(none)")), + (ssid_to_free = _nm_utils_ssid_to_string (priv->ssid)), (priv->mode == NM_802_11_MODE_ADHOC ? '*' : (priv->hotspot @@ -1032,15 +1051,12 @@ nm_wifi_ap_check_compatible (NMWifiAP *self, return FALSE; ssid = nm_setting_wireless_get_ssid (s_wireless); - if ( (ssid && !priv->ssid) - || (priv->ssid && !ssid)) - return FALSE; - - if ( ssid && priv->ssid && - !nm_utils_same_ssid (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid), - priv->ssid->data, priv->ssid->len, - TRUE)) - return FALSE; + if (ssid != priv->ssid) { + if (!ssid || !priv->ssid) + return FALSE; + if (!g_bytes_equal (ssid, priv->ssid)) + return FALSE; + } bssid = nm_setting_wireless_get_bssid (s_wireless); if (bssid && (!priv->address || !nm_utils_hwaddr_matches (bssid, -1, priv->address, -1))) @@ -1126,7 +1142,8 @@ get_property (GObject *object, guint prop_id, g_value_set_uint (value, priv->rsn_flags); break; case PROP_SSID: - g_value_take_variant (value, nm_wifi_ap_get_ssid_as_variant (self)); + g_value_take_variant (value, + nm_utils_gbytes_to_variant_ay (priv->ssid)); break; case PROP_FREQUENCY: g_value_set_uint (value, priv->freq); @@ -1146,7 +1163,7 @@ get_property (GObject *object, guint prop_id, case PROP_LAST_SEEN: g_value_set_int (value, priv->last_seen > 0 - ? (gint) nm_utils_monotonic_timestamp_as_boottime (priv->last_seen, NM_UTILS_NS_PER_SECOND) + ? (int) nm_utils_monotonic_timestamp_as_boottime (priv->last_seen, NM_UTILS_NS_PER_SECOND) : -1); break; default: @@ -1202,7 +1219,6 @@ nm_wifi_ap_new_fake_from_connection (NMConnection *connection) NMWifiAPPrivate *priv; NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; - GBytes *ssid; const char *mode, *band, *key_mgmt; guint32 channel; NM80211ApSecurityFlags flags; @@ -1213,14 +1229,12 @@ nm_wifi_ap_new_fake_from_connection (NMConnection *connection) s_wireless = nm_connection_get_setting_wireless (connection); g_return_val_if_fail (s_wireless != NULL, NULL); - ssid = nm_setting_wireless_get_ssid (s_wireless); - g_return_val_if_fail (ssid != NULL, NULL); - g_return_val_if_fail (g_bytes_get_size (ssid) > 0, NULL); - ap = (NMWifiAP *) g_object_new (NM_TYPE_WIFI_AP, NULL); priv = NM_WIFI_AP_GET_PRIVATE (ap); priv->fake = TRUE; - nm_wifi_ap_set_ssid (ap, g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid)); + + nm_wifi_ap_set_ssid (ap, + nm_setting_wireless_get_ssid (s_wireless)); // FIXME: bssid too? @@ -1334,7 +1348,7 @@ finalize (GObject *object) g_free (priv->supplicant_path); if (priv->ssid) - g_byte_array_free (priv->ssid, TRUE); + g_bytes_unref (priv->ssid); g_free (priv->address); G_OBJECT_CLASS (nm_wifi_ap_parent_class)->finalize (object); @@ -1520,8 +1534,8 @@ nm_wifi_ap_lookup_for_device (NMDevice *device, const char *exported_path) g_return_val_if_fail (NM_IS_DEVICE (device), NULL); - ap = (NMWifiAP *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (device)), - exported_path); + ap = nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (device)), + exported_path); if ( !ap || !NM_IS_WIFI_AP (ap) || ap->wifi_device != device) diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h index 4fdeee93..7462e9d1 100644 --- a/src/devices/wifi/nm-wifi-ap.h +++ b/src/devices/wifi/nm-wifi-ap.h @@ -72,10 +72,12 @@ gboolean nm_wifi_ap_complete_connection (NMWifiAP *self, GError **error); const char * nm_wifi_ap_get_supplicant_path (NMWifiAP *ap); -const GByteArray *nm_wifi_ap_get_ssid (const NMWifiAP *ap); -gboolean nm_wifi_ap_set_ssid (NMWifiAP *ap, +GBytes *nm_wifi_ap_get_ssid (const NMWifiAP *ap); +gboolean nm_wifi_ap_set_ssid_arr (NMWifiAP *ap, const guint8 *ssid, - gsize len); + gsize ssid_len); +gboolean nm_wifi_ap_set_ssid (NMWifiAP *ap, + GBytes *ssid); const char * nm_wifi_ap_get_address (const NMWifiAP *ap); gboolean nm_wifi_ap_set_address (NMWifiAP *ap, const char *addr); diff --git a/src/devices/wifi/nm-wifi-utils.c b/src/devices/wifi/nm-wifi-utils.c index 044bd392..0f7836be 100644 --- a/src/devices/wifi/nm-wifi-utils.c +++ b/src/devices/wifi/nm-wifi-utils.c @@ -525,7 +525,7 @@ verify_adhoc (NMSettingWirelessSecurity *s_wsec, } gboolean -nm_wifi_utils_complete_connection (const GByteArray *ap_ssid, +nm_wifi_utils_complete_connection (GBytes *ap_ssid, const char *bssid, NM80211Mode ap_mode, guint32 ap_flags, @@ -538,7 +538,7 @@ nm_wifi_utils_complete_connection (const GByteArray *ap_ssid, NMSettingWireless *s_wifi; NMSettingWirelessSecurity *s_wsec; NMSetting8021x *s_8021x; - GBytes *ssid, *ap_ssid_bytes; + GBytes *ssid; const char *mode, *key_mgmt, *auth_alg, *leap_username; gboolean adhoc = FALSE; @@ -548,20 +548,17 @@ nm_wifi_utils_complete_connection (const GByteArray *ap_ssid, s_8021x = nm_connection_get_setting_802_1x (connection); /* Fill in missing SSID */ - ap_ssid_bytes = ap_ssid ? g_bytes_new (ap_ssid->data, ap_ssid->len) : NULL; ssid = nm_setting_wireless_get_ssid (s_wifi); if (!ssid) - g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_SSID, ap_ssid_bytes, NULL); - else if (!ap_ssid_bytes || !g_bytes_equal (ssid, ap_ssid_bytes)) { + g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_SSID, ap_ssid, NULL); + else if (!ap_ssid || !g_bytes_equal (ssid, ap_ssid)) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("connection does not match access point")); g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_SSID); - g_bytes_unref (ap_ssid_bytes); return FALSE; } - g_bytes_unref (ap_ssid_bytes); if (lock_bssid && !nm_setting_wireless_get_bssid (s_wifi)) g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_BSSID, bssid, NULL); @@ -764,7 +761,7 @@ nm_wifi_utils_complete_connection (const GByteArray *ap_ssid, } guint32 -nm_wifi_utils_level_to_quality (gint val) +nm_wifi_utils_level_to_quality (int val) { if (val < 0) { /* Assume dBm already; rough conversion: best = -40, worst = -100 */ @@ -783,8 +780,10 @@ nm_wifi_utils_level_to_quality (gint val) } gboolean -nm_wifi_utils_is_manf_default_ssid (const GByteArray *ssid) +nm_wifi_utils_is_manf_default_ssid (GBytes *ssid) { + const guint8 *ssid_p; + gsize ssid_l; int i; /* * List of manufacturer default SSIDs that are often unchanged by users. @@ -806,11 +805,46 @@ nm_wifi_utils_is_manf_default_ssid (const GByteArray *ssid) "TURBONETT", }; + ssid_p = g_bytes_get_data (ssid, &ssid_l); + for (i = 0; i < G_N_ELEMENTS (manf_defaults); i++) { - if (ssid->len == strlen (manf_defaults[i])) { - if (memcmp (manf_defaults[i], ssid->data, ssid->len) == 0) + if (ssid_l == strlen (manf_defaults[i])) { + if (memcmp (manf_defaults[i], ssid_p, ssid_l) == 0) return TRUE; } } return FALSE; } + +NMIwdNetworkSecurity +nm_wifi_connection_get_iwd_security (NMConnection *connection, + gboolean *mapped) +{ + NMSettingWirelessSecurity *s_wireless_sec; + const char *key_mgmt = NULL; + + if (!nm_connection_get_setting_wireless (connection)) + goto error; + + NM_SET_OUT (mapped, TRUE); + + s_wireless_sec = nm_connection_get_setting_wireless_security (connection); + if (!s_wireless_sec) + return NM_IWD_NETWORK_SECURITY_NONE; + + key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec); + nm_assert (key_mgmt); + + if (NM_IN_STRSET (key_mgmt, "none", "ieee8021x")) + return NM_IWD_NETWORK_SECURITY_WEP; + + if (nm_streq (key_mgmt, "wpa-psk")) + return NM_IWD_NETWORK_SECURITY_PSK; + + if (nm_streq (key_mgmt, "wpa-eap")) + return NM_IWD_NETWORK_SECURITY_8021X; + +error: + NM_SET_OUT (mapped, FALSE); + return NM_IWD_NETWORK_SECURITY_NONE; +} diff --git a/src/devices/wifi/nm-wifi-utils.h b/src/devices/wifi/nm-wifi-utils.h index def64dd6..03238c24 100644 --- a/src/devices/wifi/nm-wifi-utils.h +++ b/src/devices/wifi/nm-wifi-utils.h @@ -27,7 +27,14 @@ #include "nm-setting-wireless-security.h" #include "nm-setting-8021x.h" -gboolean nm_wifi_utils_complete_connection (const GByteArray *ssid, +typedef enum { + NM_IWD_NETWORK_SECURITY_NONE, + NM_IWD_NETWORK_SECURITY_WEP, + NM_IWD_NETWORK_SECURITY_PSK, + NM_IWD_NETWORK_SECURITY_8021X, +} NMIwdNetworkSecurity; + +gboolean nm_wifi_utils_complete_connection (GBytes *ssid, const char *bssid, NM80211Mode mode, guint32 flags, @@ -37,8 +44,11 @@ gboolean nm_wifi_utils_complete_connection (const GByteArray *ssid, gboolean lock_bssid, GError **error); -guint32 nm_wifi_utils_level_to_quality (gint val); +guint32 nm_wifi_utils_level_to_quality (int val); + +gboolean nm_wifi_utils_is_manf_default_ssid (GBytes *ssid); -gboolean nm_wifi_utils_is_manf_default_ssid (const GByteArray *ssid); +NMIwdNetworkSecurity nm_wifi_connection_get_iwd_security (NMConnection *connection, + gboolean *mapped); #endif /* __NM_WIFI_UTILS_H__ */ diff --git a/src/devices/wifi/tests/test-general.c b/src/devices/wifi/tests/test-general.c index 89eebb22..f752bbfc 100644 --- a/src/devices/wifi/tests/test-general.c +++ b/src/devices/wifi/tests/test-general.c @@ -74,8 +74,7 @@ complete_connection (const char *ssid, NMConnection *src, GError **error) { - GByteArray *tmp; - gboolean success; + gs_unref_bytes GBytes *ssid_b = NULL; NMSettingWireless *s_wifi; /* Add a wifi setting if one doesn't exist */ @@ -85,20 +84,17 @@ complete_connection (const char *ssid, nm_connection_add_setting (src, NM_SETTING (s_wifi)); } - tmp = g_byte_array_sized_new (strlen (ssid)); - g_byte_array_append (tmp, (const guint8 *) ssid, strlen (ssid)); - - success = nm_wifi_utils_complete_connection (tmp, - bssid, - mode, - flags, - wpa_flags, - rsn_flags, - src, - lock_bssid, - error); - g_byte_array_free (tmp, TRUE); - return success; + ssid_b = g_bytes_new (ssid, strlen (ssid)); + + return nm_wifi_utils_complete_connection (ssid_b, + bssid, + mode, + flags, + wpa_flags, + rsn_flags, + src, + lock_bssid, + error); } typedef struct { @@ -127,7 +123,7 @@ set_items (NMSetting *setting, const KeyData *items) g_assert (item->str == NULL); g_object_set (G_OBJECT (setting), item->key, item->uint, NULL); } else if (pspec->value_type == G_TYPE_INT) { - gint foo = (gint) item->uint; + int foo = (int) item->uint; g_assert (item->str == NULL); g_object_set (G_OBJECT (setting), item->key, foo, NULL); @@ -1462,7 +1458,7 @@ main (int argc, char **argv) test_ap_wpa_eap_connection_5); #define ADD_FUNC(func) do { \ - gchar *name_idx = g_strdup_printf ("/wifi/wpa_psk/" G_STRINGIFY (func) "/%zd", i); \ + char *name_idx = g_strdup_printf ("/wifi/wpa_psk/" G_STRINGIFY (func) "/%zd", i); \ g_test_add_data_func (name_idx, (gconstpointer) i, func); \ g_free (name_idx); \ } while (0) @@ -1487,7 +1483,7 @@ main (int argc, char **argv) #undef ADD_FUNC #define ADD_FUNC(func) do { \ - gchar *name_idx = g_strdup_printf ("/wifi/rsn_psk/" G_STRINGIFY (func) "/%zd", i); \ + char *name_idx = g_strdup_printf ("/wifi/rsn_psk/" G_STRINGIFY (func) "/%zd", i); \ g_test_add_data_func (name_idx, (gconstpointer) i, func); \ g_free (name_idx); \ } while (0) diff --git a/src/devices/wwan/meson.build b/src/devices/wwan/meson.build index abf58594..2c0ea5a1 100644 --- a/src/devices/wwan/meson.build +++ b/src/devices/wwan/meson.build @@ -35,10 +35,10 @@ libnm_wwan_dep = declare_dependency( core_plugins += libnm_wwan -run_target( +test( 'check-wwan', - command: [check_exports, libnm_wwan.full_path(), linker_script], - depends: libnm_wwan + check_exports, + args: [libnm_wwan.full_path(), linker_script], ) sources = files( diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index 352b1c3e..4119d598 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -397,34 +397,67 @@ get_type_description (NMDevice *device) } static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) +check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { - if (!NM_DEVICE_CLASS (nm_device_modem_parent_class)->check_connection_compatible (device, connection)) + GError *local = NULL; + + if (!NM_DEVICE_CLASS (nm_device_modem_parent_class)->check_connection_compatible (device, connection, error)) return FALSE; - return nm_modem_check_connection_compatible (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device)->modem, connection); + if (!nm_modem_check_connection_compatible (NM_DEVICE_MODEM_GET_PRIVATE ((NMDeviceModem *) device)->modem, + connection, + error ? &local : NULL)) { + if (error) { + g_set_error (error, + NM_UTILS_ERROR, + g_error_matches (local, NM_UTILS_ERROR, NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE) + ? NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE + : NM_UTILS_ERROR_UNKNOWN, + "modem is incompatible with connection: %s", + local->message); + g_error_free (local); + } + return FALSE; + } + return TRUE; } static gboolean check_connection_available (NMDevice *device, NMConnection *connection, NMDeviceCheckConAvailableFlags flags, - const char *specific_object) + const char *specific_object, + GError **error) { NMDeviceModem *self = NM_DEVICE_MODEM (device); NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); NMModemState state; - if (!priv->rf_enabled || !priv->modem) + if (!priv->rf_enabled) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "RFKILL for modem enabled"); return FALSE; + } + + if (!priv->modem) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "modem not available"); + return FALSE; + } state = nm_modem_get_state (priv->modem); - if (state <= NM_MODEM_STATE_INITIALIZING) + if (state <= NM_MODEM_STATE_INITIALIZING) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "modem not initalized"); return FALSE; + } if (state == NM_MODEM_STATE_LOCKED) { - if (!nm_connection_get_setting_gsm (connection)) + if (!nm_connection_get_setting_gsm (connection)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "modem is locked without pin available"); return FALSE; + } } return TRUE; diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index e5678b96..04cb8599 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -256,7 +256,7 @@ create_cdma_connect_properties (NMConnection *connection) { NMSettingCdma *setting; MMSimpleConnectProperties *properties; - const gchar *str; + const char *str; setting = nm_connection_get_setting_cdma (connection); properties = mm_simple_connect_properties_new (); @@ -274,7 +274,7 @@ create_gsm_connect_properties (NMConnection *connection) NMSettingGsm *setting; NMSettingPpp *s_ppp; MMSimpleConnectProperties *properties; - const gchar *str; + const char *str; setting = nm_connection_get_setting_gsm (connection); properties = mm_simple_connect_properties_new (); @@ -617,44 +617,40 @@ act_stage1_prepare (NMModem *_self, /*****************************************************************************/ static gboolean -check_connection_compatible (NMModem *_self, NMConnection *connection) +check_connection_compatible_with_modem (NMModem *_self, NMConnection *connection, GError **error) { NMModemBroadband *self = NM_MODEM_BROADBAND (_self); MMModemCapability modem_caps; - NMSettingConnection *s_con; modem_caps = mm_modem_get_current_capabilities (self->_priv.modem_iface); - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); if (MODEM_CAPS_3GPP (modem_caps)) { - NMSettingGsm *s_gsm; - - if (!g_str_equal (nm_setting_connection_get_connection_type (s_con), - NM_SETTING_GSM_SETTING_NAME)) - return FALSE; - - s_gsm = nm_connection_get_setting_gsm (connection); - if (!s_gsm) + if (!_nm_connection_check_main_setting (connection, NM_SETTING_GSM_SETTING_NAME, error)) return FALSE; return TRUE; } if (MODEM_CAPS_3GPP2 (modem_caps)) { - NMSettingCdma *s_cdma; - - if (!g_str_equal (nm_setting_connection_get_connection_type (s_con), - NM_SETTING_CDMA_SETTING_NAME)) - return FALSE; - - s_cdma = nm_connection_get_setting_cdma (connection); - if (!s_cdma) + if (!_nm_connection_check_main_setting (connection, NM_SETTING_CDMA_SETTING_NAME, error)) return FALSE; return TRUE; } + if ( !_nm_connection_check_main_setting (connection, NM_SETTING_GSM_SETTING_NAME, NULL) + && !_nm_connection_check_main_setting (connection, NM_SETTING_CDMA_SETTING_NAME, NULL)) { + nm_utils_error_set (error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, + "connection type %s is not supported by modem", + nm_connection_get_connection_type (connection)); + return FALSE; + } + + nm_utils_error_set (error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "modem lacks capabilities for %s profile", + nm_connection_get_connection_type (connection)); return FALSE; } @@ -868,12 +864,12 @@ static_stage3_ip4_done (NMModemBroadband *self) GError *error = NULL; gs_unref_object NMIP4Config *config = NULL; const char *data_port; - const gchar *address_string; - const gchar *gw_string; + const char *address_string; + const char *gw_string; guint32 address_network; guint32 gw = 0; NMPlatformIP4Address address; - const gchar **dns; + const char **dns; guint i; guint32 ip4_route_table, ip4_route_metric; NMPlatformIP4Route *r; @@ -979,10 +975,10 @@ stage3_ip6_done (NMModemBroadband *self) GError *error = NULL; NMIP6Config *config = NULL; const char *data_port; - const gchar *address_string; + const char *address_string; NMPlatformIP6Address address; NMModemIPMethod ip_method; - const gchar **dns; + const char **dns; guint i; g_assert (self->_priv.ipv6_config); @@ -1067,7 +1063,7 @@ stage3_ip6_done (NMModemBroadband *self) /* DNS servers */ dns = mm_bearer_ip_config_get_dns (self->_priv.ipv6_config); - for (i = 0; dns[i]; i++) { + for (i = 0; dns && dns[i]; i++) { struct in6_addr addr; if (inet_pton (AF_INET6, dns[i], &addr)) { @@ -1476,7 +1472,7 @@ nm_modem_broadband_class_init (NMModemBroadbandClass *klass) modem_class->deactivate_cleanup = deactivate_cleanup; modem_class->set_mm_enabled = set_mm_enabled; modem_class->get_user_pass = get_user_pass; - modem_class->check_connection_compatible = check_connection_compatible; + modem_class->check_connection_compatible_with_modem = check_connection_compatible_with_modem; modem_class->complete_connection = complete_connection; modem_class->act_stage1_prepare = act_stage1_prepare; modem_class->owns_port = owns_port; diff --git a/src/devices/wwan/nm-modem-manager.c b/src/devices/wwan/nm-modem-manager.c index 59cd2bca..dfc102f3 100644 --- a/src/devices/wwan/nm-modem-manager.c +++ b/src/devices/wwan/nm-modem-manager.c @@ -170,7 +170,7 @@ modm_handle_object_added (MMManager *modem_manager, NMModemManager *self) { NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); - const gchar *path; + const char *path; MMModem *modem_iface; NMModem *modem; GError *error = NULL; @@ -211,7 +211,7 @@ modm_handle_object_removed (MMManager *manager, { NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); NMModem *modem; - const gchar *path; + const char *path; path = mm_object_get_path (modem_object); modem = (NMModem *) g_hash_table_lookup (priv->modems, path); @@ -246,7 +246,7 @@ modm_handle_name_owner_changed (MMManager *modem_manager, NMModemManager *self) { NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); - gchar *name_owner; + char *name_owner; /* Quit poking, if any */ nm_clear_g_source (&priv->modm.relaunch_id); @@ -341,7 +341,7 @@ static void modm_manager_check_name_owner (NMModemManager *self) { NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); - gs_free gchar *name_owner = NULL; + gs_free char *name_owner = NULL; name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (priv->modm.manager)); if (name_owner) { @@ -606,14 +606,14 @@ ofono_create_modem (NMModemManager *self, const char *path) static void ofono_signal_cb (GDBusProxy *proxy, - gchar *sender_name, - gchar *signal_name, + char *sender_name, + char *signal_name, GVariant *parameters, gpointer user_data) { NMModemManager *self = NM_MODEM_MANAGER (user_data); NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE (self); - gchar *object_path; + char *object_path; NMModem *modem; if (g_strcmp0 (signal_name, "ModemAdded") == 0) { diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c index 8b81ac41..ea668590 100644 --- a/src/devices/wwan/nm-modem-ofono.c +++ b/src/devices/wwan/nm-modem-ofono.c @@ -279,47 +279,42 @@ deactivate_cleanup (NMModem *modem, NMDevice *device) } static gboolean -check_connection_compatible (NMModem *modem, - NMConnection *connection) +check_connection_compatible_with_modem (NMModem *modem, + NMConnection *connection, + GError **error) { NMModemOfono *self = NM_MODEM_OFONO (modem); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE (self); - NMSettingConnection *s_con; - NMSettingGsm *s_gsm; - const char *uuid; const char *id; - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - uuid = nm_connection_get_uuid (connection); - id = nm_connection_get_id (connection); - - s_gsm = nm_connection_get_setting_gsm (connection); - if (!s_gsm) + if (!_nm_connection_check_main_setting (connection, NM_SETTING_GSM_SETTING_NAME, NULL)) { + nm_utils_error_set (error, + NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, + "connection type %s is not supported by ofono modem", + nm_connection_get_connection_type (connection)); return FALSE; + } if (!priv->imsi) { - _LOGW ("skipping %s/%s: no IMSI", uuid, id); + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "modem has no IMSI"); return FALSE; } - if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_GSM_SETTING_NAME)) { - _LOGD ("skipping %s/%s: not GSM", uuid, id); - return FALSE; - } + id = nm_connection_get_id (connection); - if (!g_strrstr (id, "/context")) { - _LOGD ("skipping %s/%s: unexpected ID", uuid, id); + if (!strstr (id, "/context")) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "the connection ID has no context"); return FALSE; } - if (!g_strrstr (id, priv->imsi)) { - _LOGD ("skipping %s/%s: ID doesn't contain IMSI", uuid, id); + if (!strstr (id, priv->imsi)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "the connection ID does not contain the IMSI"); return FALSE; } - _LOGD ("%s/%s compatible with IMSI %s", uuid, id, priv->imsi); return TRUE; } @@ -830,8 +825,8 @@ context_property_changed (GDBusProxy *proxy, gboolean ret = FALSE; gs_unref_variant GVariant *v_dict = NULL; const char *interface; - const gchar *s; - const gchar **array, **iter; + const char *s; + const char **array, **iter; guint32 address_network, gateway_network; guint32 ip4_route_table, ip4_route_metric; int ifindex; @@ -1326,7 +1321,7 @@ nm_modem_ofono_class_init (NMModemOfonoClass *klass) modem_class->disconnect = disconnect; modem_class->disconnect_finish = disconnect_finish; modem_class->deactivate_cleanup = deactivate_cleanup; - modem_class->check_connection_compatible = check_connection_compatible; + modem_class->check_connection_compatible_with_modem = check_connection_compatible_with_modem; modem_class->act_stage1_prepare = act_stage1_prepare; modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start; diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index 617d5c4a..59b081e9 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -291,7 +291,7 @@ nm_modem_get_supported_ip_types (NMModem *self) return NM_MODEM_GET_PRIVATE (self)->ip_types; } -const gchar * +const char * nm_modem_ip_type_to_string (NMModemIPType ip_type) { switch (ip_type) { @@ -1027,35 +1027,29 @@ nm_modem_act_stage2_config (NMModem *self, /*****************************************************************************/ gboolean -nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection) +nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection, GError **error) { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - NMSettingConnection *s_con; - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - if (g_str_equal (nm_setting_connection_get_connection_type (s_con), - NM_SETTING_GSM_SETTING_NAME)) { + if (nm_streq0 (nm_connection_get_connection_type (connection), + NM_SETTING_GSM_SETTING_NAME)) { NMSettingGsm *s_gsm; const char *str; - s_gsm = nm_connection_get_setting_gsm (connection); + s_gsm = _nm_connection_check_main_setting (connection, NM_SETTING_GSM_SETTING_NAME, error); if (!s_gsm) return FALSE; str = nm_setting_gsm_get_device_id (s_gsm); if (str) { if (!priv->device_id) { - _LOGD ("%s/%s has device-id, device does not", - nm_connection_get_uuid (connection), - nm_connection_get_id (connection)); + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "GSM profile has device-id, device does not"); return FALSE; } - if (strcmp (str, priv->device_id)) { - _LOGD ("%s/%s device-id mismatch", - nm_connection_get_uuid (connection), - nm_connection_get_id (connection)); + if (!nm_streq (str, priv->device_id)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has differing device-id than GSM profile"); return FALSE; } } @@ -1065,30 +1059,26 @@ nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection) * are only compared if present on the device. */ - str = nm_setting_gsm_get_sim_id (s_gsm); - if (str && priv->sim_id) { - if (strcmp (str, priv->sim_id)) { - _LOGD ("%s/%s sim-id mismatch", - nm_connection_get_uuid (connection), - nm_connection_get_id (connection)); + if ( priv->sim_id + && (str = nm_setting_gsm_get_sim_id (s_gsm))) { + if (!nm_streq (str, priv->sim_id)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has differing sim-id than GSM profile"); return FALSE; } } - str = nm_setting_gsm_get_sim_operator_id (s_gsm); - if (str && priv->sim_operator_id) { - if (strcmp (str, priv->sim_operator_id)) { - _LOGD ("%s/%s sim-operator-id mismatch", - nm_connection_get_uuid (connection), - nm_connection_get_id (connection)); + if ( priv->sim_operator_id + && (str = nm_setting_gsm_get_sim_operator_id (s_gsm))) { + if (!nm_streq (str, priv->sim_operator_id)) { + nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, + "device has differing sim-operator-id than GSM profile"); return FALSE; } } } - if (NM_MODEM_GET_CLASS (self)->check_connection_compatible) - return NM_MODEM_GET_CLASS (self)->check_connection_compatible (self, connection); - return FALSE; + return NM_MODEM_GET_CLASS (self)->check_connection_compatible_with_modem (self, connection, error); } /*****************************************************************************/ diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index cad9ece4..c73745ce 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -121,8 +121,9 @@ typedef struct { const char **user, const char **pass); - gboolean (*check_connection_compatible) (NMModem *modem, - NMConnection *connection); + gboolean (*check_connection_compatible_with_modem) (NMModem *modem, + NMConnection *connection, + GError **error); gboolean (*complete_connection) (NMModem *modem, NMConnection *connection, @@ -185,7 +186,9 @@ void nm_modem_get_capabilities (NMModem *self, NMDeviceModemCapabilities *modem_caps, NMDeviceModemCapabilities *current_caps); -gboolean nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection); +gboolean nm_modem_check_connection_compatible (NMModem *self, + NMConnection *connection, + GError **error); gboolean nm_modem_complete_connection (NMModem *self, NMConnection *connection, @@ -273,7 +276,7 @@ void nm_modem_emit_ip6_config_result (NMModem *self, NMIP6Config *config, GError *error); -const gchar *nm_modem_ip_type_to_string (NMModemIPType ip_type); +const char *nm_modem_ip_type_to_string (NMModemIPType ip_type); guint32 nm_modem_get_configured_mtu (NMDevice *self, NMDeviceMtuSource *out_source); |