diff options
Diffstat (limited to 'src')
494 files changed, 18519 insertions, 8314 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index a3bd6013..1404854d 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -805,9 +805,11 @@ nm_utils_match_connection (NMConnection *const*connections, return NULL; for (; *connections; connections++) { - NMConnection *candidate = NM_CONNECTION (*connections); + NMConnection *candidate = *connections; GHashTable *diffs = NULL; + nm_assert (NM_IS_CONNECTION (candidate)); + if (match_filter_func) { if (!match_filter_func (candidate, match_filter_data)) continue; 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); diff --git a/src/dhcp/meson.build b/src/dhcp/meson.build index 289a16ca..76707bca 100644 --- a/src/dhcp/meson.build +++ b/src/dhcp/meson.build @@ -3,7 +3,6 @@ name = 'nm-dhcp-helper' cflags = [ '-DG_LOG_DOMAIN="@0@"'.format(name), '-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_GLIB', - '-DNMRUNDIR="@0@"'.format(nm_pkgrundir), ] executable( diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c index e53c8d87..16db8306 100644 --- a/src/dhcp/nm-dhcp-client.c +++ b/src/dhcp/nm-dhcp-client.c @@ -445,7 +445,7 @@ transaction_timeout (gpointer user_data) } static void -daemon_watch_cb (GPid pid, gint status, gpointer user_data) +daemon_watch_cb (GPid pid, int status, gpointer user_data) { NMDhcpClient *self = NM_DHCP_CLIENT (user_data); NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); @@ -510,7 +510,8 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self, GBytes *client_id, const char *dhcp_anycast_addr, const char *hostname, - const char *last_ip4_address) + const char *last_ip4_address, + GError **error) { NMDhcpClientPrivate *priv; @@ -531,7 +532,10 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self, g_clear_pointer (&priv->hostname, g_free); priv->hostname = g_strdup (hostname); - return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_anycast_addr, last_ip4_address); + return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, + dhcp_anycast_addr, + last_ip4_address, + error); } static GBytes * @@ -548,7 +552,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, const struct in6_addr *ll_addr, const char *hostname, NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes) + guint needed_prefixes, + GError **error) { NMDhcpClientPrivate *priv; gs_free char *str = NULL; @@ -584,7 +589,8 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, ll_addr, privacy, priv->duid, - needed_prefixes); + needed_prefixes, + error); } void @@ -734,7 +740,7 @@ maybe_add_option (NMDhcpClient *self, gboolean nm_dhcp_client_handle_event (gpointer unused, const char *iface, - gint pid, + int pid, GVariant *options, const char *reason, NMDhcpClient *self) diff --git a/src/dhcp/nm-dhcp-client.h b/src/dhcp/nm-dhcp-client.h index 4c196045..86d60e38 100644 --- a/src/dhcp/nm-dhcp-client.h +++ b/src/dhcp/nm-dhcp-client.h @@ -76,18 +76,18 @@ typedef enum { typedef struct { GObjectClass parent; - /* Methods */ - gboolean (*ip4_start) (NMDhcpClient *self, const char *anycast_addr, - const char *last_ip4_address); + const char *last_ip4_address, + GError **error); gboolean (*ip6_start) (NMDhcpClient *self, const char *anycast_addr, const struct in6_addr *ll_addr, NMSettingIP6ConfigPrivacy privacy, GBytes *duid, - guint needed_prefixes); + guint needed_prefixes, + GError **error); void (*stop) (NMDhcpClient *self, gboolean release, @@ -151,7 +151,8 @@ gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self, GBytes *client_id, const char *dhcp_anycast_addr, const char *hostname, - const char *last_ip4_address); + const char *last_ip4_address, + GError **error); gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self, GBytes *client_id, @@ -160,7 +161,8 @@ gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self, const struct in6_addr *ll_addr, const char *hostname, NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes); + guint needed_prefixes, + GError **error); void nm_dhcp_client_stop (NMDhcpClient *self, gboolean release); @@ -180,7 +182,7 @@ void nm_dhcp_client_set_state (NMDhcpClient *self, gboolean nm_dhcp_client_handle_event (gpointer unused, const char *iface, - gint pid, + int pid, GVariant *options, const char *reason, NMDhcpClient *self); diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index 3290dd65..a2c3bfb6 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -316,6 +316,7 @@ nm_dhcp_dhclient_create_config (const char *interface, if (orig_contents) { char **lines, **line; + int nest = 0; gboolean in_alsoreq = FALSE; gboolean in_req = FALSE; char intf[IFNAMSIZ]; @@ -330,18 +331,24 @@ nm_dhcp_dhclient_create_config (const char *interface, if (!strlen (g_strstrip (p))) continue; - if ( !intf[0] - && g_str_has_prefix (p, "interface") - && !in_req) { - if (read_interface (p, intf, sizeof (intf))) - continue; - } - - if (intf[0] && strchr (p, '}')) { + if (in_req) { + /* pass */ + } else if (strchr (p, '{')) { + nest++; + if ( !intf[0] + && g_str_has_prefix (p, "interface")) + if (read_interface (p, intf, sizeof (intf))) + continue; + } else if (strchr (p, '}')) { + if (nest) + nest--; intf[0] = '\0'; continue; } + if (nest && !intf[0]) + continue; + if (intf[0] && !nm_streq (intf, interface)) continue; @@ -437,6 +444,7 @@ nm_dhcp_dhclient_create_config (const char *interface, add_request (reqs, "static-routes"); add_request (reqs, "wpad"); add_request (reqs, "ntp-servers"); + add_request (reqs, "root-path"); } else { add_hostname6 (new_contents, hostname); add_request (reqs, "dhcp6.name-servers"); @@ -523,6 +531,10 @@ nm_dhcp_dhclient_unescape_duid (const char *duid) guint i, len; guint8 octal; + /* FIXME: it's wrong to have an "unescape-duid" function. dhclient + * defines a file format with escaping. So we need a general unescape + * function that can handle dhclient syntax. */ + len = strlen (duid); unescaped = g_byte_array_sized_new (len); for (i = 0; i < len; i++) { @@ -536,6 +548,9 @@ nm_dhcp_dhclient_unescape_duid (const char *duid) g_byte_array_append (unescaped, &octal, 1); i += 2; } else { + /* FIXME: don't warn on untrusted data. Either signal an error, or accept + * it silently. */ + /* One of ", ', $, `, \, |, or & */ g_warn_if_fail (p[i] == '"' || p[i] == '\'' || p[i] == '$' || p[i] == '`' || p[i] == '\\' || p[i] == '|' || diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c index bf93c831..4a936178 100644 --- a/src/dhcp/nm-dhcp-dhclient.c +++ b/src/dhcp/nm-dhcp-dhclient.c @@ -41,6 +41,7 @@ #include "nm-utils/nm-dedup-multi.h" #include "nm-utils.h" +#include "nm-config.h" #include "nm-dhcp-dhclient-utils.h" #include "nm-dhcp-manager.h" #include "NetworkManagerUtils.h" @@ -120,8 +121,20 @@ get_dhclient_leasefile (int addr_family, const char *uuid, char **out_preferred_path) { + char *rundir_path; char *path; + /* First, see if the lease file is in /run */ + rundir_path = g_strdup_printf (NMRUNDIR "/dhclient%s-%s-%s.lease", + _addr_family_to_path_part (addr_family), + uuid, + iface); + + if (g_file_test (rundir_path, G_FILE_TEST_EXISTS)) { + NM_SET_OUT (out_preferred_path, g_strdup (rundir_path)); + return rundir_path; + } + /* /var/lib/NetworkManager is the preferred leasefile path */ path = g_strdup_printf (NMSTATEDIR "/dhclient%s-%s-%s.lease", _addr_family_to_path_part (addr_family), @@ -133,6 +146,12 @@ get_dhclient_leasefile (int addr_family, return path; } + if (nm_config_get_configure_and_quit (nm_config_get ()) == NM_CONFIG_CONFIGURE_AND_QUIT_INITRD) { + g_free (path); + path = rundir_path; + } else { + g_free (rundir_path); + } NM_SET_OUT (out_preferred_path, g_steal_pointer (&path)); /* If the leasefile we're looking for doesn't exist yet in the new location @@ -174,13 +193,14 @@ merge_dhclient_config (NMDhcpDhclient *self, GBytes **out_new_client_id, GError **error) { - char *orig = NULL, *new; - gboolean success = FALSE; + gs_free char *orig = NULL; + gs_free char *new = NULL; - g_return_val_if_fail (iface != NULL, FALSE); - g_return_val_if_fail (conf_file != NULL, FALSE); + g_return_val_if_fail (iface, FALSE); + g_return_val_if_fail (conf_file, FALSE); - if (orig_path && g_file_test (orig_path, G_FILE_TEST_EXISTS)) { + if ( orig_path + && g_file_test (orig_path, G_FILE_TEST_EXISTS)) { GError *read_error = NULL; if (!g_file_get_contents (orig_path, &orig, NULL, &read_error)) { @@ -190,14 +210,22 @@ merge_dhclient_config (NMDhcpDhclient *self, } } - new = nm_dhcp_dhclient_create_config (iface, addr_family, client_id, anycast_addr, hostname, timeout, - use_fqdn, orig_path, orig, out_new_client_id); + new = nm_dhcp_dhclient_create_config (iface, + addr_family, + client_id, + anycast_addr, + hostname, + timeout, + use_fqdn, + orig_path, + orig, + out_new_client_id); g_assert (new); - success = g_file_set_contents (conf_file, new, -1, error); - g_free (new); - g_free (orig); - return success; + return g_file_set_contents (conf_file, + new, + -1, + error); } static char * @@ -282,13 +310,14 @@ create_dhclient_config (NMDhcpDhclient *self, gboolean use_fqdn, GBytes **out_new_client_id) { - char *orig = NULL, *new = NULL; + gs_free char *orig = NULL; + char *new = NULL; GError *error = NULL; - gboolean success = FALSE; g_return_val_if_fail (iface != NULL, NULL); new = g_strdup_printf (NMSTATEDIR "/dhclient%s-%s.conf", _addr_family_to_path_part (addr_family), iface); + _LOGD ("creating composite dhclient config %s", new); orig = find_existing_config (self, addr_family, iface, uuid); @@ -297,15 +326,12 @@ create_dhclient_config (NMDhcpDhclient *self, else _LOGD ("no existing dhclient configuration to merge"); - error = NULL; - success = merge_dhclient_config (self, addr_family, iface, new, client_id, dhcp_anycast_addr, - hostname, timeout, use_fqdn, orig, out_new_client_id, &error); - if (!success) { + if (!merge_dhclient_config (self, addr_family, iface, new, client_id, dhcp_anycast_addr, + hostname, timeout, use_fqdn, orig, out_new_client_id, &error)) { _LOGW ("error creating dhclient configuration: %s", error->message); - g_error_free (error); + g_clear_error (&error); } - g_free (orig); return new; } @@ -315,13 +341,14 @@ dhclient_start (NMDhcpClient *client, GBytes *duid, gboolean release, pid_t *out_pid, - int prefixes) + int prefixes, + GError **error) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); gs_unref_ptrarray GPtrArray *argv = NULL; pid_t pid; - GError *error = NULL; + gs_free_error GError *local = NULL; const char *iface; const char *uuid; const char *system_bus_address; @@ -339,7 +366,7 @@ dhclient_start (NMDhcpClient *client, dhclient_path = nm_dhcp_dhclient_get_path (); if (!dhclient_path) { - _LOGW ("dhclient could not be found"); + nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "dhclient binary not found"); return FALSE; } @@ -371,11 +398,7 @@ dhclient_start (NMDhcpClient *client, gs_unref_object GFile *dst = g_file_new_for_path (preferred_leasefile_path); /* Try to copy the existing leasefile to the preferred location */ - if (g_file_copy (src, dst, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &error)) { - /* Success; use the preferred leasefile path */ - g_free (priv->lease_file); - priv->lease_file = g_file_get_path (dst); - } else { + if (!g_file_copy (src, dst, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &local)) { gs_free char *s_path = NULL; gs_free char *d_path = NULL; @@ -383,8 +406,12 @@ dhclient_start (NMDhcpClient *client, _LOGW ("failed to copy leasefile %s to %s: %s", (s_path = g_file_get_path (src)), (d_path = g_file_get_path (dst)), - error->message); - g_clear_error (&error); + local->message); + g_clear_error (&local); + } else { + /* Success; use the preferred leasefile path */ + g_free (priv->lease_file); + priv->lease_file = g_file_get_path (dst); } } @@ -393,9 +420,12 @@ dhclient_start (NMDhcpClient *client, gs_free char *escaped = NULL; escaped = nm_dhcp_dhclient_escape_duid (duid); - if (!nm_dhcp_dhclient_save_duid (priv->lease_file, escaped, &error)) { - _LOGW ("failed to save DUID to %s: %s", priv->lease_file, error->message); - g_clear_error (&error); + if (!nm_dhcp_dhclient_save_duid (priv->lease_file, escaped, &local)) { + nm_utils_error_set (error, + NM_UTILS_ERROR_UNKNOWN, + "failed to save DUID to '%s': %s", + priv->lease_file, + local->message); return FALSE; } } @@ -451,13 +481,15 @@ dhclient_start (NMDhcpClient *client, g_ptr_array_add (argv, NULL); _LOGD ("running: %s", - (cmd_str = g_strjoinv (" ", (gchar **) argv->pdata))); + (cmd_str = g_strjoinv (" ", (char **) argv->pdata))); if (!g_spawn_async (NULL, (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, - nm_utils_setpgid, NULL, &pid, &error)) { - _LOGW ("dhclient failed to start: '%s'", error->message); - g_error_free (error); + nm_utils_setpgid, NULL, &pid, &local)) { + nm_utils_error_set (error, + NM_UTILS_ERROR_UNKNOWN, + "dhclient failed to start: %s", + local->message); return FALSE; } @@ -473,36 +505,46 @@ dhclient_start (NMDhcpClient *client, } static gboolean -ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address) +ip4_start (NMDhcpClient *client, + const char *dhcp_anycast_addr, + const char *last_ip4_address, + GError **error) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); GBytes *client_id; gs_unref_bytes GBytes *new_client_id = NULL; - const char *iface, *uuid, *hostname; - guint32 timeout; - gboolean success = FALSE; - gboolean use_fqdn; - iface = nm_dhcp_client_get_iface (client); - uuid = nm_dhcp_client_get_uuid (client); client_id = nm_dhcp_client_get_client_id (client); - hostname = nm_dhcp_client_get_hostname (client); - timeout = nm_dhcp_client_get_timeout (client); - use_fqdn = nm_dhcp_client_get_use_fqdn (client); - priv->conf_file = create_dhclient_config (self, AF_INET, iface, uuid, client_id, dhcp_anycast_addr, - hostname, timeout, use_fqdn, &new_client_id); - if (priv->conf_file) { - if (new_client_id) { - nm_assert (!client_id); - nm_dhcp_client_set_client_id (client, new_client_id); - } - success = dhclient_start (client, NULL, NULL, FALSE, NULL, 0); - } else - _LOGW ("error creating dhclient configuration file"); + priv->conf_file = create_dhclient_config (self, + AF_INET, + nm_dhcp_client_get_iface (client), + nm_dhcp_client_get_uuid (client), + client_id, + dhcp_anycast_addr, + nm_dhcp_client_get_hostname (client), + nm_dhcp_client_get_timeout (client), + nm_dhcp_client_get_use_fqdn (client), + &new_client_id); + if (!priv->conf_file) { + nm_utils_error_set_literal (error, + NM_UTILS_ERROR_UNKNOWN, + "error creating dhclient configuration file"); + return FALSE; + } - return success; + if (new_client_id) { + nm_assert (!client_id); + nm_dhcp_client_set_client_id (client, new_client_id); + } + return dhclient_start (client, + NULL, + NULL, + FALSE, + NULL, + 0, + error); } static gboolean @@ -511,22 +553,26 @@ ip6_start (NMDhcpClient *client, const struct in6_addr *ll_addr, NMSettingIP6ConfigPrivacy privacy, GBytes *duid, - guint needed_prefixes) + guint needed_prefixes, + GError **error) { NMDhcpDhclient *self = NM_DHCP_DHCLIENT (client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (self); - const char *iface, *uuid, *hostname; - guint32 timeout; - - iface = nm_dhcp_client_get_iface (client); - uuid = nm_dhcp_client_get_uuid (client); - hostname = nm_dhcp_client_get_hostname (client); - timeout = nm_dhcp_client_get_timeout (client); - priv->conf_file = create_dhclient_config (self, AF_INET6, iface, uuid, NULL, dhcp_anycast_addr, - hostname, timeout, TRUE, NULL); + priv->conf_file = create_dhclient_config (self, + AF_INET6, + nm_dhcp_client_get_iface (client), + nm_dhcp_client_get_uuid (client), + NULL, + dhcp_anycast_addr, + nm_dhcp_client_get_hostname (client), + nm_dhcp_client_get_timeout (client), + TRUE, + NULL); if (!priv->conf_file) { - _LOGW ("error creating dhclient configuration file"); + nm_utils_error_set_literal (error, + NM_UTILS_ERROR_UNKNOWN, + "error creating dhclient configuration file"); return FALSE; } @@ -534,7 +580,11 @@ ip6_start (NMDhcpClient *client, nm_dhcp_client_get_info_only (NM_DHCP_CLIENT (self)) ? "-S" : "-N", - duid, FALSE, NULL, needed_prefixes); + duid, + FALSE, + NULL, + needed_prefixes, + error); } static void @@ -560,7 +610,13 @@ stop (NMDhcpClient *client, gboolean release, GBytes *duid) if (release) { pid_t rpid = -1; - if (dhclient_start (client, NULL, duid, TRUE, &rpid, 0)) { + if (dhclient_start (client, + NULL, + duid, + TRUE, + &rpid, + 0, + NULL)) { /* Wait a few seconds for the release to happen */ nm_dhcp_client_stop_pid (rpid, nm_dhcp_client_get_iface (client)); } diff --git a/src/dhcp/nm-dhcp-dhcpcanon.c b/src/dhcp/nm-dhcp-dhcpcanon.c index 12aa57aa..de403020 100644 --- a/src/dhcp/nm-dhcp-dhcpcanon.c +++ b/src/dhcp/nm-dhcp-dhcpcanon.c @@ -82,28 +82,36 @@ dhcpcanon_start (NMDhcpClient *client, GBytes *duid, gboolean release, pid_t *out_pid, - int prefixes) + guint needed_prefixes, + GError **error) { NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON (client); NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE (self); - GPtrArray *argv = NULL; + gs_unref_ptrarray GPtrArray *argv = NULL; pid_t pid; - GError *error = NULL; - const char *iface, *system_bus_address, *dhcpcanon_path = NULL; - char *binary_name, *cmd_str, *pid_file = NULL, *system_bus_address_env = NULL; + gs_free_error GError *local = NULL; + const char *iface; + const char *system_bus_address; + const char *dhcpcanon_path; + gs_free char *binary_name = NULL; + gs_free char *pid_file = NULL; + gs_free char *system_bus_address_env = NULL; int addr_family; - g_return_val_if_fail (priv->pid_file == NULL, FALSE); + g_return_val_if_fail (!priv->pid_file, FALSE); iface = nm_dhcp_client_get_iface (client); + addr_family = nm_dhcp_client_get_addr_family (client); + dhcpcanon_path = nm_dhcp_dhcpcanon_get_path (); - _LOGD ("dhcpcanon_path: %s", dhcpcanon_path); if (!dhcpcanon_path) { - _LOGW ("dhcpcanon could not be found"); + nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "dhcpcanon binary not found"); return FALSE; } + _LOGD ("dhcpcanon_path: %s", dhcpcanon_path); + pid_file = g_strdup_printf (RUNSTATEDIR "/dhcpcanon%c-%s.pid", nm_utils_addr_family_to_char (addr_family), iface); @@ -112,7 +120,6 @@ dhcpcanon_start (NMDhcpClient *client, /* Kill any existing dhcpcanon from the pidfile */ binary_name = g_path_get_basename (dhcpcanon_path); nm_dhcp_client_stop_existing (pid_file, binary_name); - g_free (binary_name); argv = g_ptr_array_new (); g_ptr_array_add (argv, (gpointer) dhcpcanon_path); @@ -120,10 +127,8 @@ dhcpcanon_start (NMDhcpClient *client, g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */ g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path); - if (pid_file) { - g_ptr_array_add (argv, (gpointer) "-pf"); /* Set pid file */ - g_ptr_array_add (argv, (gpointer) pid_file); - } + g_ptr_array_add (argv, (gpointer) "-pf"); /* Set pid file */ + g_ptr_array_add (argv, (gpointer) pid_file); if (priv->conf_file) { g_ptr_array_add (argv, (gpointer) "-cf"); /* Set interface config file */ @@ -144,33 +149,43 @@ dhcpcanon_start (NMDhcpClient *client, g_ptr_array_add (argv, (gpointer) iface); g_ptr_array_add (argv, NULL); - cmd_str = g_strjoinv (" ", (gchar **) argv->pdata); - g_free (cmd_str); - - if (g_spawn_async (NULL, (char **) argv->pdata, NULL, - G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, - nm_utils_setpgid, NULL, &pid, &error)) { - g_assert (pid > 0); - _LOGI ("dhcpcanon started with pid %d", pid); - nm_dhcp_client_watch_child (client, pid); - priv->pid_file = pid_file; - } else { - _LOGW ("dhcpcanon failed to start: '%s'", error->message); - g_error_free (error); - g_free (pid_file); + if (!g_spawn_async (NULL, + (char **) argv->pdata, + NULL, + G_SPAWN_DO_NOT_REAP_CHILD + | G_SPAWN_STDOUT_TO_DEV_NULL + | G_SPAWN_STDERR_TO_DEV_NULL, + nm_utils_setpgid, + NULL, + &pid, + &local)) { + nm_utils_error_set (error, + NM_UTILS_ERROR_UNKNOWN, + "dhcpcanon failed to start: %s", + local->message); + return FALSE; } - g_ptr_array_free (argv, TRUE); - g_free (system_bus_address_env); - return pid > 0 ? TRUE : FALSE; + nm_assert (pid > 0); + _LOGI ("dhcpcanon started with pid %d", pid); + nm_dhcp_client_watch_child (client, pid); + priv->pid_file = g_steal_pointer (&pid_file); + return TRUE; } static gboolean -ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address) +ip4_start (NMDhcpClient *client, + const char *dhcp_anycast_addr, + const char *last_ip4_address, + GError **error) { - gboolean success = FALSE; - success = dhcpcanon_start (client, NULL, NULL, FALSE, NULL, 0); - return success; + return dhcpcanon_start (client, + NULL, + NULL, + FALSE, + NULL, + 0, + error); } static gboolean @@ -179,11 +194,10 @@ ip6_start (NMDhcpClient *client, const struct in6_addr *ll_addr, NMSettingIP6ConfigPrivacy privacy, GBytes *duid, - guint needed_prefixes) + guint needed_prefixes, + GError **error) { - NMDhcpDhcpcanon *self = NM_DHCP_DHCPCANON (client); - - _LOGW ("the dhcpcd backend does not support IPv6"); + nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "dhcpcanon plugin does not support IPv6"); return FALSE; } static void diff --git a/src/dhcp/nm-dhcp-dhcpcd.c b/src/dhcp/nm-dhcp-dhcpcd.c index c4bcb084..98ab5342 100644 --- a/src/dhcp/nm-dhcp-dhcpcd.c +++ b/src/dhcp/nm-dhcp-dhcpcd.c @@ -81,15 +81,21 @@ nm_dhcp_dhcpcd_get_path (void) } static gboolean -ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address) +ip4_start (NMDhcpClient *client, + const char *dhcp_anycast_addr, + const char *last_ip4_address, + GError **error) { NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client); NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (self); - GPtrArray *argv = NULL; + gs_unref_ptrarray GPtrArray *argv = NULL; pid_t pid = -1; - GError *error = NULL; - char *pid_contents = NULL, *binary_name, *cmd_str; - const char *iface, *dhcpcd_path, *hostname; + GError *local = NULL; + gs_free char *cmd_str = NULL; + gs_free char *binary_name = NULL; + const char *iface; + const char *dhcpcd_path; + const char *hostname; g_return_val_if_fail (priv->pid_file == NULL, FALSE); @@ -102,14 +108,13 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last dhcpcd_path = nm_dhcp_dhcpcd_get_path (); if (!dhcpcd_path) { - _LOGW ("dhcpcd could not be found"); + nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "dhcpcd binary not found"); return FALSE; } /* Kill any existing dhcpcd from the pidfile */ binary_name = g_path_get_basename (dhcpcd_path); nm_dhcp_client_stop_existing (priv->pid_file, binary_name); - g_free (binary_name); argv = g_ptr_array_new (); g_ptr_array_add (argv, (gpointer) dhcpcd_path); @@ -128,13 +133,11 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last g_ptr_array_add (argv, (gpointer) "-c"); /* Set script file */ g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path); -#ifdef DHCPCD_SUPPORTS_IPV6 /* IPv4-only for now. NetworkManager knows better than dhcpcd when to * run IPv6, and dhcpcd's automatic Router Solicitations cause problems * with devices that don't expect them. */ g_ptr_array_add (argv, (gpointer) "-4"); -#endif hostname = nm_dhcp_client_get_hostname (client); @@ -153,24 +156,30 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last g_ptr_array_add (argv, (gpointer) iface); g_ptr_array_add (argv, NULL); - cmd_str = g_strjoinv (" ", (gchar **) argv->pdata); - _LOGD ("running: %s", cmd_str); - g_free (cmd_str); - - if (g_spawn_async (NULL, (char **) argv->pdata, NULL, - G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, - nm_utils_setpgid, NULL, &pid, &error)) { - g_assert (pid > 0); - _LOGI ("dhcpcd started with pid %d", pid); - nm_dhcp_client_watch_child (client, pid); - } else { - _LOGW ("dhcpcd failed to start, error: '%s'", error->message); - g_error_free (error); + _LOGD ("running: %s", + (cmd_str = g_strjoinv (" ", (char **) argv->pdata))); + + if (!g_spawn_async (NULL, + (char **) argv->pdata, NULL, + G_SPAWN_DO_NOT_REAP_CHILD + | G_SPAWN_STDOUT_TO_DEV_NULL + | G_SPAWN_STDERR_TO_DEV_NULL, + nm_utils_setpgid, + NULL, + &pid, + &local)) { + nm_utils_error_set (error, + NM_UTILS_ERROR_UNKNOWN, + "dhcpcd failed to start: %s", + local->message); + g_error_free (local); + return FALSE; } - g_free (pid_contents); - g_ptr_array_free (argv, TRUE); - return pid > 0 ? TRUE : FALSE; + nm_assert (pid > 0); + _LOGI ("dhcpcd started with pid %d", pid); + nm_dhcp_client_watch_child (client, pid); + return TRUE; } static gboolean @@ -179,11 +188,10 @@ ip6_start (NMDhcpClient *client, const struct in6_addr *ll_addr, NMSettingIP6ConfigPrivacy privacy, GBytes *duid, - guint needed_prefixes) + guint needed_prefixes, + GError **error) { - NMDhcpDhcpcd *self = NM_DHCP_DHCPCD (client); - - _LOGW ("the dhcpcd backend does not support IPv6"); + nm_utils_error_set_literal (error, NM_UTILS_ERROR_UNKNOWN, "dhcpcd plugin does not support IPv6"); return FALSE; } diff --git a/src/dhcp/nm-dhcp-helper.c b/src/dhcp/nm-dhcp-helper.c index 8ea55061..7f1d2a7b 100644 --- a/src/dhcp/nm-dhcp-helper.c +++ b/src/dhcp/nm-dhcp-helper.c @@ -31,7 +31,7 @@ /*****************************************************************************/ -#ifdef NM_MORE_LOGGING +#if NM_MORE_LOGGING #define _NMLOG_ENABLED(level) TRUE #else #define _NMLOG_ENABLED(level) ((level) <= LOG_ERR) @@ -118,7 +118,7 @@ kill_pid (void) if (pid_str) pid = strtol (pid_str, NULL, 10); if (pid) { - _LOGI ("a fatal error occured, kill dhclient instance with pid %d\n", pid); + _LOGI ("a fatal error occurred, kill dhclient instance with pid %d", pid); kill (pid, SIGTERM); } } diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c index 67254323..5ae16d72 100644 --- a/src/dhcp/nm-dhcp-manager.c +++ b/src/dhcp/nm-dhcp-manager.c @@ -172,22 +172,39 @@ client_start (NMDhcpManager *self, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, const char *last_ip4_address, - guint needed_prefixes) + guint needed_prefixes, + GError **error) { NMDhcpManagerPrivate *priv; NMDhcpClient *client; gboolean success = FALSE; + gsize hwaddr_len; - g_return_val_if_fail (self, NULL); g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL); g_return_val_if_fail (ifindex > 0, NULL); g_return_val_if_fail (uuid != NULL, NULL); g_return_val_if_fail (!dhcp_client_id || g_bytes_get_size (dhcp_client_id) >= 2, NULL); + g_return_val_if_fail (!error || !*error, NULL); + + if (!hwaddr) { + nm_utils_error_set (error, + NM_UTILS_ERROR_UNKNOWN, + "missing MAC address"); + return NULL; + } + + hwaddr_len = g_bytes_get_size (hwaddr); + if ( hwaddr_len == 0 + || hwaddr_len > NM_UTILS_HWADDR_LEN_MAX) { + nm_utils_error_set (error, + NM_UTILS_ERROR_UNKNOWN, + "invalid MAC address"); + g_return_val_if_reached (NULL) ; + } priv = NM_DHCP_MANAGER_GET_PRIVATE (self); - if (!priv->client_factory) - return NULL; + nm_assert (priv->client_factory); /* Kill any old client instance */ client = get_client_for_ifindex (self, addr_family, ifindex); @@ -216,10 +233,24 @@ client_start (NMDhcpManager *self, c_list_link_tail (&priv->dhcp_client_lst_head, &client->dhcp_client_lst); g_signal_connect (client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (client_state_changed), self); - if (addr_family == AF_INET) - success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, last_ip4_address); - else - success = nm_dhcp_client_start_ip6 (client, dhcp_client_id, enforce_duid, dhcp_anycast_addr, ipv6_ll_addr, hostname, privacy, needed_prefixes); + if (addr_family == AF_INET) { + success = nm_dhcp_client_start_ip4 (client, + dhcp_client_id, + dhcp_anycast_addr, + hostname, + last_ip4_address, + error); + } else { + success = nm_dhcp_client_start_ip6 (client, + dhcp_client_id, + enforce_duid, + dhcp_anycast_addr, + ipv6_ll_addr, + hostname, + privacy, + needed_prefixes, + error); + } if (!success) { remove_client_unref (self, client); @@ -245,7 +276,8 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self, GBytes *dhcp_client_id, guint32 timeout, const char *dhcp_anycast_addr, - const char *last_ip_address) + const char *last_ip_address, + GError **error) { NMDhcpManagerPrivate *priv; const char *hostname = NULL; @@ -282,7 +314,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self, return client_start (self, AF_INET, multi_idx, iface, ifindex, hwaddr, uuid, route_table, route_metric, NULL, dhcp_client_id, 0, timeout, dhcp_anycast_addr, hostname, - use_fqdn, FALSE, 0, last_ip_address, 0); + use_fqdn, FALSE, 0, last_ip_address, 0, error); } /* Caller owns a reference to the NMDhcpClient on return */ @@ -304,7 +336,8 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, const char *dhcp_anycast_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes) + guint needed_prefixes, + GError **error) { NMDhcpManagerPrivate *priv; const char *hostname = NULL; @@ -319,7 +352,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, return client_start (self, AF_INET6, multi_idx, iface, ifindex, hwaddr, uuid, route_table, route_metric, ll_addr, duid, enforce_duid, timeout, dhcp_anycast_addr, hostname, TRUE, info_only, - privacy, NULL, needed_prefixes); + privacy, NULL, needed_prefixes, error); } void @@ -380,7 +413,7 @@ nm_dhcp_manager_init (NMDhcpManager *self) NM_CONFIG_KEYFILE_KEY_MAIN_DHCP, NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY); client = client_free; - if (nm_config_get_configure_and_quit (config)) { + if (nm_config_get_configure_and_quit (config) == NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED) { client_factory = &_nm_dhcp_client_factory_internal; if (client && !nm_streq (client, client_factory->name)) nm_log_info (LOGD_DHCP, "dhcp-init: Using internal DHCP client since configure-and-quit is set."); @@ -409,7 +442,7 @@ nm_dhcp_manager_init (NMDhcpManager *self) } } - nm_assert (client_factory); + g_return_if_fail (client_factory); nm_log_info (LOGD_DHCP, "dhcp-init: Using DHCP client '%s'", client_factory->name); diff --git a/src/dhcp/nm-dhcp-manager.h b/src/dhcp/nm-dhcp-manager.h index 7eb32c37..1d9e5c21 100644 --- a/src/dhcp/nm-dhcp-manager.h +++ b/src/dhcp/nm-dhcp-manager.h @@ -59,7 +59,8 @@ NMDhcpClient * nm_dhcp_manager_start_ip4 (NMDhcpManager *manager, GBytes *dhcp_client_id, guint32 timeout, const char *dhcp_anycast_addr, - const char *last_ip_address); + const char *last_ip_address, + GError **error); NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, struct _NMDedupMultiIndex *multi_idx, @@ -78,7 +79,8 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, const char *dhcp_anycast_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes); + guint needed_prefixes, + GError **error); /* For testing only */ extern const char* nm_dhcp_helper_path; diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c index 2d0202bb..5b7b5fbe 100644 --- a/src/dhcp/nm-dhcp-systemd.c +++ b/src/dhcp/nm-dhcp-systemd.c @@ -32,6 +32,7 @@ #include "nm-utils/unaligned.h" #include "nm-utils.h" +#include "nm-config.h" #include "nm-dhcp-utils.h" #include "NetworkManagerUtils.h" #include "platform/nm-platform.h" @@ -121,6 +122,7 @@ static const ReqOption dhcp4_requests[] = { { SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, REQPREFIX "rfc3442_classless_static_routes", TRUE }, { SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE, REQPREFIX "ms_classless_static_routes", TRUE }, { SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, REQPREFIX "wpad", TRUE }, + { SD_DHCP_OPTION_ROOT_PATH, REQPREFIX "root_path", TRUE }, /* Internal values */ { SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, REQPREFIX "expiry", FALSE }, @@ -432,6 +434,13 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, add_option (options, dhcp4_requests, SD_DHCP_OPTION_NTP_SERVER, str->str); } + /* Root path */ + r = sd_dhcp_lease_get_root_path (lease, &s); + if (r >= 0) { + LOG_LEASE (LOGD_DHCP4, "root path '%s'", s); + add_option (options, dhcp4_requests, SD_DHCP_OPTION_ROOT_PATH, s); + } + r = sd_dhcp_lease_get_vendor_specific (lease, &data, &data_len); if (r >= 0) metered = !!memmem (data, data_len, "ANDROID_METERED", NM_STRLEN ("ANDROID_METERED")); @@ -445,10 +454,30 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, static char * get_leasefile_path (int addr_family, const char *iface, const char *uuid) { - return g_strdup_printf (NMSTATEDIR "/internal%s-%s-%s.lease", - addr_family == AF_INET6 ? "6" : "", - uuid, - iface); + char *rundir_path; + char *statedir_path; + + rundir_path = g_strdup_printf (NMRUNDIR "/internal%s-%s-%s.lease", + addr_family == AF_INET6 ? "6" : "", + uuid, + iface); + + if (g_file_test (rundir_path, G_FILE_TEST_EXISTS)) + return rundir_path; + + statedir_path = g_strdup_printf (NMSTATEDIR "/internal%s-%s-%s.lease", + addr_family == AF_INET6 ? "6" : "", + uuid, + iface); + + if ( g_file_test (statedir_path, G_FILE_TEST_EXISTS) + || nm_config_get_configure_and_quit (nm_config_get ()) != NM_CONFIG_CONFIGURE_AND_QUIT_INITRD) { + g_free (rundir_path); + return statedir_path; + } else { + g_free (statedir_path); + return rundir_path; + } } /*****************************************************************************/ @@ -567,7 +596,10 @@ get_arp_type (GBytes *hwaddr) } static gboolean -ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address) +ip4_start (NMDhcpClient *client, + const char *dhcp_anycast_addr, + const char *last_ip4_address, + GError **error) { NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); @@ -590,7 +622,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last r = sd_dhcp_client_new (&priv->client4, FALSE); if (r < 0) { - _LOGW ("failed to create client (%d)", r); + nm_utils_error_set_errno (error, r, "failed to create dhcp-client: %s"); return FALSE; } @@ -598,8 +630,8 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last r = sd_dhcp_client_attach_event (priv->client4, NULL, 0); if (r < 0) { - _LOGW ("failed to attach event (%d)", r); - goto error; + nm_utils_error_set_errno (error, r, "failed to attach event: %s"); + goto errout; } hwaddr = nm_dhcp_client_get_hw_addr (client); @@ -613,21 +645,21 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last len, get_arp_type (hwaddr)); if (r < 0) { - _LOGW ("failed to set MAC address (%d)", r); - goto error; + nm_utils_error_set_errno (error, r, "failed to set MAC address: %s"); + goto errout; } } r = sd_dhcp_client_set_ifindex (priv->client4, nm_dhcp_client_get_ifindex (client)); if (r < 0) { - _LOGW ("failed to set ififindex (%d)", r); - goto error; + nm_utils_error_set_errno (error, r, "failed to set ifindex: %s"); + goto errout; } r = sd_dhcp_client_set_callback (priv->client4, dhcp_event_cb, client); if (r < 0) { - _LOGW ("failed to set callback (%d)", r); - goto error; + nm_utils_error_set_errno (error, r, "failed to set callback: %s"); + goto errout; } dhcp_lease_load (&lease, priv->lease_file); @@ -640,8 +672,8 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last if (last_addr.s_addr) { r = sd_dhcp_client_set_request_address (priv->client4, &last_addr); if (r < 0) { - _LOGW ("failed to set last IPv4 address (%d)", r); - goto error; + nm_utils_error_set_errno (error, r, "failed to set last IPv4 address: %s"); + goto errout; } } @@ -681,25 +713,25 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last */ r = sd_dhcp_client_set_hostname (priv->client4, hostname); if (r < 0) { - _LOGW ("failed to set DHCP hostname to '%s' (%d)", hostname, r); - goto error; + nm_utils_error_set_errno (error, r, "failed to set DHCP hostname: %s"); + goto errout; } } r = sd_dhcp_client_start (priv->client4); if (r < 0) { - _LOGW ("failed to start client (%d)", r); - goto error; + nm_utils_error_set_errno (error, r, "failed to start DHCP client: %s"); + goto errout; } nm_dhcp_client_start_timeout (client); success = TRUE; -error: +errout: sd_dhcp_lease_unref (lease); if (!success) - priv->client4 = sd_dhcp_client_unref (priv->client4); + sd_dhcp_client_unref (g_steal_pointer (&priv->client4)); return success; } @@ -864,7 +896,8 @@ ip6_start (NMDhcpClient *client, const struct in6_addr *ll_addr, NMSettingIP6ConfigPrivacy privacy, GBytes *duid, - guint needed_prefixes) + guint needed_prefixes, + GError **error) { NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); @@ -888,12 +921,12 @@ ip6_start (NMDhcpClient *client, r = sd_dhcp6_client_new (&priv->client6); if (r < 0) { - _LOGW ("failed to create client (%d)", r); + nm_utils_error_set_errno (error, r, "failed to create dhcp-client: %s"); return FALSE; } if (needed_prefixes > 0) { - _LOGW ("dhcp-client6: prefix delegation not yet supported, won't supply %d prefixes\n", + _LOGW ("dhcp-client6: prefix delegation not yet supported, won't supply %d prefixes", needed_prefixes); } @@ -907,14 +940,14 @@ ip6_start (NMDhcpClient *client, &duid_arr[2], duid_len - 2); if (r < 0) { - _LOGW ("failed to set DUID (%d)", r); + nm_utils_error_set_errno (error, r, "failed to set DUID: %s"); return FALSE; } r = sd_dhcp6_client_attach_event (priv->client6, NULL, 0); if (r < 0) { - _LOGW ("failed to attach event (%d)", r); - goto error; + nm_utils_error_set_errno (error, r, "failed to attach event: %s"); + goto errout; } hwaddr = nm_dhcp_client_get_hw_addr (client); @@ -928,21 +961,21 @@ ip6_start (NMDhcpClient *client, len, get_arp_type (hwaddr)); if (r < 0) { - _LOGW ("failed to set MAC address (%d)", r); - goto error; + nm_utils_error_set_errno (error, r, "failed to set MAC address: %s"); + goto errout; } } r = sd_dhcp6_client_set_ifindex (priv->client6, nm_dhcp_client_get_ifindex (client)); if (r < 0) { - _LOGW ("failed to set ifindex (%d)", r); - goto error; + nm_utils_error_set_errno (error, r, "failed to set ifindex: %s"); + goto errout; } r = sd_dhcp6_client_set_callback (priv->client6, dhcp6_event_cb, client); if (r < 0) { - _LOGW ("failed to set callback (%d)", r); - goto error; + nm_utils_error_set_errno (error, r, "failed to set callback: %s"); + goto errout; } /* Add requested options */ @@ -953,30 +986,29 @@ ip6_start (NMDhcpClient *client, r = sd_dhcp6_client_set_local_address (priv->client6, ll_addr); if (r < 0) { - _LOGW ("failed to set local address (%d)", r); - goto error; + nm_utils_error_set_errno (error, r, "failed to set local address: %s"); + goto errout; } hostname = nm_dhcp_client_get_hostname (client); r = sd_dhcp6_client_set_fqdn (priv->client6, hostname); if (r < 0) { - _LOGW ("failed to set DHCP hostname to '%s' (%d)", hostname, r); - goto error; + nm_utils_error_set_errno (error, r, "failed to set DHCP hostname: %s"); + goto errout; } r = sd_dhcp6_client_start (priv->client6); if (r < 0) { - _LOGW ("failed to start client (%d)", r); - goto error; + nm_utils_error_set_errno (error, r, "failed to start client: %s"); + goto errout; } nm_dhcp_client_start_timeout (client); return TRUE; -error: - sd_dhcp6_client_unref (priv->client6); - priv->client6 = NULL; +errout: + sd_dhcp6_client_unref (g_steal_pointer (&priv->client6)); return FALSE; } diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c index 9185a135..6bbc670b 100644 --- a/src/dhcp/nm-dhcp-utils.c +++ b/src/dhcp/nm-dhcp-utils.c @@ -594,7 +594,7 @@ ip6_add_domain_search (gpointer data, gpointer user_data) NMPlatformIP6Address nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options) { - gs_strfreev gchar **split_addr = NULL; + gs_strfreev char **split_addr = NULL; NMPlatformIP6Address address = { 0, }; struct in6_addr tmp_addr; char *str = NULL; diff --git a/src/dhcp/tests/meson.build b/src/dhcp/tests/meson.build index 9d8be427..0fee26b2 100644 --- a/src/dhcp/tests/meson.build +++ b/src/dhcp/tests/meson.build @@ -8,7 +8,6 @@ foreach test_unit: test_units test_unit, test_unit + '.c', dependencies: test_nm_dep, - c_args: nm_build_cflags, ) test( diff --git a/src/dhcp/tests/test-dhcp-dhclient.c b/src/dhcp/tests/test-dhcp-dhclient.c index 2f369aac..edac4257 100644 --- a/src/dhcp/tests/test-dhcp-dhclient.c +++ b/src/dhcp/tests/test-dhcp-dhclient.c @@ -86,7 +86,7 @@ test_config (const char *orig, if (expected_new_client_id) { g_assert (new_client_id); g_assert (g_bytes_equal (new_client_id, expected_new_client_id)); - } else + } else g_assert (new_client_id == NULL); } @@ -104,6 +104,7 @@ static const char *orig_missing_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -132,6 +133,7 @@ static const char *override_client_id_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -161,6 +163,7 @@ static const char *quote_client_id_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -190,6 +193,7 @@ static const char *quote_client_id_expected_2 = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -219,6 +223,7 @@ static const char *hex_zero_client_id_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -248,6 +253,7 @@ static const char *ascii_client_id_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -277,6 +283,7 @@ static const char *hex_single_client_id_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -310,6 +317,7 @@ static const char *existing_hex_client_id_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -347,6 +355,7 @@ static const char *existing_escaped_client_id_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -385,6 +394,7 @@ static const char *existing_ascii_client_id_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -419,7 +429,8 @@ static const char *fqdn_expected = \ "also request ms-classless-static-routes;\n" "also request static-routes;\n" "also request wpad;\n" - "also request ntp-servers;\n\n"; + "also request ntp-servers;\n" + "also request root-path;\n\n"; static void test_fqdn (void) @@ -455,6 +466,7 @@ static const char *fqdn_options_override_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n" "# FQDN options from /path/to/dhclient.conf\n" "send fqdn.encoded off;\n" @@ -492,6 +504,7 @@ static const char *override_hostname_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -580,6 +593,7 @@ static const char *existing_alsoreq_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -618,6 +632,7 @@ static const char *existing_req_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -657,6 +672,7 @@ static const char *existing_multiline_alsoreq_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -675,27 +691,18 @@ test_existing_multiline_alsoreq (void) static void test_one_duid (const char *escaped, const guint8 *unescaped, guint len) { - GBytes *t; - char *w; - gsize t_len; - gconstpointer t_arr; - - t = nm_dhcp_dhclient_unescape_duid (escaped); - g_assert (t); - t_arr = g_bytes_get_data (t, &t_len); - g_assert (t_arr); - g_assert_cmpint (t_len, ==, len); - g_assert_cmpint (memcmp (t_arr, unescaped, len), ==, 0); - g_bytes_unref (t); - - t = g_bytes_new_static (unescaped, len); - w = nm_dhcp_dhclient_escape_duid (t); + gs_unref_bytes GBytes *t1 = NULL; + gs_unref_bytes GBytes *t2 = NULL; + gs_free char *w = NULL; + + t1 = nm_dhcp_dhclient_unescape_duid (escaped); + g_assert (t1); + g_assert (nm_utils_gbytes_equal_mem (t1, unescaped, len)); + + t2 = g_bytes_new (unescaped, len); + w = nm_dhcp_dhclient_escape_duid (t2); g_assert (w); - g_assert_cmpint (strlen (escaped), ==, strlen (w)); g_assert_cmpstr (escaped, ==, w); - - g_bytes_unref (t); - g_free (w); } static void @@ -735,15 +742,11 @@ test_read_duid_from_leasefile (void) 0x13, 0x60, 0x67, 0x20, 0xec, 0x4c, 0x70 }; gs_unref_bytes GBytes *duid = NULL; GError *error = NULL; - gconstpointer duid_arr; - gsize duid_len; duid = nm_dhcp_dhclient_read_duid (TEST_DIR"/test-dhclient-duid.leases", &error); - g_assert_no_error (error); - g_assert (duid); - duid_arr = g_bytes_get_data (duid, &duid_len); - g_assert_cmpint (duid_len, ==, sizeof (expected)); - g_assert_cmpint (memcmp (duid_arr, expected, duid_len), ==, 0); + nmtst_assert_success (duid, error); + + g_assert (nm_utils_gbytes_equal_mem (duid, expected, G_N_ELEMENTS (expected))); } static void @@ -903,6 +906,7 @@ static const char *interface1_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -948,6 +952,7 @@ static const char *interface2_expected = \ "also request static-routes;\n" "also request wpad;\n" "also request ntp-servers;\n" + "also request root-path;\n" "\n"; static void @@ -962,6 +967,100 @@ test_interface2 (void) } static void +test_structured (void) +{ + gs_unref_bytes GBytes *new_client_id = NULL; + const guint8 bytes[] = "sad-and-useless"; + + static const char *const orig = \ + "interface \"eth0\" { \n" + " send host-name \"useless.example.com\";\n" + " hardware ethernet de:ad:80:86:ba:be;\n" + " send dhcp-client-identifier \"sad-and-useless\";\n" + " script \"/bin/useless\";\n" + " send dhcp-lease-time 8086;\n" + " request subnet-mask, broadcast-address, time-offset, routers,\n" + " domain-search, domain-name, host-name;\n" + " require subnet-mask;\n" + "} \n" + "\n" + " interface \"eth1\" { \n" + " send host-name \"sad.example.com\";\n" + " hardware ethernet de:ca:f6:66:ca:fe;\n" + " send dhcp-client-identifier \"useless-and-miserable\";\n" + " script \"/bin/miserable\";\n" + " send dhcp-lease-time 1337;\n" + " request subnet-mask, broadcast-address, time-offset, routers,\n" + " domain-search, domain-name, domain-name-servers, host-name;\n" + " require subnet-mask, domain-name-servers;\n" + " } \n" + "\n" + "pseudo \"secondary\" \"eth0\" { \n" + " send dhcp-client-identifier \"sad-useless-and-secondary\";\n" + " script \"/bin/secondary\";\n" + " send host-name \"secondary.useless.example.com\";\n" + " send dhcp-lease-time 666;\n" + " request routers;\n" + " require routers;\n" + " } \n" + "\n" + " pseudo \"tertiary\" \"eth0\" { \n" + " send dhcp-client-identifier \"sad-useless-and-tertiary\";\n" + " script \"/bin/tertiary\";\n" + " send host-name \"tertiary.useless.example.com\";\n" + "} \n" + "\n" + " alias{ \n" + " interface \"eth0\";\n" + " fixed-address 192.0.2.1;\n" + " option subnet-mask 255.255.255.0;\n" + " } \n" + " lease { \n" + " interface \"eth0\";\n" + " fixed-address 192.0.2.2;\n" + " option subnet-mask 255.255.255.0;\n" + " } \n"; + + static const char *const expected = \ + "# Created by NetworkManager\n" + "# Merged from /path/to/dhclient.conf\n" + "\n" + "send host-name \"useless.example.com\";\n" + "hardware ethernet de:ad:80:86:ba:be;\n" + "send dhcp-client-identifier \"sad-and-useless\";\n" + "send dhcp-lease-time 8086;\n" + "require subnet-mask;\n" + "\n" + "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" + "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" + "option wpad code 252 = string;\n" + "\n" + "request; # override dhclient defaults\n" + "also request subnet-mask;\n" + "also request broadcast-address;\n" + "also request time-offset;\n" + "also request routers;\n" + "also request domain-search;\n" + "also request domain-name;\n" + "also request host-name;\n" + "also request rfc3442-classless-static-routes;\n" + "also request ms-classless-static-routes;\n" + "also request static-routes;\n" + "also request wpad;\n" + "also request ntp-servers;\n" + "also request root-path;\n" + "\n"; + + new_client_id = g_bytes_new (bytes, sizeof (bytes) - 1); + test_config (orig, expected, + AF_INET, NULL, 0, FALSE, + NULL, + new_client_id, + "eth0", + NULL); +} + +static void test_config_req_intf (void) { static const char *const orig = \ @@ -1005,6 +1104,7 @@ test_config_req_intf (void) "also request ms-classless-static-routes;\n" "also request static-routes;\n" "also request wpad;\n" + "also request root-path;\n" "\n"; test_config (orig, expected, @@ -1046,6 +1146,7 @@ main (int argc, char **argv) g_test_add_func ("/dhcp/dhclient/interface/1", test_interface1); g_test_add_func ("/dhcp/dhclient/interface/2", test_interface2); g_test_add_func ("/dhcp/dhclient/config/req_intf", test_config_req_intf); + g_test_add_func ("/dhcp/dhclient/structured", test_structured); g_test_add_func ("/dhcp/dhclient/read_duid_from_leasefile", test_read_duid_from_leasefile); g_test_add_func ("/dhcp/dhclient/read_commented_duid_from_leasefile", test_read_commented_duid_from_leasefile); diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index 91f4c55b..b48c6b87 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -306,8 +306,6 @@ start_dnsmasq (NMDnsDnsmasq *self) const char *argv[15]; GPid pid = 0; guint idx = 0; - NMDBusManager *dbus_mgr; - GDBusConnection *connection; if (priv->running) { /* the dnsmasq process is running. Nothing to do. */ @@ -358,22 +356,16 @@ start_dnsmasq (NMDnsDnsmasq *self) return; } - dbus_mgr = nm_dbus_manager_get (); - g_return_if_fail (dbus_mgr); - - connection = nm_dbus_manager_get_connection (dbus_mgr); - g_return_if_fail (connection); - priv->dnsmasq_cancellable = g_cancellable_new (); - g_dbus_proxy_new (connection, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - DNSMASQ_DBUS_SERVICE, - DNSMASQ_DBUS_PATH, - DNSMASQ_DBUS_SERVICE, - priv->dnsmasq_cancellable, - dnsmasq_proxy_cb, - self); + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + DNSMASQ_DBUS_SERVICE, + DNSMASQ_DBUS_PATH, + DNSMASQ_DBUS_SERVICE, + priv->dnsmasq_cancellable, + dnsmasq_proxy_cb, + self); } static gboolean @@ -409,7 +401,7 @@ update (NMDnsPlugin *plugin, /*****************************************************************************/ static void -child_quit (NMDnsPlugin *plugin, gint status) +child_quit (NMDnsPlugin *plugin, int status) { NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin); NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE (self); diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index a29fd81f..6a59b41c 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -310,7 +310,7 @@ _config_data_free (NMDnsConfigData *data) g_slice_free (NMDnsConfigData, data); } -static gint +static int _ip_config_data_cmp (const NMDnsIPConfigData *a, const NMDnsIPConfigData *b) { int a_prio, b_prio; @@ -333,7 +333,7 @@ _ip_config_data_cmp (const NMDnsIPConfigData *a, const NMDnsIPConfigData *b) return 0; } -static gint +static int _ip_config_lst_cmp (const CList *a, const CList *b, const void *user_data) @@ -482,7 +482,7 @@ merge_one_ip_config (NMResolvConfData *rc, } static GPid -run_netconfig (NMDnsManager *self, GError **error, gint *stdin_fd) +run_netconfig (NMDnsManager *self, GError **error, int *stdin_fd) { char *argv[5]; gs_free char *tmp = NULL; @@ -533,7 +533,7 @@ dispatch_netconfig (NMDnsManager *self, GError **error) { GPid pid; - gint fd; + int fd; int status; gssize l; nm_auto_free_gstring GString *str = NULL; @@ -970,6 +970,8 @@ compute_hash (NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer else { const CList *head; + /* FIXME(ip-config-checksum): this relies on the fact that an IP + * configuration without DNS parameters gives a zero checksum. */ head = _ip_config_lst_head (self); c_list_for_each_entry (ip_data, head, ip_config_lst) nm_ip_config_hash (ip_data->ip_config, sum, TRUE); diff --git a/src/dns/nm-dns-plugin.c b/src/dns/nm-dns-plugin.c index d9400e3e..48f04b00 100644 --- a/src/dns/nm-dns-plugin.c +++ b/src/dns/nm-dns-plugin.c @@ -124,7 +124,7 @@ _clear_pidfile (NMDnsPlugin *self) static void kill_existing (const char *progname, const char *pidfile, const char *kill_match) { - glong pid; + long pid; gs_free char *contents = NULL; gs_free char *cmdline_contents = NULL; guint64 start_time; @@ -167,7 +167,7 @@ out: } static void -watch_cb (GPid pid, gint status, gpointer user_data) +watch_cb (GPid pid, int status, gpointer user_data) { NMDnsPlugin *self = NM_DNS_PLUGIN (user_data); NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self); diff --git a/src/dns/nm-dns-plugin.h b/src/dns/nm-dns-plugin.h index 80b77d95..8a55921d 100644 --- a/src/dns/nm-dns-plugin.h +++ b/src/dns/nm-dns-plugin.h @@ -70,7 +70,7 @@ typedef struct { * by NMDnsManager. If the subclass decides the exit status (as returned * by waitpid(2)) is fatal it should then emit the 'failed' signal. */ - void (*child_quit) (NMDnsPlugin *self, gint status); + void (*child_quit) (NMDnsPlugin *self, int status); } NMDnsPluginClass; GType nm_dns_plugin_get_type (void); diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index 1a73aae1..10797b86 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -65,7 +65,6 @@ typedef struct { GDBusProxy *resolve; GCancellable *init_cancellable; GCancellable *update_cancellable; - GCancellable *mdns_cancellable; CList request_queue_lst_head; } NMDnsSystemdResolvedPrivate; @@ -130,7 +129,7 @@ call_done (GObject *source, GAsyncResult *r, gpointer user_data) if (!v) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - _LOGW ("Failed: %s\n", error->message); + _LOGW ("Failed: %s", error->message); g_error_free (error); } } @@ -192,7 +191,8 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) GVariantBuilder dns, domains; NMCListElem *elem; NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; - const char *mdns_arg = NULL; + NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; + const char *mdns_arg = NULL, *llmnr_arg = NULL; g_variant_builder_init (&dns, G_VARIANT_TYPE ("(ia(iay))")); g_variant_builder_add (&dns, "i", ic->ifindex); @@ -208,8 +208,10 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) update_add_ip_config (self, &dns, &domains, data); - if (NM_IS_IP4_CONFIG (ip_config)) + if (NM_IS_IP4_CONFIG (ip_config)) { mdns = NM_MAX (mdns, nm_ip4_config_mdns_get (NM_IP4_CONFIG (ip_config))); + llmnr = NM_MAX (llmnr, nm_ip4_config_llmnr_get (NM_IP4_CONFIG (ip_config))); + } } g_variant_builder_close (&dns); @@ -231,6 +233,22 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) } nm_assert (mdns_arg); + switch (llmnr) { + case NM_SETTING_CONNECTION_LLMNR_NO: + llmnr_arg = "no"; + break; + case NM_SETTING_CONNECTION_LLMNR_RESOLVE: + llmnr_arg = "resolve"; + break; + case NM_SETTING_CONNECTION_LLMNR_YES: + llmnr_arg = "yes"; + break; + case NM_SETTING_CONNECTION_LLMNR_DEFAULT: + llmnr_arg = ""; + break; + } + nm_assert (llmnr_arg); + _request_item_append (&priv->request_queue_lst_head, "SetLinkDNS", g_variant_builder_end (&dns)); @@ -240,6 +258,9 @@ prepare_one_interface (NMDnsSystemdResolved *self, InterfaceConfig *ic) _request_item_append (&priv->request_queue_lst_head, "SetLinkMulticastDNS", g_variant_new ("(is)", ic->ifindex, mdns_arg ?: "")); + _request_item_append (&priv->request_queue_lst_head, + "SetLinkLLMNR", + g_variant_new ("(is)", ic->ifindex, llmnr_arg ?: "")); } static void @@ -370,28 +391,20 @@ static void nm_dns_systemd_resolved_init (NMDnsSystemdResolved *self) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); - NMDBusManager *dbus_mgr; - GDBusConnection *connection; c_list_init (&priv->request_queue_lst_head); - dbus_mgr = nm_dbus_manager_get (); - g_return_if_fail (dbus_mgr); - - connection = nm_dbus_manager_get_connection (dbus_mgr); - g_return_if_fail (connection); - priv->init_cancellable = g_cancellable_new (); - g_dbus_proxy_new (connection, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, - NULL, - SYSTEMD_RESOLVED_DBUS_SERVICE, - SYSTEMD_RESOLVED_DBUS_PATH, - SYSTEMD_RESOLVED_DBUS_SERVICE ".Manager", - priv->init_cancellable, - resolved_proxy_created, - self); + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + SYSTEMD_RESOLVED_DBUS_SERVICE, + SYSTEMD_RESOLVED_DBUS_PATH, + SYSTEMD_RESOLVED_DBUS_SERVICE ".Manager", + priv->init_cancellable, + resolved_proxy_created, + self); } NMDnsPlugin * @@ -410,7 +423,6 @@ dispose (GObject *object) g_clear_object (&priv->resolve); nm_clear_g_cancellable (&priv->init_cancellable); nm_clear_g_cancellable (&priv->update_cancellable); - nm_clear_g_cancellable (&priv->mdns_cancellable); G_OBJECT_CLASS (nm_dns_systemd_resolved_parent_class)->dispose (object); } diff --git a/src/dns/nm-dns-unbound.c b/src/dns/nm-dns-unbound.c index e06128aa..b900f29e 100644 --- a/src/dns/nm-dns-unbound.c +++ b/src/dns/nm-dns-unbound.c @@ -43,7 +43,7 @@ update (NMDnsPlugin *plugin, const CList *ip_config_lst_head, const char *hostname) { - char *argv[] = { DNSSEC_TRIGGER_SCRIPT, "--async", "--update", NULL }; + char *argv[] = { DNSSEC_TRIGGER_PATH, "--async", "--update", NULL }; int status; /* TODO: We currently call a script installed with the dnssec-trigger diff --git a/src/dnsmasq/nm-dnsmasq-manager.c b/src/dnsmasq/nm-dnsmasq-manager.c index 041e75ea..09889441 100644 --- a/src/dnsmasq/nm-dnsmasq-manager.c +++ b/src/dnsmasq/nm-dnsmasq-manager.c @@ -104,7 +104,7 @@ nm_cmd_line_to_str (NMCmdLine *cmd) char *str; g_ptr_array_add (cmd->array, NULL); - str = g_strjoinv (" ", (gchar **) cmd->array->pdata); + str = g_strjoinv (" ", (char **) cmd->array->pdata); g_ptr_array_remove_index (cmd->array, cmd->array->len - 1); return str; @@ -119,7 +119,7 @@ nm_cmd_line_add_string (NMCmdLine *cmd, const char *str) /*****************************************************************************/ static void -dm_watch_cb (GPid pid, gint status, gpointer user_data) +dm_watch_cb (GPid pid, int status, gpointer user_data) { NMDnsMasqManager *manager = NM_DNSMASQ_MANAGER (user_data); NMDnsMasqManagerPrivate *priv = NM_DNSMASQ_MANAGER_GET_PRIVATE (manager); @@ -187,7 +187,7 @@ create_dm_cmd_line (const char *iface, * as the gateway or whatever. So tell dnsmasq not to use any config file * at all. */ - nm_cmd_line_add_string (cmd, "--conf-file"); + nm_cmd_line_add_string (cmd, "--conf-file=/dev/null"); nm_cmd_line_add_string (cmd, "--no-hosts"); nm_cmd_line_add_string (cmd, "--keep-in-foreground"); @@ -249,6 +249,11 @@ create_dm_cmd_line (const char *iface, nm_cmd_line_add_string (cmd, "--dhcp-lease-max=50"); + g_string_append (s, "--dhcp-leasefile=" NMSTATEDIR); + g_string_append_printf (s, "/dnsmasq-%s.leases", iface); + nm_cmd_line_add_string (cmd, s->str); + g_string_truncate (s, 0); + g_string_append (s, "--pid-file="); g_string_append (s, pidfile); nm_cmd_line_add_string (cmd, s->str); diff --git a/src/initrd/nm-initrd-generator.c b/src/initrd/nm-initrd-generator.c new file mode 100644 index 00000000..eb9a38df --- /dev/null +++ b/src/initrd/nm-initrd-generator.c @@ -0,0 +1,139 @@ +/* NetworkManager initrd configuration generator + * + * 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 (C) 2018 Red Hat, Inc. + */ + +#include "nm-default.h" +#include "nm-core-utils.h" +#include "nm-core-internal.h" +#include "nm-keyfile-internal.h" +#include "nm-initrd-generator.h" +#include "nm-utils/nm-io-utils.h" + +/*****************************************************************************/ + +#define _NMLOG(level, domain, ...) \ + nm_log ((level), (domain), NULL, NULL, \ + "initrd-generator: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__) \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)) + +/*****************************************************************************/ + +static void +output_conn (gpointer key, gpointer value, gpointer user_data) +{ + const char *basename = key; + NMConnection *connection = value; + char *connections_dir = user_data; + GKeyFile *file; + gs_free char *data = NULL; + GError *error = NULL; + gsize len; + + if (!nm_connection_normalize (connection, NULL, NULL, &error)) { + g_print ("%s\n", error->message); + g_error_free (error); + return; + } + + file = nm_keyfile_write (connection, NULL, NULL, &error); + if (file == NULL) { + g_print ("%s\n", error->message); + g_error_free (error); + return; + } + + data = g_key_file_to_data (file, &len, &error); + if (!data) { + g_print ("%s\n", error->message); + g_error_free (error); + } else if (connections_dir) { + gs_free char *basename_w_ext = g_strconcat (basename, ".nmconnection", NULL); + char *filename = g_build_filename (connections_dir, basename_w_ext, NULL); + + if (!nm_utils_file_set_contents (filename, data, len, 0600, &error)) { + g_print ("%s\n", error->message); + g_error_free (error); + } + g_free (filename); + } else { + g_print ("\n*** Connection '%s' ***\n\n%s\n", basename, data); + } + + g_key_file_free (file); +} + +#define DEFAULT_CONNECTIONS_DIR NMRUNDIR "/system-connections" +#define DEFAULT_SYSFS_DIR "/sys" + +int +main (int argc, char *argv[]) +{ + GHashTable *connections; + gs_free char *connections_dir = NULL; + gs_free char *sysfs_dir = NULL; + gboolean dump_to_stdout = FALSE; + gs_strfreev char **remaining = NULL; + GOptionEntry option_entries[] = { + { "connections-dir", 'c', 0, G_OPTION_ARG_FILENAME, &connections_dir, "Output connection directory", DEFAULT_CONNECTIONS_DIR }, + { "sysfs-dir", 'd', 0, G_OPTION_ARG_FILENAME, &sysfs_dir, "The sysfs mount point", DEFAULT_SYSFS_DIR }, + { "stdout", 's', 0, G_OPTION_ARG_NONE, &dump_to_stdout, "Dump connections to standard output", NULL }, + { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &remaining, NULL, NULL }, + { NULL } + }; + GOptionContext *option_context; + GError *error = NULL; + + option_context = g_option_context_new ("-- [ip=...] [rd.route=...] [bridge=...] [bond=...] [team=...] [vlan=...] " + "[bootdev=...] [nameserver=...] [rd.peerdns=...] [rd.bootif=...] [BOOTIF=...] ... "); + + g_option_context_set_summary (option_context, "Generate early NetworkManager configuration."); + g_option_context_set_description (option_context, + "This tool scans the command line for options relevant to network\n" + "configuration and creates configuration files for an early instance\n" + "of NetworkManager run from the initial ramdisk during early boot."); + g_option_context_add_main_entries (option_context, option_entries, GETTEXT_PACKAGE); + + if (!g_option_context_parse (option_context, &argc, &argv, &error)) { + _LOGW (LOGD_CORE, "%s\n", error->message); + return 1; + } + + if (!remaining) { + /* No arguments, no networking. Don't bother. */ + return 0; + } + + if (!connections_dir) + connections_dir = g_strdup (DEFAULT_CONNECTIONS_DIR); + if (!sysfs_dir) + sysfs_dir = g_strdup (DEFAULT_SYSFS_DIR); + if (dump_to_stdout) + g_clear_pointer (&connections_dir, g_free); + + if (connections_dir && g_mkdir_with_parents (connections_dir, 0755) != 0) { + _LOGW (LOGD_CORE, "%s: %s\n", connections_dir, strerror (errno)); + return 1; + } + + connections = nmi_cmdline_reader_parse (sysfs_dir, remaining); + g_hash_table_foreach (connections, output_conn, connections_dir); + g_hash_table_destroy (connections); + + return 0; +} diff --git a/src/initrd/nm-initrd-generator.h b/src/initrd/nm-initrd-generator.h new file mode 100644 index 00000000..1fa858fc --- /dev/null +++ b/src/initrd/nm-initrd-generator.h @@ -0,0 +1,45 @@ +/* NetworkManager initrd configuration generator + * + * 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 (C) 2014, 2018 Red Hat, Inc. + */ + +#ifndef __NM_INITRD_GENERATOR_H__ +#define __NM_INITRD_GENERATOR_H__ + +#include "nm-connection.h" +#include "nm-utils.h" + +static inline gboolean +guess_ip_address_family (const char *str) +{ + if (str == NULL) + return AF_UNSPEC; + else if (strchr (str, '.')) + return AF_INET; + else if (strchr (str, ':')) + return AF_INET6; + else + return AF_UNSPEC; +} + +GHashTable *nmi_ibft_read (const char *sysfs_dir); + +gboolean nmi_ibft_update_connection_from_nic (NMConnection *connection, GHashTable *nic, GError **error); + +GHashTable *nmi_cmdline_reader_parse (const char *sysfs_dir, char **argv); + +#endif /* __NM_INITRD_GENERATOR_H__ */ diff --git a/src/initrd/nmi-cmdline-reader.c b/src/initrd/nmi-cmdline-reader.c new file mode 100644 index 00000000..2cef534e --- /dev/null +++ b/src/initrd/nmi-cmdline-reader.c @@ -0,0 +1,714 @@ +/* NetworkManager initrd configuration generator + * + * 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 (C) 2018 Red Hat, Inc. + */ + +#include "nm-default.h" +#include "nm-core-internal.h" + +#include "nm-initrd-generator.h" + +#include <string.h> + +/*****************************************************************************/ + +#define _NMLOG(level, domain, ...) \ + nm_log ((level), (domain), NULL, NULL, \ + "cmdline-reader: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__) \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)) + +/*****************************************************************************/ + +static NMConnection * +get_conn (GHashTable *connections, const char *ifname, const char *type_name) +{ + NMConnection *connection; + NMSetting *setting; + const char *basename = ifname ?: "default_connection"; + + connection = g_hash_table_lookup (connections, (gpointer)basename); + + if (connection) { + setting = (NMSetting *)nm_connection_get_setting_connection (connection); + } else { + connection = nm_simple_connection_new (); + g_hash_table_insert (connections, g_strdup (basename), connection); + + /* Start off assuming dynamic IP configurations. */ + + setting = nm_setting_ip4_config_new (); + nm_connection_add_setting (connection, setting); + g_object_set (setting, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE, + NULL); + + setting = nm_setting_ip6_config_new (); + nm_connection_add_setting (connection, setting); + g_object_set (setting, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE, + NULL); + + setting = nm_setting_connection_new (); + nm_connection_add_setting (connection, setting); + g_object_set (setting, + NM_SETTING_CONNECTION_ID, ifname ?: "Wired Connection", + NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_a (), + NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, + NULL); + + if (!type_name) + type_name = NM_SETTING_WIRED_SETTING_NAME; + } + + if (type_name) { + g_object_set (setting, NM_SETTING_CONNECTION_TYPE, type_name, NULL); + if (!nm_connection_get_setting_by_name (connection, type_name)) { + setting = g_object_new (nm_setting_lookup_type (type_name), NULL); + nm_connection_add_setting (connection, setting); + } + } + + return connection; +} + +static char * +get_word (char **argument, const char separator) +{ + char *word; + int nest = 0; + + if (*argument == NULL) + return NULL; + + if (**argument == '[') { + nest++; + (*argument)++; + } + + word = *argument; + + while (**argument != '\0') { + if (nest && **argument == ']') { + **argument = '\0'; + (*argument)++; + nest--; + continue; + } + + if (nest == 0 && **argument == separator) { + **argument = '\0'; + (*argument)++; + break; + } + (*argument)++; + } + + return *word ? word : NULL; +} + +static void +_base_setting_set (NMConnection *connection, const char *property, const char *value) +{ + NMSetting *setting; + const char *type_name = nm_connection_get_connection_type (connection); + GObjectClass *object_class = g_type_class_ref (nm_setting_lookup_type (type_name)); + GParamSpec *spec = g_object_class_find_property (object_class, property); + + if (!spec) { + _LOGW (LOGD_CORE, "'%s' does not support setting %s\n", type_name, property); + return; + } + + setting = nm_connection_get_setting_by_name (connection, type_name); + + if (G_IS_PARAM_SPEC_UINT (spec)) + g_object_set (setting, property, g_ascii_strtoull (value, NULL, 10), NULL); + else if (G_IS_PARAM_SPEC_STRING (spec)) + g_object_set (setting, property, value, NULL); + else + _LOGW (LOGD_CORE, "Don't know how to set '%s' of %s\n", property, type_name); + + g_type_class_unref (object_class); +} + +static void +parse_ip (GHashTable *connections, const char *sysfs_dir, char *argument) +{ + NMConnection *connection; + NMSettingIPConfig *s_ip4 = NULL, *s_ip6 = NULL; + gs_unref_hashtable GHashTable *ibft = NULL; + const char *tmp; + const char *kind = NULL; + const char *client_ip = NULL; + const char *peer = NULL; + const char *gateway_ip = NULL; + const char *netmask = NULL; + const char *client_hostname = NULL; + const char *ifname = NULL; + const char *mtu = NULL; + const char *macaddr = NULL; + int client_ip_family = AF_UNSPEC; + int client_ip_prefix = -1; + const char *dns[2] = { 0, }; + int dns_addr_family[2] = { 0, }; + int i; + GError *error = NULL; + + if (!*argument) + return; + + tmp = get_word (&argument, ':'); + if (!*argument) { + /* ip={dhcp|on|any|dhcp6|auto6|ibft} */ + kind = tmp; + } else { + client_ip_family = guess_ip_address_family (tmp); + if (client_ip_family != AF_UNSPEC) { + /* <client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>: */ + client_ip = tmp; + peer = get_word (&argument, ':'); + gateway_ip = get_word (&argument, ':'); + netmask = get_word (&argument, ':'); + client_hostname = get_word (&argument, ':'); + ifname = get_word (&argument, ':'); + } else { + ifname = tmp; + } + + /* <ifname>:{none|off|dhcp|on|any|dhcp6|auto6|ibft} */ + + kind = get_word (&argument, ':'); + + tmp = get_word (&argument, ':'); + dns_addr_family[0] = guess_ip_address_family (tmp); + if (dns_addr_family[0] != AF_UNSPEC) { + dns[0] = tmp; + dns[1] = get_word (&argument, ':'); + dns_addr_family[1] = guess_ip_address_family (dns[1]); + if (argument && *argument) + _LOGW (LOGD_CORE, "Ignoring extra: '%s'.\n", argument); + } else { + mtu = tmp; + macaddr = argument; + } + } + + if (ifname == NULL && g_strcmp0 (kind, "ibft") == 0) { + GHashTableIter iter; + const char *mac; + GHashTable *nic; + const char *index; + + /* This is the ip=ibft case. Just take all we got from iBFT + * and don't process anything else, since there's no ifname + * specified to apply it to. */ + if (!ibft) + ibft = nmi_ibft_read (sysfs_dir); + + g_hash_table_iter_init (&iter, ibft); + while (g_hash_table_iter_next (&iter, (gpointer)&mac, (gpointer)&nic)) { + connection = nm_simple_connection_new (); + + index = g_hash_table_lookup (nic, "index"); + if (!index) { + _LOGW (LOGD_CORE, "Ignoring an iBFT entry without an index\n"); + continue; + } + + if (!nmi_ibft_update_connection_from_nic (connection, nic, &error)) { + _LOGW (LOGD_CORE, "Unable to merge iBFT configuration: %s\n", error->message); + g_error_free (error); + } + + g_hash_table_insert (connections, + g_strdup_printf ("ibft%s", index), + connection); + } + + return; + } + + /* Parsing done, construct the NMConnection. */ + connection = get_conn (connections, ifname, NULL); + s_ip4 = nm_connection_get_setting_ip4_config (connection); + s_ip6 = nm_connection_get_setting_ip6_config (connection); + + if (netmask && *netmask) { + NMIPAddr addr; + + if (nm_utils_parse_inaddr_bin (AF_INET, netmask, &addr)) { + client_ip_prefix = nm_utils_ip4_netmask_to_prefix (addr.addr4); + } else { + _LOGW (LOGD_CORE, "Unrecognized address: %s\n", client_ip); + } + } + + /* Static IP configuration might be present. */ + if (client_ip && *client_ip) { + NMIPAddress *address = NULL; + NMIPAddr addr; + + if (nm_utils_parse_inaddr_prefix_bin (client_ip_family, client_ip, &addr, + client_ip_prefix == -1 ? &client_ip_prefix : NULL)) { + if (client_ip_prefix == -1) { + switch (client_ip_family) { + case AF_INET: + client_ip_prefix = _nm_utils_ip4_get_default_prefix (addr.addr4); + break; + case AF_INET6: + client_ip_prefix = 64; + break; + } + } + + address = nm_ip_address_new_binary (client_ip_family, &addr.addr_ptr, client_ip_prefix, &error); + if (!address) { + _LOGW (LOGD_CORE, "Invalid address '%s': %s\n", client_ip, error->message); + g_clear_error (&error); + } + } else { + _LOGW (LOGD_CORE, "Unrecognized address: %s\n", client_ip); + } + + if (address) { + switch (client_ip_family) { + case AF_INET: + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE, + NULL); + nm_setting_ip_config_add_address (s_ip4, address); + break; + case AF_INET6: + g_object_set (s_ip6, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE, + NULL); + nm_setting_ip_config_add_address (s_ip6, address); + break; + default: + _LOGW (LOGD_CORE, "Unknown address family: %s\n", client_ip); + break; + } + nm_ip_address_unref (address); + } + } + + /* Dynamic IP configuration configured explicitly. */ + if (g_strcmp0 (kind, "none") == 0 || (g_strcmp0 (kind, "off") == 0)) { + if (nm_setting_ip_config_get_num_addresses (s_ip6) == 0) { + g_object_set (s_ip6, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NULL); + } + if (nm_setting_ip_config_get_num_addresses (s_ip4) == 0) { + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, + NULL); + } + } else if (g_strcmp0 (kind, "dhcp") == 0) { + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE, + NULL); + if (nm_setting_ip_config_get_num_addresses (s_ip6) == 0) { + g_object_set (s_ip6, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NULL); + } + } else if (g_strcmp0 (kind, "dhcp6") == 0) { + g_object_set (s_ip6, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_DHCP, + NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE, + NULL); + if (nm_setting_ip_config_get_num_addresses (s_ip4) == 0) { + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, + NULL); + } + } else if (g_strcmp0 (kind, "auto6") == 0) { + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE, + NULL); + if (nm_setting_ip_config_get_num_addresses (s_ip4) == 0) { + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, + NULL); + } + } else if (g_strcmp0 (kind, "ibft") == 0) { + gs_free char *address_path = g_build_filename (sysfs_dir, "class", "net", ifname, "address", NULL); + gs_free char *mac, *mac_up = NULL; + GHashTable *nic = NULL; + + if (!g_file_get_contents (address_path, &mac, NULL, &error)) { + _LOGW (LOGD_CORE, "Can't get a MAC address for %s: %s", ifname, error->message); + g_clear_error (&error); + } + + if (mac) { + g_strchomp (mac); + mac_up = g_ascii_strup (mac, -1); + if (!ibft) + ibft = nmi_ibft_read (sysfs_dir); + nic = g_hash_table_lookup (ibft, mac_up); + if (!nic) + _LOGW (LOGD_CORE, "No iBFT NIC for %s (%s)\n", ifname, mac_up); + } + + if (nic) { + if (!nmi_ibft_update_connection_from_nic (connection, nic, &error)) { + _LOGW (LOGD_CORE, "Unable to merge iBFT configuration: %s\n", error->message); + g_clear_error (&error); + } + } + } + + if (peer && *peer) + _LOGW (LOGD_CORE, "Ignoring peer: %s (not implemented)\b", peer); + + if (gateway_ip && *gateway_ip) { + int addr_family = guess_ip_address_family (gateway_ip); + + if (nm_utils_ipaddr_valid (addr_family, gateway_ip)) { + switch (addr_family) { + case AF_INET: + g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway_ip, NULL); + break; + case AF_INET6: + g_object_set (s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, gateway_ip, NULL); + break; + default: + _LOGW (LOGD_CORE, "Unknown address family: %s\n", gateway_ip); + break; + } + } else { + _LOGW (LOGD_CORE, "Invalid gateway: %s\n", gateway_ip); + } + } + + if (client_hostname && *client_hostname) { + g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, client_hostname, NULL); + g_object_set (s_ip6, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, client_hostname, NULL); + } + + for (i = 0; i < 2; i++) { + if (dns_addr_family[i] == AF_UNSPEC) + break; + if (nm_utils_ipaddr_valid (dns_addr_family[i], dns[i])) { + switch (dns_addr_family[i]) { + case AF_INET: + nm_setting_ip_config_add_dns (s_ip4, dns[i]); + break; + case AF_INET6: + nm_setting_ip_config_add_dns (s_ip6, dns[i]); + break; + default: + _LOGW (LOGD_CORE, "Unknown address family: %s\n", dns[i]); + break; + } + } else { + _LOGW (LOGD_CORE, "Invalid name server: %s\n", dns[i]); + } + } + + if (mtu && *mtu) + _base_setting_set (connection, "mtu", mtu); + + if (macaddr && *macaddr) + _base_setting_set (connection, "cloned-mac-address", macaddr); +} + +static void +parse_master (GHashTable *connections, char *argument, const char *type_name) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingBond *s_bond; + gs_free char *master_to_free = NULL; + const char *master; + char *slaves; + const char *slave; + char *opts; + char *opt; + const char *opt_name; + const char *mtu = NULL; + + master = get_word (&argument, ':'); + if (!master) + master = master_to_free = g_strdup_printf ("%s0", type_name); + slaves = get_word (&argument, ':'); + + connection = get_conn (connections, master, type_name); + s_con = nm_connection_get_setting_connection (connection); + master = nm_setting_connection_get_uuid (s_con); + + if (strcmp (type_name, NM_SETTING_BOND_SETTING_NAME) == 0) { + s_bond = (NMSettingBond *)nm_connection_get_setting_by_name (connection, type_name); + + opts = get_word (&argument, ':'); + while (opts && *opts) { + opt = get_word (&opts, ','); + opt_name = get_word (&opt, '='); + nm_setting_bond_add_option (s_bond, opt_name, opt); + } + + mtu = get_word (&argument, ':'); + } + + do { + slave = get_word (&slaves, ','); + if (slave == NULL) + slave = "eth0"; + + connection = get_conn (connections, slave, NULL); + s_con = nm_connection_get_setting_connection (connection); + g_object_set (s_con, + NM_SETTING_CONNECTION_SLAVE_TYPE, type_name, + NM_SETTING_CONNECTION_MASTER, master, + NULL); + if (mtu) + _base_setting_set (connection, "mtu", mtu); + } while (slaves && *slaves != '\0'); + + if (argument && *argument) + _LOGW (LOGD_CORE, "Ignoring extra: '%s'.\n", argument); +} + +static void +parse_rd_route (GHashTable *connections, char *argument) +{ + NMConnection *connection; + const char *net; + const char *gateway; + const char *interface; + int family = AF_UNSPEC; + NMIPAddr net_addr = { 0, }; + NMIPAddr gateway_addr = { 0, }; + int net_prefix = -1; + NMIPRoute *route; + NMSettingIPConfig *s_ip; + GError *error = NULL; + + net = get_word (&argument, ':'); + gateway = get_word (&argument, ':'); + interface = get_word (&argument, ':'); + + family = guess_ip_address_family (net); + connection = get_conn (connections, interface, NULL); + + if (net && *net) { + if (!nm_utils_parse_inaddr_prefix_bin (family, net, &net_addr, &net_prefix)) { + _LOGW (LOGD_CORE, "Unrecognized address: %s\n", net); + return; + } + } + + if (gateway && *net) { + if (!nm_utils_parse_inaddr_bin (family, gateway, &gateway_addr)) { + _LOGW (LOGD_CORE, "Unrecognized address: %s\n", gateway); + return; + } + } + + switch (family) { + case AF_INET: + s_ip = nm_connection_get_setting_ip4_config (connection); + if (net_prefix == -1) + net_prefix = 32; + break; + case AF_INET6: + s_ip = nm_connection_get_setting_ip6_config (connection); + if (net_prefix == -1) + net_prefix = 128; + break; + default: + _LOGW (LOGD_CORE, "Unknown address family: %s\n", net); + return; + } + + route = nm_ip_route_new_binary (family, &net_addr.addr_ptr, net_prefix, &gateway_addr.addr_ptr, -1, &error); + if (!route) { + g_warning ("Invalid route '%s via %s': %s\n", net, gateway, error->message); + g_clear_error (&error); + return; + } + + nm_setting_ip_config_add_route (s_ip, route); + nm_ip_route_unref (route); +} + +static void +parse_vlan (GHashTable *connections, char *argument) +{ + NMConnection *connection; + NMSettingVlan *s_vlan; + const char *vlan; + const char *phy; + const char *vlanid; + + vlan = get_word (&argument, ':'); + phy = get_word (&argument, ':'); + + for (vlanid = vlan + strlen (vlan); vlanid > vlan; vlanid--) { + if (!g_ascii_isdigit (*(vlanid - 1))) + break; + } + + connection = get_conn (connections, vlan, NM_SETTING_VLAN_SETTING_NAME); + + s_vlan = nm_connection_get_setting_vlan (connection); + g_object_set (s_vlan, + NM_SETTING_VLAN_PARENT, phy, + NM_SETTING_VLAN_ID, g_ascii_strtoull (vlanid, NULL, 10), + NULL); + + if (argument && *argument) + _LOGW (LOGD_CORE, "Ignoring extra: '%s'.\n", argument); +} + +static void +parse_bootdev (GHashTable *connections, char *argument) +{ + NMConnection *connection; + NMSettingConnection *s_con; + + connection = get_conn (connections, NULL, NULL); + + s_con = nm_connection_get_setting_connection (connection); + g_object_set (s_con, + NM_SETTING_CONNECTION_INTERFACE_NAME, argument, + NULL); +} + +static void +parse_nameserver (GHashTable *connections, char *argument) +{ + NMConnection *connection; + NMSettingIPConfig *s_ip = NULL; + char *dns; + + connection = get_conn (connections, NULL, NULL); + + dns = get_word (&argument, '\0'); + + switch (guess_ip_address_family (dns)) { + case AF_INET: + s_ip = nm_connection_get_setting_ip4_config (connection); + break; + case AF_INET6: + s_ip = nm_connection_get_setting_ip6_config (connection); + break; + default: + _LOGW (LOGD_CORE, "Unknown address family: %s\n", dns); + break; + } + + nm_setting_ip_config_add_dns (s_ip, dns); + + if (argument && *argument) + _LOGW (LOGD_CORE, "xIgnoring extra: '%s'.\n", argument); +} + +static void +parse_rd_peerdns (GHashTable *connections, char *argument) +{ + gboolean auto_dns = !_nm_utils_ascii_str_to_bool (argument, TRUE); + NMConnection *connection; + NMSettingIPConfig *s_ip = NULL; + + connection = get_conn (connections, NULL, NULL); + + s_ip = nm_connection_get_setting_ip4_config (connection); + g_object_set (s_ip, + NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, auto_dns, + NULL); + + + s_ip = nm_connection_get_setting_ip6_config (connection); + g_object_set (s_ip, + NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, auto_dns, + NULL); +} + +static void +_normalize_conn (gpointer key, gpointer value, gpointer user_data) +{ + NMConnection *connection = value; + + nm_connection_normalize (connection, NULL, NULL, NULL); +} + +GHashTable * +nmi_cmdline_reader_parse (const char *sysfs_dir, char **argv) +{ + GHashTable *connections; + const char *tag; + char *argument; + gboolean ignore_bootif = FALSE; + char *bootif = NULL; + int i; + + connections = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref); + + for (i = 0; argv[i]; i++) { + argument = argv[i]; + tag = get_word (&argument, '='); + if (strcmp (tag, "ip") == 0) + parse_ip (connections, sysfs_dir, argument); + else if (strcmp (tag, "rd.route") == 0) + parse_rd_route (connections, argument); + else if (strcmp (tag, "bridge") == 0) + parse_master (connections, argument, NM_SETTING_BRIDGE_SETTING_NAME); + else if (strcmp (tag, "bond") == 0) + parse_master (connections, argument, NM_SETTING_BOND_SETTING_NAME); + else if (strcmp (tag, "team") == 0) + parse_master (connections, argument, NM_SETTING_TEAM_SETTING_NAME); + else if (strcmp (tag, "vlan") == 0) + parse_vlan (connections, argument); + else if (strcmp (tag, "bootdev") == 0) + parse_bootdev (connections, argument); + else if (strcmp (tag, "nameserver") == 0) + parse_nameserver (connections, argument); + else if (strcmp (tag, "rd.peerdns") == 0) + parse_rd_peerdns (connections, argument); + else if (strcmp (tag, "rd.bootif") == 0) + ignore_bootif = !_nm_utils_ascii_str_to_bool (argument, TRUE); + else if (strcasecmp (tag, "BOOTIF") == 0) + bootif = argument; + } + + if (ignore_bootif) + bootif = NULL; + if (bootif) { + NMConnection *connection; + NMSettingWired *s_wired; + + connection = get_conn (connections, NULL, NM_SETTING_WIRED_SETTING_NAME); + + s_wired = nm_connection_get_setting_wired (connection); + g_object_set (s_wired, + NM_SETTING_WIRED_MAC_ADDRESS, bootif, + NULL); + } + + g_hash_table_foreach (connections, _normalize_conn, NULL); + + return connections; +} diff --git a/src/initrd/nmi-ibft-reader.c b/src/initrd/nmi-ibft-reader.c new file mode 100644 index 00000000..c9275467 --- /dev/null +++ b/src/initrd/nmi-ibft-reader.c @@ -0,0 +1,441 @@ +/* NetworkManager initrd configuration generator + * + * 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 2014 - 2018 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-initrd-generator.h" + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <sys/wait.h> +#include <sys/inotify.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <unistd.h> + +#include "nm-core-internal.h" +#include "platform/nm-platform.h" +#include "NetworkManagerUtils.h" + +/*****************************************************************************/ + +#define _NMLOG(level, domain, ...) \ + nm_log ((level), (domain), NULL, NULL, \ + "ibft-reader: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__) \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)) + +/*****************************************************************************/ + +static GHashTable * +load_one_nic (const char *sysfs_dir, const char *dir_name) +{ + gs_free char *nic_path = g_build_filename (sysfs_dir, dir_name, NULL); + GDir *nic_dir; + const char *entry_name; + char *content; + gs_free_error GError *error = NULL; + GHashTable *nic; + + g_return_val_if_fail (sysfs_dir != NULL, FALSE); + + nic_dir = g_dir_open (nic_path, 0, &error); + if (!nic_dir) { + _LOGW (LOGD_CORE, "Can't open %s: %s", nic_path, error->message); + return NULL; + } + + nic = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free); + while ((entry_name = g_dir_read_name (nic_dir))) { + gs_free char *entry_path = g_build_filename (nic_path, entry_name, NULL); + + if (!g_file_test (entry_path, G_FILE_TEST_IS_REGULAR)) + continue; + + if (!g_file_get_contents (entry_path, &content, NULL, &error)) { + _LOGW (LOGD_CORE, "Can't read %s: %s", entry_path, error->message); + g_clear_error (&error); + continue; + } + + g_strchomp (content); + if (!g_hash_table_insert (nic, g_strdup (entry_name), content)) + _LOGW (LOGD_CORE, "Duplicate iBFT entry: %s", entry_name); + } + + g_dir_close (nic_dir); + + return nic; +} + +GHashTable * +nmi_ibft_read (const char *sysfs_dir) +{ + gs_free char *ibft_path = NULL; + GDir *ibft_dir; + const char *dir_name; + GHashTable *ibft, *nic; + char *mac; + gs_free_error GError *error = NULL; + + g_return_val_if_fail (sysfs_dir != NULL, FALSE); + + ibft_path = g_build_filename (sysfs_dir, "firmware", "ibft", NULL); + + ibft = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, + (GDestroyNotify) g_hash_table_unref); + + if (!g_file_test (ibft_path, G_FILE_TEST_IS_DIR)) + nm_utils_modprobe (NULL, FALSE, "iscsi_ibft", NULL); + if (!g_file_test (ibft_path, G_FILE_TEST_IS_DIR)) + return ibft; + + ibft_dir = g_dir_open (ibft_path, 0, &error); + if (!ibft_dir) { + _LOGW (LOGD_CORE, "Unable to open iBFT firmware directory: %s", error->message); + return ibft; + } + + while ((dir_name = g_dir_read_name (ibft_dir))) { + if (!g_str_has_prefix (dir_name, "ethernet")) + continue; + + nic = load_one_nic (ibft_path, dir_name); + mac = g_hash_table_lookup (nic, "mac"); + + if (!mac) { + _LOGW (LOGD_CORE, "Ignoring an iBFT record without a MAC address"); + g_hash_table_unref (nic); + continue; + } + + mac = g_ascii_strup (mac, -1); + if (!g_hash_table_insert (ibft, mac, nic)) + _LOGW (LOGD_CORE, "Duplicate iBFT record for %s", mac); + } + + g_dir_close (ibft_dir); + + return ibft; +} + +static gboolean +ip_setting_add_from_block (GHashTable *nic, + NMConnection *connection, + GError **error) +{ + NMSettingIPConfig *s_ip = NULL; + NMSettingIPConfig *s_ip4 = NULL; + NMSettingIPConfig *s_ip6 = NULL; + NMIPAddress *addr; + const char *s_ipaddr = NULL; + const char *s_prefix = NULL; + const char *s_gateway = NULL; + const char *s_dns1 = NULL; + const char *s_dns2 = NULL; + const char *s_origin = NULL; + const char *method = NULL; + int family; + gint64 prefix; + + s_ipaddr = (const char *)g_hash_table_lookup (nic, "ip-addr"); + s_prefix = (const char *)g_hash_table_lookup (nic, "prefix-len"); + s_gateway = (const char *)g_hash_table_lookup (nic, "gateway"); + s_dns1 = (const char *)g_hash_table_lookup (nic, "primary-dns"); + s_dns2 = (const char *)g_hash_table_lookup (nic, "secondary-dns"); + s_origin = (const char *)g_hash_table_lookup (nic, "origin"); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + if (!s_ip4) { + s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new (); + nm_connection_add_setting (connection, (NMSetting *) s_ip4); + } + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + if (!s_ip6) { + s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new (); + nm_connection_add_setting (connection, (NMSetting *) s_ip6); + } + + family = guess_ip_address_family (s_ipaddr); + if (family == AF_UNSPEC) + family = guess_ip_address_family (s_gateway); + + switch (family) { + case AF_INET: + s_ip = s_ip4; + g_object_set (s_ip6, NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); + break; + case AF_INET6: + s_ip = s_ip6; + g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP4_CONFIG_METHOD_DISABLED, NULL); + break; + default: + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "iBFT: invalid IP address '%s'.", + s_ipaddr); + return FALSE; + } + + if ( (g_strcmp0 (s_origin, "3") == 0 && family == AF_INET) + || (g_strcmp0 (s_origin, "4") == 0 && family == AF_INET)) { + method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; + } else if (g_strcmp0 (s_origin, "3") == 0 && family == AF_INET6) { + method = NM_SETTING_IP6_CONFIG_METHOD_DHCP; + } else if (g_strcmp0 (s_origin, "4") == 0 && family == AF_INET6) { + method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; + } else if (family == AF_INET) { + method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL; + } else if (family == AF_INET6) { + method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; + } else { + g_return_val_if_reached (FALSE); + } + g_object_set (s_ip, + NM_SETTING_IP_CONFIG_METHOD, method, + NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE, + NULL); + + if (s_gateway && !nm_utils_ipaddr_valid (family, s_gateway)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "iBFT: invalid IP gateway '%s'.", s_gateway); + return FALSE; + } + + if (s_dns1 && !nm_utils_ipaddr_valid (family, s_dns1)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "iBFT: invalid DNS1 address '%s'.", s_dns1); + return FALSE; + } + + if (s_dns2 && !nm_utils_ipaddr_valid (family, s_dns2)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "iBFT: invalid DNS2 address '%s'.", s_dns2); + return FALSE; + } + + if (s_ipaddr) { + prefix = _nm_utils_ascii_str_to_int64 (s_prefix, 10, 0, 128, -1); + if (prefix == -1) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "iBFT: invalid IP prefix '%s'.", s_prefix); + return FALSE; + } + + addr = nm_ip_address_new (family, s_ipaddr, prefix, error); + if (!addr) { + g_prefix_error (error, "iBFT: "); + return FALSE; + } + + nm_setting_ip_config_add_address (s_ip, addr); + nm_ip_address_unref (addr); + + g_object_set (s_ip, NM_SETTING_IP_CONFIG_GATEWAY, s_gateway, NULL); + } + + if (s_dns1) + nm_setting_ip_config_add_dns (s_ip, s_dns1); + if (s_dns2) + nm_setting_ip_config_add_dns (s_ip, s_dns2); + + return TRUE; +} + +static gboolean +connection_setting_add (GHashTable *nic, + NMConnection *connection, + const char *type, + const char *prefix, + GError **error) +{ + NMSetting *s_con; + char *id, *uuid; + const char *s_index, *s_hwaddr, *s_ipaddr, *s_vlanid; + + s_index = (const char *)g_hash_table_lookup (nic, "index"); + s_hwaddr = (const char *)g_hash_table_lookup (nic, "mac"); + s_ipaddr = (const char *)g_hash_table_lookup (nic, "ip-addr"); + s_vlanid = (const char *)g_hash_table_lookup (nic, "vlan"); + + if (!s_hwaddr) { + g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "iBFT: missing MAC address"); + return FALSE; + } + + id = g_strdup_printf ("iBFT%s%s Connection%s%s", + prefix ? " " : "", + prefix ? prefix : "", + s_index ? " " : "", + s_index ? s_index : ""); + + uuid = _nm_utils_uuid_generate_from_strings ("ibft", + s_hwaddr, + s_vlanid ? "V" : "v", + s_vlanid ? s_vlanid : "", + s_ipaddr ? "A" : "DHCP", + s_ipaddr ? s_ipaddr : "", + NULL); + + s_con = (NMSetting *) nm_connection_get_setting_connection (connection); + if (!s_con) { + s_con = nm_setting_connection_new (); + nm_connection_add_setting (connection, s_con); + } + + g_object_set (s_con, + NM_SETTING_CONNECTION_TYPE, type, + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_ID, id, + NULL); + + g_free (uuid); + g_free (id); + + return TRUE; +} + +static gboolean +is_ibft_vlan_device (GHashTable *nic) +{ + const char *s_vlan_id; + + g_assert (nic); + + s_vlan_id = (const char *)g_hash_table_lookup (nic, "vlan"); + + if (s_vlan_id) { + /* VLAN 0 is normally a valid VLAN ID, but in the iBFT case it + * means "no VLAN". + */ + if (_nm_utils_ascii_str_to_int64 (s_vlan_id, 10, 1, 4095, -1) != -1) + return TRUE; + } + + return FALSE; +} + +static gboolean +vlan_setting_add_from_block (GHashTable *nic, + NMConnection *connection, + GError **error) +{ + NMSetting *s_vlan = NULL; + const char *vlan_id_str = NULL; + gint64 vlan_id = -1; + + g_assert (nic); + g_assert (connection); + + /* This won't fail since this function shouldn't be called unless the + * iBFT VLAN ID exists and is > 0. + */ + vlan_id_str = (const char *)g_hash_table_lookup (nic, "vlan"); + g_assert (vlan_id_str); + + /* VLAN 0 is normally a valid VLAN ID, but in the iBFT case it means "no VLAN" */ + vlan_id = _nm_utils_ascii_str_to_int64 (vlan_id_str, 10, 1, 4095, -1); + if (vlan_id == -1) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid VLAN_ID '%s'", vlan_id_str); + return FALSE; + } + + s_vlan = (NMSetting *) nm_connection_get_setting_vlan (connection); + if (!s_vlan) { + s_vlan = nm_setting_vlan_new (); + nm_connection_add_setting (connection, s_vlan); + } + + g_object_set (s_vlan, NM_SETTING_VLAN_ID, (guint32) vlan_id, NULL); + + return TRUE; +} + +static gboolean +wired_setting_add_from_block (GHashTable *nic, + NMConnection *connection, + GError **error) +{ + NMSetting *s_wired = NULL; + const char *hwaddr = NULL; + + g_assert (nic); + g_assert (connection); + + + hwaddr = (const char *)g_hash_table_lookup (nic, "mac"); + if (!hwaddr) { + g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "iBFT: missing MAC address"); + return FALSE; + } + + if (!nm_utils_hwaddr_valid (hwaddr, ETH_ALEN)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "iBFT: invalid MAC address '%s'.", hwaddr); + return FALSE; + } + + s_wired = (NMSetting *) nm_connection_get_setting_wired (connection); + if (!s_wired) { + s_wired = nm_setting_wired_new (); + nm_connection_add_setting (connection, s_wired); + } + + g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, hwaddr, NULL); + + return TRUE; +} + +gboolean +nmi_ibft_update_connection_from_nic (NMConnection *connection, GHashTable *nic, GError **error) +{ + gboolean is_vlan = FALSE; + + g_assert (nic); + + is_vlan = is_ibft_vlan_device (nic); + if (is_vlan && !vlan_setting_add_from_block (nic, connection, error)) + return FALSE; + + /* Always have a wired setting; for VLAN it defines the parent */ + if (!wired_setting_add_from_block (nic, connection, error)) + return FALSE; + + if (!ip_setting_add_from_block (nic, connection, error)) + return FALSE; + + if (!connection_setting_add (nic, + connection, + is_vlan ? NM_SETTING_VLAN_SETTING_NAME : NM_SETTING_WIRED_SETTING_NAME, + is_vlan ? "VLAN" : NULL, + error)) + return FALSE; + + if (!nm_connection_normalize (connection, NULL, NULL, error)) + return FALSE; + + return TRUE; +} diff --git a/src/initrd/tests/sysfs-bad-dns1/class/net/eth0/address b/src/initrd/tests/sysfs-bad-dns1/class/net/eth0/address new file mode 100644 index 00000000..20659db7 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/class/net/eth0/address @@ -0,0 +1 @@ +00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/gateway b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/gateway new file mode 100644 index 00000000..bf6cf454 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/gateway @@ -0,0 +1 @@ +192.168.35.254 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/index b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/index new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/index @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/ip-addr b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/ip-addr new file mode 100644 index 00000000..944c8d45 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/ip-addr @@ -0,0 +1 @@ +192.168.32.72 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/mac b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/mac new file mode 100644 index 00000000..20659db7 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/mac @@ -0,0 +1 @@ +00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/origin b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/origin new file mode 100644 index 00000000..56a6051c --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/origin @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/prefix-len b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/prefix-len new file mode 100644 index 00000000..8fdd954d --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/prefix-len @@ -0,0 +1 @@ +22 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/primary-dns b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/primary-dns new file mode 100644 index 00000000..2303dbdc --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/primary-dns @@ -0,0 +1 @@ +10000.500.250.1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/secondary-dns b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/secondary-dns new file mode 100644 index 00000000..2eb9e1d0 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/secondary-dns @@ -0,0 +1 @@ +10.16.255.3 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/subnet-mask b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/subnet-mask new file mode 100644 index 00000000..7cb9d0a9 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/subnet-mask @@ -0,0 +1 @@ +255.255.252.0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/vlan b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/vlan new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/vlan @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/initiator/initiator-name b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/initiator/initiator-name new file mode 100644 index 00000000..509a7ab8 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/initiator/initiator-name @@ -0,0 +1 @@ +iqn.pjones6 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/index b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/index new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/index @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/ip-addr b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/ip-addr new file mode 100644 index 00000000..7450fdf9 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/ip-addr @@ -0,0 +1 @@ +10.16.52.16 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/lun b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/lun new file mode 100644 index 00000000..c43d0930 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/lun @@ -0,0 +1 @@ +00000000 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/port b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/port new file mode 100644 index 00000000..58f0d919 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/port @@ -0,0 +1 @@ +3260 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/target-name b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/target-name new file mode 100644 index 00000000..32c9450a --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/target-name @@ -0,0 +1 @@ +iqn.0.2008-11.com.blahblah:iscsi0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/class/net/eth0/address b/src/initrd/tests/sysfs-bad-dns2/class/net/eth0/address new file mode 100644 index 00000000..20659db7 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/class/net/eth0/address @@ -0,0 +1 @@ +00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/gateway b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/gateway new file mode 100644 index 00000000..bf6cf454 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/gateway @@ -0,0 +1 @@ +192.168.35.254 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/index b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/index new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/index @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/ip-addr b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/ip-addr new file mode 100644 index 00000000..944c8d45 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/ip-addr @@ -0,0 +1 @@ +192.168.32.72 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/mac b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/mac new file mode 100644 index 00000000..20659db7 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/mac @@ -0,0 +1 @@ +00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/origin b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/origin new file mode 100644 index 00000000..56a6051c --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/origin @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/prefix-len b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/prefix-len new file mode 100644 index 00000000..8fdd954d --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/prefix-len @@ -0,0 +1 @@ +22 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/primary-dns b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/primary-dns new file mode 100644 index 00000000..2e152cb0 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/primary-dns @@ -0,0 +1 @@ +10.16.255.2 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/secondary-dns b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/secondary-dns new file mode 100644 index 00000000..5ed7b719 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/secondary-dns @@ -0,0 +1 @@ +blah.foo.bar.baz \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/subnet-mask b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/subnet-mask new file mode 100644 index 00000000..7cb9d0a9 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/subnet-mask @@ -0,0 +1 @@ +255.255.252.0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/vlan b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/vlan new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/vlan @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/initiator/initiator-name b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/initiator/initiator-name new file mode 100644 index 00000000..509a7ab8 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/initiator/initiator-name @@ -0,0 +1 @@ +iqn.pjones6 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/index b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/index new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/index @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/ip-addr b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/ip-addr new file mode 100644 index 00000000..7450fdf9 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/ip-addr @@ -0,0 +1 @@ +10.16.52.16 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/lun b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/lun new file mode 100644 index 00000000..c43d0930 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/lun @@ -0,0 +1 @@ +00000000 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/port b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/port new file mode 100644 index 00000000..58f0d919 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/port @@ -0,0 +1 @@ +3260 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/target-name b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/target-name new file mode 100644 index 00000000..32c9450a --- /dev/null +++ b/src/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/target-name @@ -0,0 +1 @@ +iqn.0.2008-11.com.blahblah:iscsi0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/class/net/eth0/address b/src/initrd/tests/sysfs-bad-gateway/class/net/eth0/address new file mode 100644 index 00000000..20659db7 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/class/net/eth0/address @@ -0,0 +1 @@ +00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/gateway b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/gateway new file mode 100644 index 00000000..1970856e --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/gateway @@ -0,0 +1 @@ +bb.cc.dd.ee \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/index b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/index new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/index @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/ip-addr b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/ip-addr new file mode 100644 index 00000000..944c8d45 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/ip-addr @@ -0,0 +1 @@ +192.168.32.72 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/mac b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/mac new file mode 100644 index 00000000..20659db7 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/mac @@ -0,0 +1 @@ +00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/origin b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/origin new file mode 100644 index 00000000..56a6051c --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/origin @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/prefix-len b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/prefix-len new file mode 100644 index 00000000..8fdd954d --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/prefix-len @@ -0,0 +1 @@ +22 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/primary-dns b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/primary-dns new file mode 100644 index 00000000..2e152cb0 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/primary-dns @@ -0,0 +1 @@ +10.16.255.2 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/secondary-dns b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/secondary-dns new file mode 100644 index 00000000..2eb9e1d0 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/secondary-dns @@ -0,0 +1 @@ +10.16.255.3 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/subnet-mask b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/subnet-mask new file mode 100644 index 00000000..7cb9d0a9 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/subnet-mask @@ -0,0 +1 @@ +255.255.252.0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/vlan b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/vlan new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/vlan @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/initiator/initiator-name b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/initiator/initiator-name new file mode 100644 index 00000000..509a7ab8 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/initiator/initiator-name @@ -0,0 +1 @@ +iqn.pjones6 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/index b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/index new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/index @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/ip-addr b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/ip-addr new file mode 100644 index 00000000..7450fdf9 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/ip-addr @@ -0,0 +1 @@ +10.16.52.16 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/lun b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/lun new file mode 100644 index 00000000..c43d0930 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/lun @@ -0,0 +1 @@ +00000000 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/port b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/port new file mode 100644 index 00000000..58f0d919 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/port @@ -0,0 +1 @@ +3260 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/target-name b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/target-name new file mode 100644 index 00000000..32c9450a --- /dev/null +++ b/src/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/target-name @@ -0,0 +1 @@ +iqn.0.2008-11.com.blahblah:iscsi0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/class/net/eth0/address b/src/initrd/tests/sysfs-bad-ipaddr/class/net/eth0/address new file mode 100644 index 00000000..20659db7 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/class/net/eth0/address @@ -0,0 +1 @@ +00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/gateway b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/gateway new file mode 100644 index 00000000..bf6cf454 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/gateway @@ -0,0 +1 @@ +192.168.35.254 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/index b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/index new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/index @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/ip-addr b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/ip-addr new file mode 100644 index 00000000..d526f324 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/ip-addr @@ -0,0 +1 @@ +aa.bb.cc.dd \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/mac b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/mac new file mode 100644 index 00000000..20659db7 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/mac @@ -0,0 +1 @@ +00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/origin b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/origin new file mode 100644 index 00000000..56a6051c --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/origin @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/prefix-len b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/prefix-len new file mode 100644 index 00000000..8fdd954d --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/prefix-len @@ -0,0 +1 @@ +22 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/primary-dns b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/primary-dns new file mode 100644 index 00000000..2e152cb0 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/primary-dns @@ -0,0 +1 @@ +10.16.255.2 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/secondary-dns b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/secondary-dns new file mode 100644 index 00000000..2eb9e1d0 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/secondary-dns @@ -0,0 +1 @@ +10.16.255.3 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/subnet-mask b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/subnet-mask new file mode 100644 index 00000000..7cb9d0a9 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/subnet-mask @@ -0,0 +1 @@ +255.255.252.0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/vlan b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/vlan new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/vlan @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/initiator/initiator-name b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/initiator/initiator-name new file mode 100644 index 00000000..509a7ab8 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/initiator/initiator-name @@ -0,0 +1 @@ +iqn.pjones6 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/index b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/index new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/index @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/ip-addr b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/ip-addr new file mode 100644 index 00000000..7450fdf9 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/ip-addr @@ -0,0 +1 @@ +10.16.52.16 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/lun b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/lun new file mode 100644 index 00000000..c43d0930 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/lun @@ -0,0 +1 @@ +00000000 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/port b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/port new file mode 100644 index 00000000..58f0d919 --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/port @@ -0,0 +1 @@ +3260 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/target-name b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/target-name new file mode 100644 index 00000000..32c9450a --- /dev/null +++ b/src/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/target-name @@ -0,0 +1 @@ +iqn.0.2008-11.com.blahblah:iscsi0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/class/net/eth0/address b/src/initrd/tests/sysfs-dhcp/class/net/eth0/address new file mode 100644 index 00000000..20659db7 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/class/net/eth0/address @@ -0,0 +1 @@ +00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/class/net/eth1/address b/src/initrd/tests/sysfs-dhcp/class/net/eth1/address new file mode 100644 index 00000000..befa7850 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/class/net/eth1/address @@ -0,0 +1 @@ +00:33:21:98:b9:f1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/gateway b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/gateway new file mode 100644 index 00000000..59ea5b82 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/gateway @@ -0,0 +1 @@ +10.16.52.254 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/index b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/index new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/index @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/mac b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/mac new file mode 100644 index 00000000..20659db7 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/mac @@ -0,0 +1 @@ +00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/origin b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/origin new file mode 100644 index 00000000..e440e5c8 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/origin @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/primary-dns b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/primary-dns new file mode 100644 index 00000000..2e152cb0 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/primary-dns @@ -0,0 +1 @@ +10.16.255.2 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/secondary-dns b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/secondary-dns new file mode 100644 index 00000000..2eb9e1d0 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/secondary-dns @@ -0,0 +1 @@ +10.16.255.3 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/vlan b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/vlan new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/vlan @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/gateway b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/gateway new file mode 100644 index 00000000..59ea5b82 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/gateway @@ -0,0 +1 @@ +10.16.52.254 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/index b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/index new file mode 100644 index 00000000..56a6051c --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/index @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/mac b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/mac new file mode 100644 index 00000000..befa7850 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/mac @@ -0,0 +1 @@ +00:33:21:98:b9:f1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/origin b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/origin new file mode 100644 index 00000000..e440e5c8 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/origin @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/primary-dns b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/primary-dns new file mode 100644 index 00000000..2e152cb0 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/primary-dns @@ -0,0 +1 @@ +10.16.255.2 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/secondary-dns b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/secondary-dns new file mode 100644 index 00000000..2eb9e1d0 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/secondary-dns @@ -0,0 +1 @@ +10.16.255.3 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/vlan b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/vlan new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/vlan @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/initiator/initiator-name b/src/initrd/tests/sysfs-dhcp/firmware/ibft/initiator/initiator-name new file mode 100644 index 00000000..509a7ab8 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/initiator/initiator-name @@ -0,0 +1 @@ +iqn.pjones6 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/index b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/index new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/index @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/ip-addr b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/ip-addr new file mode 100644 index 00000000..7450fdf9 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/ip-addr @@ -0,0 +1 @@ +10.16.52.16 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/lun b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/lun new file mode 100644 index 00000000..c43d0930 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/lun @@ -0,0 +1 @@ +00000000 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/port b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/port new file mode 100644 index 00000000..58f0d919 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/port @@ -0,0 +1 @@ +3260 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/target-name b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/target-name new file mode 100644 index 00000000..32c9450a --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target0/target-name @@ -0,0 +1 @@ +iqn.0.2008-11.com.blahblah:iscsi0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/index b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/index new file mode 100644 index 00000000..56a6051c --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/index @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/ip-addr b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/ip-addr new file mode 100644 index 00000000..7450fdf9 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/ip-addr @@ -0,0 +1 @@ +10.16.52.16 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/lun b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/lun new file mode 100644 index 00000000..c43d0930 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/lun @@ -0,0 +1 @@ +00000000 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/port b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/port new file mode 100644 index 00000000..58f0d919 --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/port @@ -0,0 +1 @@ +3260 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/target-name b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/target-name new file mode 100644 index 00000000..ac3a6a2a --- /dev/null +++ b/src/initrd/tests/sysfs-dhcp/firmware/ibft/target1/target-name @@ -0,0 +1 @@ +iqn.1.2008-11.com.blahblah:iscsi1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/class/net/eth0/address b/src/initrd/tests/sysfs-static/class/net/eth0/address new file mode 100644 index 00000000..20659db7 --- /dev/null +++ b/src/initrd/tests/sysfs-static/class/net/eth0/address @@ -0,0 +1 @@ +00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/class/net/eth1/address b/src/initrd/tests/sysfs-static/class/net/eth1/address new file mode 100644 index 00000000..befa7850 --- /dev/null +++ b/src/initrd/tests/sysfs-static/class/net/eth1/address @@ -0,0 +1 @@ +00:33:21:98:b9:f1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/gateway b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/gateway new file mode 100644 index 00000000..bf6cf454 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/gateway @@ -0,0 +1 @@ +192.168.35.254 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/index b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/index new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/index @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/ip-addr b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/ip-addr new file mode 100644 index 00000000..944c8d45 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/ip-addr @@ -0,0 +1 @@ +192.168.32.72 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/mac b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/mac new file mode 100644 index 00000000..20659db7 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/mac @@ -0,0 +1 @@ +00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/origin b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/origin new file mode 100644 index 00000000..56a6051c --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/origin @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/prefix-len b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/prefix-len new file mode 100644 index 00000000..8fdd954d --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/prefix-len @@ -0,0 +1 @@ +22 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/primary-dns b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/primary-dns new file mode 100644 index 00000000..2e152cb0 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/primary-dns @@ -0,0 +1 @@ +10.16.255.2 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/secondary-dns b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/secondary-dns new file mode 100644 index 00000000..2eb9e1d0 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/secondary-dns @@ -0,0 +1 @@ +10.16.255.3 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/subnet-mask b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/subnet-mask new file mode 100644 index 00000000..7cb9d0a9 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/subnet-mask @@ -0,0 +1 @@ +255.255.252.0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/vlan b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/vlan new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet0/vlan @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/gateway b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/gateway new file mode 100644 index 00000000..59ea5b82 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/gateway @@ -0,0 +1 @@ +10.16.52.254 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/index b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/index new file mode 100644 index 00000000..56a6051c --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/index @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/mac b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/mac new file mode 100644 index 00000000..befa7850 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/mac @@ -0,0 +1 @@ +00:33:21:98:b9:f1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/origin b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/origin new file mode 100644 index 00000000..e440e5c8 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/origin @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/primary-dns b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/primary-dns new file mode 100644 index 00000000..2e152cb0 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/primary-dns @@ -0,0 +1 @@ +10.16.255.2 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/secondary-dns b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/secondary-dns new file mode 100644 index 00000000..2eb9e1d0 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/secondary-dns @@ -0,0 +1 @@ +10.16.255.3 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/vlan b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/vlan new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/ethernet1/vlan @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/initiator/initiator-name b/src/initrd/tests/sysfs-static/firmware/ibft/initiator/initiator-name new file mode 100644 index 00000000..509a7ab8 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/initiator/initiator-name @@ -0,0 +1 @@ +iqn.pjones6 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/target0/index b/src/initrd/tests/sysfs-static/firmware/ibft/target0/index new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/target0/index @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/target0/ip-addr b/src/initrd/tests/sysfs-static/firmware/ibft/target0/ip-addr new file mode 100644 index 00000000..7450fdf9 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/target0/ip-addr @@ -0,0 +1 @@ +10.16.52.16 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/target0/lun b/src/initrd/tests/sysfs-static/firmware/ibft/target0/lun new file mode 100644 index 00000000..c43d0930 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/target0/lun @@ -0,0 +1 @@ +00000000 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/target0/port b/src/initrd/tests/sysfs-static/firmware/ibft/target0/port new file mode 100644 index 00000000..58f0d919 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/target0/port @@ -0,0 +1 @@ +3260 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/target0/target-name b/src/initrd/tests/sysfs-static/firmware/ibft/target0/target-name new file mode 100644 index 00000000..32c9450a --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/target0/target-name @@ -0,0 +1 @@ +iqn.0.2008-11.com.blahblah:iscsi0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/target1/index b/src/initrd/tests/sysfs-static/firmware/ibft/target1/index new file mode 100644 index 00000000..56a6051c --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/target1/index @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/target1/ip-addr b/src/initrd/tests/sysfs-static/firmware/ibft/target1/ip-addr new file mode 100644 index 00000000..7450fdf9 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/target1/ip-addr @@ -0,0 +1 @@ +10.16.52.16 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/target1/lun b/src/initrd/tests/sysfs-static/firmware/ibft/target1/lun new file mode 100644 index 00000000..c43d0930 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/target1/lun @@ -0,0 +1 @@ +00000000 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/target1/port b/src/initrd/tests/sysfs-static/firmware/ibft/target1/port new file mode 100644 index 00000000..58f0d919 --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/target1/port @@ -0,0 +1 @@ +3260 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-static/firmware/ibft/target1/target-name b/src/initrd/tests/sysfs-static/firmware/ibft/target1/target-name new file mode 100644 index 00000000..ac3a6a2a --- /dev/null +++ b/src/initrd/tests/sysfs-static/firmware/ibft/target1/target-name @@ -0,0 +1 @@ +iqn.1.2008-11.com.blahblah:iscsi1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-vlan/class/net/eth0/address b/src/initrd/tests/sysfs-vlan/class/net/eth0/address new file mode 100644 index 00000000..20659db7 --- /dev/null +++ b/src/initrd/tests/sysfs-vlan/class/net/eth0/address @@ -0,0 +1 @@ +00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/index b/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/index new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/index @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/ip-addr b/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/ip-addr new file mode 100644 index 00000000..4923230c --- /dev/null +++ b/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/ip-addr @@ -0,0 +1 @@ +192.168.6.200 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/mac b/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/mac new file mode 100644 index 00000000..20659db7 --- /dev/null +++ b/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/mac @@ -0,0 +1 @@ +00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/origin b/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/origin new file mode 100644 index 00000000..56a6051c --- /dev/null +++ b/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/origin @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/prefix-len b/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/prefix-len new file mode 100644 index 00000000..cabf43b5 --- /dev/null +++ b/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/prefix-len @@ -0,0 +1 @@ +24 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/subnet-mask b/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/subnet-mask new file mode 100644 index 00000000..5a279b41 --- /dev/null +++ b/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/subnet-mask @@ -0,0 +1 @@ +255.255.255.0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/vlan b/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/vlan new file mode 100644 index 00000000..d800886d --- /dev/null +++ b/src/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/vlan @@ -0,0 +1 @@ +123 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-vlan/firmware/ibft/initiator/initiator-name b/src/initrd/tests/sysfs-vlan/firmware/ibft/initiator/initiator-name new file mode 100644 index 00000000..8e9cd2c4 --- /dev/null +++ b/src/initrd/tests/sysfs-vlan/firmware/ibft/initiator/initiator-name @@ -0,0 +1 @@ +iqn.2010-04.org.ipxe:d05faa97-c4be-44f6-a723-efde9aa399a0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/index b/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/index new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/index @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/ip-addr b/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/ip-addr new file mode 100644 index 00000000..a32ce01b --- /dev/null +++ b/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/ip-addr @@ -0,0 +1 @@ +192.168.6.32 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/lun b/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/lun new file mode 100644 index 00000000..f309ca6a --- /dev/null +++ b/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/lun @@ -0,0 +1 @@ +01000000 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/port b/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/port new file mode 100644 index 00000000..58f0d919 --- /dev/null +++ b/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/port @@ -0,0 +1 @@ +3260 \ No newline at end of file diff --git a/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/target-name b/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/target-name new file mode 100644 index 00000000..f0e61157 --- /dev/null +++ b/src/initrd/tests/sysfs-vlan/firmware/ibft/target0/target-name @@ -0,0 +1 @@ +iqn.2003-01.org.x:disk1 \ No newline at end of file diff --git a/src/initrd/tests/sysfs/class/net/eth0/address b/src/initrd/tests/sysfs/class/net/eth0/address new file mode 100644 index 00000000..1f2f610e --- /dev/null +++ b/src/initrd/tests/sysfs/class/net/eth0/address @@ -0,0 +1 @@ +00:53:00:AB:00:01 diff --git a/src/initrd/tests/sysfs/class/net/eth2/address b/src/initrd/tests/sysfs/class/net/eth2/address new file mode 100644 index 00000000..6ec1078a --- /dev/null +++ b/src/initrd/tests/sysfs/class/net/eth2/address @@ -0,0 +1 @@ +00:53:06:66:ab:01 diff --git a/src/initrd/tests/sysfs/firmware/ibft/acpi_header/oem_id b/src/initrd/tests/sysfs/firmware/ibft/acpi_header/oem_id new file mode 100644 index 00000000..590d9cd2 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/acpi_header/oem_id @@ -0,0 +1 @@ +NMTst diff --git a/src/initrd/tests/sysfs/firmware/ibft/acpi_header/oem_table_id b/src/initrd/tests/sysfs/firmware/ibft/acpi_header/oem_table_id new file mode 100644 index 00000000..35d4d09c --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/acpi_header/oem_table_id @@ -0,0 +1 @@ +Whatevs diff --git a/src/initrd/tests/sysfs/firmware/ibft/acpi_header/signature b/src/initrd/tests/sysfs/firmware/ibft/acpi_header/signature new file mode 100644 index 00000000..e3a5d7ef --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/acpi_header/signature @@ -0,0 +1 @@ +IBFT diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet0/dhcp b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/dhcp new file mode 100644 index 00000000..98a0d797 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/dhcp @@ -0,0 +1 @@ +2001:0db8:0000:0000:0000:0000:0000:0002 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet0/flags b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/flags new file mode 100644 index 00000000..00750edc --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/flags @@ -0,0 +1 @@ +3 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet0/gateway b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/gateway new file mode 100644 index 00000000..7f378f8f --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/gateway @@ -0,0 +1 @@ +2001:0db8:0000:0000:0000:0000:0000:0001 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet0/hostname b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/hostname new file mode 100644 index 00000000..3ed5163c --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/hostname @@ -0,0 +1 @@ +host0.example.com diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet0/index b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/index new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/index @@ -0,0 +1 @@ +0 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet0/ip-addr b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/ip-addr new file mode 100644 index 00000000..98a0d797 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/ip-addr @@ -0,0 +1 @@ +2001:0db8:0000:0000:0000:0000:0000:0002 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet0/mac b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/mac new file mode 100644 index 00000000..f2441319 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/mac @@ -0,0 +1 @@ +00:53:00:ab:00:01 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet0/origin b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/origin new file mode 100644 index 00000000..b8626c4c --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/origin @@ -0,0 +1 @@ +4 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet0/prefix-len b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/prefix-len new file mode 100644 index 00000000..900731ff --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/prefix-len @@ -0,0 +1 @@ +64 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet0/primary-dns b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/primary-dns new file mode 100644 index 00000000..e7511d5a --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/primary-dns @@ -0,0 +1 @@ +2001:0db8:0000:0000:0000:0000:0000:0053 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet0/secondary-dns b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/secondary-dns new file mode 100644 index 00000000..1f6c5c95 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/secondary-dns @@ -0,0 +1 @@ +2001:0db8:0000:0000:0000:0000:0000:5353 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet0/subnet-mask b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/subnet-mask new file mode 100644 index 00000000..5df93454 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/subnet-mask @@ -0,0 +1 @@ +255.255.255.255 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet0/vlan b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/vlan new file mode 100644 index 00000000..7cc86ad1 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet0/vlan @@ -0,0 +1 @@ +666 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet2/dhcp b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/dhcp new file mode 100644 index 00000000..61ef5585 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/dhcp @@ -0,0 +1 @@ +192.0.2.2 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet2/flags b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/flags new file mode 100644 index 00000000..00750edc --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/flags @@ -0,0 +1 @@ +3 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet2/gateway b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/gateway new file mode 100644 index 00000000..2096f194 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/gateway @@ -0,0 +1 @@ +192.0.2.1 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet2/hostname b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/hostname new file mode 100644 index 00000000..5dc539d5 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/hostname @@ -0,0 +1 @@ +host2.example.com diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet2/index b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/index new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/index @@ -0,0 +1 @@ +2 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet2/ip-addr b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/ip-addr new file mode 100644 index 00000000..61ef5585 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/ip-addr @@ -0,0 +1 @@ +192.0.2.2 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet2/mac b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/mac new file mode 100644 index 00000000..2fc3d525 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/mac @@ -0,0 +1 @@ +00:53:06:66:AB:01 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet2/origin b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/origin new file mode 100644 index 00000000..00750edc --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/origin @@ -0,0 +1 @@ +3 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet2/prefix-len b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/prefix-len new file mode 100644 index 00000000..a45fd52c --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/prefix-len @@ -0,0 +1 @@ +24 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet2/primary-dns b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/primary-dns new file mode 100644 index 00000000..6fa8c742 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/primary-dns @@ -0,0 +1 @@ +192.0.2.53 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet2/secondary-dns b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/secondary-dns new file mode 100644 index 00000000..a7269ff5 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/secondary-dns @@ -0,0 +1 @@ +192.0.2.54 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet2/subnet-mask b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/subnet-mask new file mode 100644 index 00000000..d30f9e9f --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/subnet-mask @@ -0,0 +1 @@ +255.255.255.0 diff --git a/src/initrd/tests/sysfs/firmware/ibft/ethernet2/vlan b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/vlan new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/ethernet2/vlan @@ -0,0 +1 @@ +0 diff --git a/src/initrd/tests/sysfs/firmware/ibft/initiator/flags b/src/initrd/tests/sysfs/firmware/ibft/initiator/flags new file mode 100644 index 00000000..00750edc --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/initiator/flags @@ -0,0 +1 @@ +3 diff --git a/src/initrd/tests/sysfs/firmware/ibft/initiator/index b/src/initrd/tests/sysfs/firmware/ibft/initiator/index new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/initiator/index @@ -0,0 +1 @@ +0 diff --git a/src/initrd/tests/sysfs/firmware/ibft/initiator/initiator-name b/src/initrd/tests/sysfs/firmware/ibft/initiator/initiator-name new file mode 100644 index 00000000..337b5a0f --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/initiator/initiator-name @@ -0,0 +1 @@ +iqn.1994-05.com.example.initiator:48b055856417 diff --git a/src/initrd/tests/sysfs/firmware/ibft/initiator/isns-server b/src/initrd/tests/sysfs/firmware/ibft/initiator/isns-server new file mode 100644 index 00000000..4aff9398 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/initiator/isns-server @@ -0,0 +1 @@ +2001:0db8:0000:0000:0000:0000:0000:3205 diff --git a/src/initrd/tests/sysfs/firmware/ibft/initiator/pri-radius-server b/src/initrd/tests/sysfs/firmware/ibft/initiator/pri-radius-server new file mode 100644 index 00000000..a26fb649 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/initiator/pri-radius-server @@ -0,0 +1 @@ +2001:0db8:0000:0000:0000:0000:0000:1812 diff --git a/src/initrd/tests/sysfs/firmware/ibft/initiator/sec-radius-server b/src/initrd/tests/sysfs/firmware/ibft/initiator/sec-radius-server new file mode 100644 index 00000000..908be27f --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/initiator/sec-radius-server @@ -0,0 +1 @@ +192.0.2.181 diff --git a/src/initrd/tests/sysfs/firmware/ibft/initiator/slp-server b/src/initrd/tests/sysfs/firmware/ibft/initiator/slp-server new file mode 100644 index 00000000..fca9e24b --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/initiator/slp-server @@ -0,0 +1 @@ +2001:0db8:0000:0000:0000:0000:0000:0427 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target0/chap-type b/src/initrd/tests/sysfs/firmware/ibft/target0/chap-type new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target0/chap-type @@ -0,0 +1 @@ +0 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target0/flags b/src/initrd/tests/sysfs/firmware/ibft/target0/flags new file mode 100644 index 00000000..00750edc --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target0/flags @@ -0,0 +1 @@ +3 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target0/index b/src/initrd/tests/sysfs/firmware/ibft/target0/index new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target0/index @@ -0,0 +1 @@ +0 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target0/ip-addr b/src/initrd/tests/sysfs/firmware/ibft/target0/ip-addr new file mode 100644 index 00000000..994b6e9c --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target0/ip-addr @@ -0,0 +1 @@ +2001:0db8:0000:0000:0000:0000:0000:3260 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target0/lun b/src/initrd/tests/sysfs/firmware/ibft/target0/lun new file mode 100644 index 00000000..7c295bd4 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target0/lun @@ -0,0 +1 @@ +01000000 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target0/nic-assoc b/src/initrd/tests/sysfs/firmware/ibft/target0/nic-assoc new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target0/nic-assoc @@ -0,0 +1 @@ +0 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target0/port b/src/initrd/tests/sysfs/firmware/ibft/target0/port new file mode 100644 index 00000000..53f0295f --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target0/port @@ -0,0 +1 @@ +3260 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target2/chap-type b/src/initrd/tests/sysfs/firmware/ibft/target2/chap-type new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target2/chap-type @@ -0,0 +1 @@ +0 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target2/flags b/src/initrd/tests/sysfs/firmware/ibft/target2/flags new file mode 100644 index 00000000..00750edc --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target2/flags @@ -0,0 +1 @@ +3 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target2/index b/src/initrd/tests/sysfs/firmware/ibft/target2/index new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target2/index @@ -0,0 +1 @@ +2 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target2/ip-addr b/src/initrd/tests/sysfs/firmware/ibft/target2/ip-addr new file mode 100644 index 00000000..a210477e --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target2/ip-addr @@ -0,0 +1 @@ +2001:0db8:0000:0000:0000:0000:0002:3260 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target2/lun b/src/initrd/tests/sysfs/firmware/ibft/target2/lun new file mode 100644 index 00000000..7c295bd4 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target2/lun @@ -0,0 +1 @@ +01000000 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target2/nic-assoc b/src/initrd/tests/sysfs/firmware/ibft/target2/nic-assoc new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target2/nic-assoc @@ -0,0 +1 @@ +2 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target2/port b/src/initrd/tests/sysfs/firmware/ibft/target2/port new file mode 100644 index 00000000..53f0295f --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target2/port @@ -0,0 +1 @@ +3260 diff --git a/src/initrd/tests/sysfs/firmware/ibft/target2/target-name b/src/initrd/tests/sysfs/firmware/ibft/target2/target-name new file mode 100644 index 00000000..f4094320 --- /dev/null +++ b/src/initrd/tests/sysfs/firmware/ibft/target2/target-name @@ -0,0 +1 @@ +iqn.1994-05.com.example.target:48b055851337 diff --git a/src/initrd/tests/test-cmdline-reader.c b/src/initrd/tests/test-cmdline-reader.c new file mode 100644 index 00000000..4db71147 --- /dev/null +++ b/src/initrd/tests/test-cmdline-reader.c @@ -0,0 +1,787 @@ +/* NetworkManager initrd configuration generator + * + * 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 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include <stdio.h> +#include <stdarg.h> +#include <unistd.h> +#include <string.h> +#include <netinet/ether.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/socket.h> + +#include "nm-core-internal.h" +#include "NetworkManagerUtils.h" + +#include "../nm-initrd-generator.h" + +#include "nm-test-utils-core.h" + +static void +test_auto (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ "ip=auto", NULL }); + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 1); + + connection = g_hash_table_lookup (connections, "default_connection"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + + g_assert (!nm_connection_get_setting_vlan (connection)); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "Wired Connection"); + g_assert_cmpint (nm_setting_connection_get_timestamp (s_con), ==, 0); + g_assert (nm_setting_connection_get_autoconnect (s_con)); + + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + g_assert (!nm_setting_wired_get_mac_address (s_wired)); + g_assert_cmpint (nm_setting_wired_get_mtu (s_wired), ==, 0); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 0); + g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 0); + g_assert (!nm_setting_ip_config_get_gateway (s_ip4)); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 0); + g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip6), ==, 0); + g_assert (!nm_setting_ip_config_get_gateway (s_ip6)); +} + +static void +test_if_auto_with_mtu (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ "ip=eth0:auto:1666", NULL }); + NMConnection *connection; + NMSettingWired *s_wired; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 1); + + connection = g_hash_table_lookup (connections, "eth0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth0"); + + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + g_assert_cmpint (nm_setting_wired_get_mtu (s_wired), ==, 1666); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip4)); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); +} + + +static void +test_if_dhcp6 (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ "ip=eth1:dhcp6", NULL }); + NMConnection *connection; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 1); + connection = g_hash_table_lookup (connections, "eth1"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth1"); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_DISABLED); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip4)); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_DHCP); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); +} + + +static void +test_if_auto_with_mtu_and_mac (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ "ip=eth2:auto6:2048:00:53:ef:12:34:56", NULL }); + NMConnection *connection; + NMSettingWired *s_wired; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 1); + + connection = g_hash_table_lookup (connections, "eth2"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth2"); + + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + g_assert_cmpint (nm_setting_wired_get_mtu (s_wired), ==, 2048); + g_assert_cmpstr (nm_setting_wired_get_cloned_mac_address (s_wired), ==, "00:53:EF:12:34:56"); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_DISABLED); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip4)); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); +} + + +static void +test_if_ip4_manual (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ + "ip=192.0.2.2::192.0.2.1:255.255.255.0:" + "hostname0.example.com:eth3::192.0.2.53", NULL }); + NMConnection *connection; + NMSettingIPConfig *s_ip4; + NMIPAddress *ip_addr; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 1); + + connection = g_hash_table_lookup (connections, "eth3"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth3"); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 1); + g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip4, 0), ==, "192.0.2.53"); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 0); + g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 1); + ip_addr = nm_setting_ip_config_get_address (s_ip4, 0); + g_assert (ip_addr); + g_assert_cmpstr (nm_ip_address_get_address (ip_addr), ==, "192.0.2.2"); + g_assert_cmpint (nm_ip_address_get_prefix (ip_addr), ==, 24); + g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "192.0.2.1"); + g_assert_cmpstr (nm_setting_ip_config_get_dhcp_hostname (s_ip4), ==, "hostname0.example.com"); +} + + +static void +test_if_ip6_manual (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ + "ip=[2001:0db8::02]/64::[2001:0db8::01]::" + "hostname0.example.com:eth4::[2001:0db8::53]", + NULL + }); + NMConnection *connection; + NMSettingIPConfig *s_ip6; + NMIPAddress *ip_addr; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 1); + + connection = g_hash_table_lookup (connections, "eth4"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth4"); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_MANUAL); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 1); + g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip6, 0), ==, "2001:db8::53"); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 0); + g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip6), ==, 1); + ip_addr = nm_setting_ip_config_get_address (s_ip6, 0); + g_assert (ip_addr); + g_assert_cmpstr (nm_ip_address_get_address (ip_addr), ==, "2001:db8::2"); + g_assert_cmpint (nm_ip_address_get_prefix (ip_addr), ==, 64); + g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip6), ==, "2001:db8::1"); + g_assert_cmpstr (nm_setting_ip_config_get_dhcp_hostname (s_ip6), ==, "hostname0.example.com"); +} + +static void +test_multiple (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ "ip=192.0.2.2:::::eth0", "ip=[2001:db8::2]:::::eth0", NULL }); + NMConnection *connection; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + NMIPAddress *ip_addr; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 1); + + connection = g_hash_table_lookup (connections, "eth0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth0"); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 1); + ip_addr = nm_setting_ip_config_get_address (s_ip4, 0); + g_assert (ip_addr); + g_assert_cmpstr (nm_ip_address_get_address (ip_addr), ==, "192.0.2.2"); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_MANUAL); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip6), ==, 1); + ip_addr = nm_setting_ip_config_get_address (s_ip6, 0); + g_assert (ip_addr); + g_assert_cmpstr (nm_ip_address_get_address (ip_addr), ==, "2001:db8::2"); +} + +static void +test_some_more (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ "bootdev=eth1", "hail", "nameserver=[2001:DB8:3::53]", + "satan", "nameserver=192.0.2.53", "worship", + "BOOTIF=00-53-AB-cd-02-03", "doom", "rd.peerdns=0", + "rd.route=[2001:DB8:3::/48]:[2001:DB8:2::1]:ens10", + NULL }); + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + NMIPRoute *ip_route; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 2); + + connection = g_hash_table_lookup (connections, "default_connection"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "Wired Connection"); + g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, "eth1"); + + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + g_assert_cmpstr (nm_setting_wired_get_mac_address (s_wired), ==, "00:53:AB:CD:02:03"); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + g_assert (nm_setting_ip_config_get_ignore_auto_dns (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 0); + g_assert (!nm_setting_ip_config_get_gateway (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 1); + g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip4, 0), ==, "192.0.2.53"); + + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_assert (nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 1); + g_assert (!nm_setting_ip_config_get_gateway (s_ip6)); + g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip6, 0), ==, "2001:db8:3::53"); + + + connection = g_hash_table_lookup (connections, "ens10"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "ens10"); + g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, "ens10"); + + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + g_assert (!nm_setting_wired_get_mac_address (s_wired)); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 0); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 1); + g_assert (!nm_setting_ip_config_get_gateway (s_ip6)); + ip_route = nm_setting_ip_config_get_route (s_ip6, 0); + g_assert_cmpstr (nm_ip_route_get_dest (ip_route), ==, "2001:db8:3::"); + g_assert_cmpint (nm_ip_route_get_family (ip_route), ==, AF_INET6); + g_assert_cmpint (nm_ip_route_get_metric (ip_route), ==, -1); + g_assert_cmpstr (nm_ip_route_get_next_hop (ip_route), ==, "2001:db8:2::1"); + g_assert_cmpint (nm_ip_route_get_prefix (ip_route), ==, 48); +} + +static void +test_no_bootif (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ "BOOTIF=00-53-AB-cd-02-03", "rd.bootif=0", NULL }); + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 0); +} + +static void +test_bond (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ "rd.route=192.0.2.53::bong0", "bond=bong0:eth0,eth1:mode=balance-rr", NULL }); + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + NMSettingBond *s_bond; + NMIPRoute *ip_route; + const char *master_uuid; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 3); + + connection = g_hash_table_lookup (connections, "bong0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_connection_type (connection), ==, NM_SETTING_BOND_SETTING_NAME); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "bong0"); + master_uuid = nm_connection_get_uuid (connection); + g_assert (master_uuid); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 0); + g_assert (!nm_setting_ip_config_get_gateway (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 1); + ip_route = nm_setting_ip_config_get_route (s_ip4, 0); + g_assert_cmpstr (nm_ip_route_get_dest (ip_route), ==, "192.0.2.53"); + g_assert_cmpint (nm_ip_route_get_family (ip_route), ==, AF_INET); + g_assert_cmpint (nm_ip_route_get_metric (ip_route), ==, -1); + g_assert (!nm_ip_route_get_next_hop (ip_route)); + g_assert_cmpint (nm_ip_route_get_prefix (ip_route), ==, 32); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 0); + g_assert (!nm_setting_ip_config_get_gateway (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 0); + + s_bond = nm_connection_get_setting_bond (connection); + g_assert (s_bond); + g_assert_cmpint (nm_setting_bond_get_num_options (s_bond), ==, 1); + g_assert_cmpstr (nm_setting_bond_get_option_by_name (s_bond, "mode"), ==, "balance-rr"); + + connection = g_hash_table_lookup (connections, "eth0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth0"); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "eth0"); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_BOND_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, master_uuid); + + connection = g_hash_table_lookup (connections, "eth1"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth1"); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "eth1"); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_BOND_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, master_uuid); +} + +static void +test_bond_default (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ "bond", NULL }); + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + NMSettingBond *s_bond; + const char *master_uuid; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 2); + + connection = g_hash_table_lookup (connections, "bond0"); + + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_connection_type (connection), ==, NM_SETTING_BOND_SETTING_NAME); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "bond0"); + master_uuid = nm_connection_get_uuid (connection); + g_assert (master_uuid); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 0); + g_assert (!nm_setting_ip_config_get_gateway (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 0); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 0); + g_assert (!nm_setting_ip_config_get_gateway (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 0); + + s_bond = nm_connection_get_setting_bond (connection); + g_assert (s_bond); + g_assert_cmpint (nm_setting_bond_get_num_options (s_bond), ==, 1); + g_assert_cmpstr (nm_setting_bond_get_option_by_name (s_bond, "mode"), ==, "balance-rr"); + + connection = g_hash_table_lookup (connections, "eth0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth0"); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "eth0"); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_BOND_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, master_uuid); +} + +static void +test_bridge (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ "bridge=bridge0:eth0,eth1", "rd.route=192.0.2.53::bridge0", NULL }); + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + NMSettingBridge *s_bridge; + NMIPRoute *ip_route; + const char *master_uuid; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 3); + + connection = g_hash_table_lookup (connections, "bridge0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_connection_type (connection), ==, NM_SETTING_BRIDGE_SETTING_NAME); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "bridge0"); + master_uuid = nm_connection_get_uuid (connection); + g_assert (master_uuid); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 0); + g_assert (!nm_setting_ip_config_get_gateway (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 1); + ip_route = nm_setting_ip_config_get_route (s_ip4, 0); + g_assert_cmpstr (nm_ip_route_get_dest (ip_route), ==, "192.0.2.53"); + g_assert_cmpint (nm_ip_route_get_family (ip_route), ==, AF_INET); + g_assert_cmpint (nm_ip_route_get_metric (ip_route), ==, -1); + g_assert (!nm_ip_route_get_next_hop (ip_route)); + g_assert_cmpint (nm_ip_route_get_prefix (ip_route), ==, 32); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 0); + g_assert (!nm_setting_ip_config_get_gateway (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 0); + + s_bridge = nm_connection_get_setting_bridge (connection); + g_assert (s_bridge); + + connection = g_hash_table_lookup (connections, "eth0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth0"); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "eth0"); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_BRIDGE_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, master_uuid); + + connection = g_hash_table_lookup (connections, "eth1"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth1"); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "eth1"); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_BRIDGE_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, master_uuid); +} + +static void +test_bridge_default (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ "bridge", NULL }); + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + NMSettingBridge *s_bridge; + const char *master_uuid; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 2); + + connection = g_hash_table_lookup (connections, "bridge0"); + + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_connection_type (connection), ==, NM_SETTING_BRIDGE_SETTING_NAME); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "bridge0"); + master_uuid = nm_connection_get_uuid (connection); + g_assert (master_uuid); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 0); + g_assert (!nm_setting_ip_config_get_gateway (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 0); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 0); + g_assert (!nm_setting_ip_config_get_gateway (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 0); + + s_bridge = nm_connection_get_setting_bridge (connection); + g_assert (s_bridge); + + connection = g_hash_table_lookup (connections, "eth0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth0"); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "eth0"); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_BRIDGE_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, master_uuid); +} + +static void +test_team (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ "team=team0:eth0,eth1", "ip=team0:dhcp6", NULL }); + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + NMSettingTeam *s_team; + const char *master_uuid; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 3); + + connection = g_hash_table_lookup (connections, "team0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_connection_type (connection), ==, NM_SETTING_TEAM_SETTING_NAME); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "team0"); + master_uuid = nm_connection_get_uuid (connection); + g_assert (master_uuid); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_DISABLED); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 0); + g_assert (!nm_setting_ip_config_get_gateway (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip4), ==, 0); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_DHCP); + g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 0); + g_assert (!nm_setting_ip_config_get_gateway (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 0); + + s_team = nm_connection_get_setting_team (connection); + g_assert (s_team); + + connection = g_hash_table_lookup (connections, "eth0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth0"); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "eth0"); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_TEAM_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, master_uuid); + + connection = g_hash_table_lookup (connections, "eth1"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "eth1"); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "eth1"); + g_assert_cmpstr (nm_setting_connection_get_slave_type (s_con), ==, NM_SETTING_TEAM_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, master_uuid); +} + +static void +test_ibft (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ "ip=ibft", NULL }); + NMConnection *connection; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 2); + + connection = g_hash_table_lookup (connections, "ibft0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "iBFT VLAN Connection 0"); + + connection = g_hash_table_lookup (connections, "ibft2"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert_cmpstr (nm_connection_get_id (connection), ==, "iBFT Connection 2"); +} + +static void +test_ignore_extra (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + gs_strfreev char **argv = g_strdupv ((char *[]){ "blabla", "extra", "lalala", NULL }); + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", argv); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 0); +} + +NMTST_DEFINE (); + +int main (int argc, char **argv) +{ + nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); + + g_test_add_func ("/initrd/cmdline/auto", test_auto); + g_test_add_func ("/initrd/cmdline/if_auto_with_mtu", test_if_auto_with_mtu); + g_test_add_func ("/initrd/cmdline/if_dhcp6", test_if_dhcp6); + g_test_add_func ("/initrd/cmdline/if_auto_with_mtu_and_mac", test_if_auto_with_mtu_and_mac); + g_test_add_func ("/initrd/cmdline/if_ip4_manual", test_if_ip4_manual); + g_test_add_func ("/initrd/cmdline/if_ip6_manual", test_if_ip6_manual); + g_test_add_func ("/initrd/cmdline/multiple", test_multiple); + g_test_add_func ("/initrd/cmdline/some_more", test_some_more); + g_test_add_func ("/initrd/cmdline/no_bootif", test_no_bootif); + g_test_add_func ("/initrd/cmdline/bond", test_bond); + g_test_add_func ("/initrd/cmdline/bond/default", test_bond_default); + g_test_add_func ("/initrd/cmdline/team", test_team); + g_test_add_func ("/initrd/cmdline/bridge", test_bridge); + g_test_add_func ("/initrd/cmdline/bridge/default", test_bridge_default); + g_test_add_func ("/initrd/cmdline/ibft", test_ibft); + g_test_add_func ("/initrd/cmdline/ignore_extra", test_ignore_extra); + + return g_test_run (); +} diff --git a/src/initrd/tests/test-ibft-reader.c b/src/initrd/tests/test-ibft-reader.c new file mode 100644 index 00000000..340b3896 --- /dev/null +++ b/src/initrd/tests/test-ibft-reader.c @@ -0,0 +1,286 @@ +/* NetworkManager initrd configuration generator + * + * 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 2014 - 2018 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include <stdio.h> +#include <stdarg.h> +#include <unistd.h> +#include <string.h> +#include <netinet/ether.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/socket.h> + +#include "nm-core-internal.h" +#include "NetworkManagerUtils.h" + +#include "../nm-initrd-generator.h" + +#include "nm-test-utils-core.h" + +static NMConnection * +read_connection (const char *sysfs_dir, const char *expected_mac, GError **error) +{ + NMConnection *connection = NULL; + gs_unref_hashtable GHashTable *ibft = NULL; + gs_free char *mac = NULL; + GHashTable *nic = NULL; + + ibft = nmi_ibft_read (sysfs_dir); + + mac = g_ascii_strup (expected_mac, -1); + nic = g_hash_table_lookup (ibft, mac); + if (!nic) + return NULL; + + connection = nm_simple_connection_new (); + + if (!nmi_ibft_update_connection_from_nic (connection, nic, error)) + g_clear_object (&connection); + + return connection; +} + +static void +test_read_ibft_dhcp (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + GError *error = NULL; + const char *mac_address; + const char *expected_mac_address = "00:33:21:98:b9:f1"; + + connection = read_connection (TEST_INITRD_DIR "/sysfs-dhcp", expected_mac_address, &error); + g_assert_no_error (error); + nmtst_assert_connection_verifies_without_normalization (connection); + + g_assert (!nm_connection_get_setting_vlan (connection)); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "iBFT Connection 1"); + g_assert_cmpint (nm_setting_connection_get_timestamp (s_con), ==, 0); + g_assert (nm_setting_connection_get_autoconnect (s_con)); + + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + mac_address = nm_setting_wired_get_mac_address (s_wired); + g_assert (mac_address); + g_assert (nm_utils_hwaddr_matches (mac_address, -1, expected_mac_address, -1)); + g_assert_cmpint (nm_setting_wired_get_mtu (s_wired), ==, 0); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_IGNORE); + + g_object_unref (connection); +} + +static void +test_read_ibft_static (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + GError *error = NULL; + const char *mac_address; + const char *expected_mac_address = "00:33:21:98:b9:f0"; + NMIPAddress *ip4_addr; + + connection = read_connection (TEST_INITRD_DIR "/sysfs-static", expected_mac_address, &error); + g_assert_no_error (error); + nmtst_assert_connection_verifies_without_normalization (connection); + + g_assert (!nm_connection_get_setting_vlan (connection)); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "iBFT Connection 0"); + g_assert_cmpint (nm_setting_connection_get_timestamp (s_con), ==, 0); + g_assert (nm_setting_connection_get_autoconnect (s_con)); + + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + mac_address = nm_setting_wired_get_mac_address (s_wired); + g_assert (mac_address); + g_assert (nm_utils_hwaddr_matches (mac_address, -1, expected_mac_address, -1)); + g_assert_cmpint (nm_setting_wired_get_mtu (s_wired), ==, 0); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); + + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 2); + g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip4, 0), ==, "10.16.255.2"); + g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip4, 1), ==, "10.16.255.3"); + + g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 1); + ip4_addr = nm_setting_ip_config_get_address (s_ip4, 0); + g_assert (ip4_addr); + g_assert_cmpstr (nm_ip_address_get_address (ip4_addr), ==, "192.168.32.72"); + g_assert_cmpint (nm_ip_address_get_prefix (ip4_addr), ==, 22); + + g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, "192.168.35.254"); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_IGNORE); + + g_object_unref (connection); +} + + +static void +test_read_ibft_bad_address (gconstpointer user_data) +{ + const char *sysfs_dir = user_data; + NMConnection *connection; + GError *error = NULL; + + g_assert (g_file_test (sysfs_dir, G_FILE_TEST_EXISTS)); + + connection = read_connection (sysfs_dir, "00:33:21:98:b9:f0", &error); + g_assert (connection == NULL); + g_assert (error); + g_clear_error (&error); +} + +static void +test_read_ibft_vlan (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingVlan *s_vlan; + NMSettingIPConfig *s_ip4; + const char *mac_address; + const char *expected_mac_address = "00:33:21:98:b9:f0"; + NMIPAddress *ip4_addr; + GError *error = NULL; + + connection = read_connection (TEST_INITRD_DIR "/sysfs-vlan", expected_mac_address, &error); + g_assert_no_error (error); + nmtst_assert_connection_verifies_without_normalization (connection); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_VLAN_SETTING_NAME); + + /* ===== WIRED SETTING ===== */ + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + mac_address = nm_setting_wired_get_mac_address (s_wired); + g_assert (mac_address); + g_assert (nm_utils_hwaddr_matches (mac_address, -1, expected_mac_address, -1)); + + /* ===== VLAN SETTING ===== */ + s_vlan = nm_connection_get_setting_vlan (connection); + g_assert (s_vlan); + g_assert_cmpint (nm_setting_vlan_get_id (s_vlan), ==, 123); + g_assert_cmpstr (nm_setting_vlan_get_parent (s_vlan), ==, NULL); + + /* ===== IPv4 SETTING ===== */ + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); + + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 0); + + g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 1); + ip4_addr = nm_setting_ip_config_get_address (s_ip4, 0); + g_assert (ip4_addr); + g_assert_cmpstr (nm_ip_address_get_address (ip4_addr), ==, "192.168.6.200"); + g_assert_cmpint (nm_ip_address_get_prefix (ip4_addr), ==, 24); + + g_assert_cmpstr (nm_setting_ip_config_get_gateway (s_ip4), ==, NULL); + + g_object_unref (connection); +} + +static void +test_read_ibft (void) +{ + NMConnection *connection; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + GError *error = NULL; + + /* This test doesn't actually test too much (apart from the presence of + * IPv6 that is not covered by other tests), but the test fixture is a good + * example of about everything that can be included in iBFT table (as of + * ACPI 3.0b). */ + + connection = read_connection (TEST_INITRD_DIR "/sysfs", "00:53:00:AB:00:01", &error); + g_assert (connection); + g_assert_no_error (error); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + g_assert (nm_setting_ip_config_get_num_addresses (s_ip4) == 0); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_DISABLED); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (nm_setting_ip_config_get_num_addresses (s_ip6) == 1); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + g_object_unref (connection); + + connection = read_connection (TEST_INITRD_DIR "/sysfs", "00:53:06:66:AB:01", &error); + g_assert (connection); + g_assert_no_error (error); + nmtst_assert_connection_verifies_without_normalization (connection); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (nm_setting_ip_config_get_num_addresses (s_ip4) == 1); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (nm_setting_ip_config_get_num_addresses (s_ip6) == 0); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_IGNORE); + g_object_unref (connection); +} + +NMTST_DEFINE (); + +int main (int argc, char **argv) +{ + nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); + + g_test_add_func ("/initrd/ibft", test_read_ibft); + g_test_add_func ("/initrd/ibft/dhcp", test_read_ibft_dhcp); + g_test_add_func ("/initrd/ibft/static", test_read_ibft_static); + g_test_add_func ("/initrd/ibft/vlan", test_read_ibft_vlan); + g_test_add_data_func ("/initrd/ibft/bad-ipaddr-read", TEST_INITRD_DIR "/sysfs-bad-ipaddr", test_read_ibft_bad_address); + g_test_add_data_func ("/initrd/ibft/bad-gateway-read", TEST_INITRD_DIR "/sysfs-bad-gateway", test_read_ibft_bad_address); + g_test_add_data_func ("/initrd/ibft/bad-dns1-read", TEST_INITRD_DIR "/sysfs-bad-dns1", test_read_ibft_bad_address); + g_test_add_data_func ("/initrd/ibft/bad-dns2-read", TEST_INITRD_DIR "/sysfs-bad-dns2", test_read_ibft_bad_address); + + return g_test_run (); +} diff --git a/src/main-utils.c b/src/main-utils.c index 0f790536..a597ede7 100644 --- a/src/main-utils.c +++ b/src/main-utils.c @@ -177,7 +177,7 @@ nm_main_utils_ensure_not_running_pidfile (const char *pidfile) gs_free char *contents = NULL; gs_free char *proc_cmdline = NULL; gsize len = 0; - glong pid; + long pid; const char *process_name; const char *prgname = g_get_prgname (); diff --git a/src/main.c b/src/main.c index 7da0c3c2..f834fa94 100644 --- a/src/main.c +++ b/src/main.c @@ -59,7 +59,6 @@ #endif #define NM_DEFAULT_PID_FILE NMRUNDIR "/NetworkManager.pid" -#define NM_DEFAULT_SYSTEM_STATE_FILE NMSTATEDIR "/NetworkManager.state" #define CONFIG_ATOMIC_SECTION_PREFIXES ((char **) NULL) @@ -398,8 +397,13 @@ main (int argc, char *argv[]) NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT, NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT_BOOL)); - if (!nm_dbus_manager_acquire_bus (nm_dbus_manager_get ())) - goto done_no_manager; + if (!nm_config_get_configure_and_quit (config)) { + /* D-Bus is useless in configure and quit mode -- we're eventually dropping + * off and potential clients would have no way of knowing whether we're + * finished already or didn't start yet. */ + if (!nm_dbus_manager_acquire_bus (nm_dbus_manager_get ())) + goto done_no_manager; + } manager = nm_manager_setup (); nm_dbus_manager_start (nm_dbus_manager_get(), @@ -444,7 +448,7 @@ done: * state here. We don't bother updating the state as devices * change during regular operation. If NM is killed with SIGKILL, * it misses to update the state. */ - nm_manager_write_device_state (manager); + nm_manager_write_device_state_all (manager); nm_manager_stop (manager); diff --git a/src/meson.build b/src/meson.build index e60ab93f..87c57671 100644 --- a/src/meson.build +++ b/src/meson.build @@ -17,35 +17,7 @@ nm_dep = declare_dependency( compile_args: nm_cflags ) -cflags = nm_cflags + [ - '-DPREFIX="@0@"'.format(nm_prefix), - '-DBINDIR="@0@"'.format(nm_bindir), - '-DDATADIR="@0@"'.format(nm_datadir), - '-DLIBEXECDIR="@0@"'.format(nm_libexecdir), - '-DLOCALSTATEDIR="@0@"'.format(nm_localstatedir), - '-DRUNSTATEDIR="@0@"'.format(nm_runstatedir), - '-DSBINDIR="@0@"'.format(nm_sbindir), - '-DSYSCONFDIR="@0@"'.format(nm_sysconfdir), - '-DRUNDIR="@0@"'.format(nm_pkgrundir), - '-DNMCONFDIR="@0@"'.format(nm_pkgconfdir), - '-DNMLOCALEDIR="@0@"'.format(nm_localedir), - '-DNMPLUGINDIR="@0@"'.format(nm_plugindir), - '-DNMRUNDIR="@0@"'.format(nm_pkgrundir), - '-DNMSTATEDIR="@0@"'.format(nm_pkgstatedir), - '-DNMLIBDIR="@0@"'.format(nm_pkglibdir) -] - -if enable_dhcpcanon - cflags += '-DDHCPCANON_PATH="@0@"'.format(dhcpcanon.path()) -endif - -if enable_dhclient - cflags += '-DDHCLIENT_PATH="@0@"'.format(dhclient.path()) -endif - -if enable_dhcpcd - cflags += '-DDHCPCD_PATH="@0@"'.format(dhcpcd.path()) -endif +cflags = nm_cflags sources = files( 'dhcp/nm-dhcp-client.c', @@ -55,8 +27,9 @@ sources = files( 'ndisc/nm-lndp-ndisc.c', 'ndisc/nm-ndisc.c', 'platform/nm-netlink.c', - 'platform/wifi/wifi-utils-nl80211.c', - 'platform/wifi/wifi-utils.c', + 'platform/wifi/nm-wifi-utils-nl80211.c', + 'platform/wifi/nm-wifi-utils.c', + 'platform/wpan/nm-wpan-utils.c', 'platform/nm-linux-platform.c', 'platform/nm-platform.c', 'platform/nm-platform-utils.c', @@ -79,7 +52,7 @@ deps = [ ] if enable_wext - sources += files('platform/wifi/wifi-utils-wext.c') + sources += files('platform/wifi/nm-wifi-utils-wext.c') endif libnetwork_manager_base = static_library( @@ -92,6 +65,7 @@ libnetwork_manager_base = static_library( sources = files( 'devices/nm-acd-manager.c', + 'devices/nm-device-6lowpan.c', 'devices/nm-device-bond.c', 'devices/nm-device-bridge.c', 'devices/nm-device.c', @@ -109,6 +83,8 @@ sources = files( 'devices/nm-device-veth.c', 'devices/nm-device-vlan.c', 'devices/nm-device-vxlan.c', + 'devices/nm-device-wireguard.c', + 'devices/nm-device-wpan.c', 'devices/nm-lldp-listener.c', 'dhcp/nm-dhcp-dhclient.c', 'dhcp/nm-dhcp-dhclient-utils.c', @@ -167,86 +143,39 @@ sources = files( 'nm-sleep-monitor.c' ) -deps = [ +nm_deps = [ dl_dep, libndp_dep, - # FIXME: Some files use introspection/dbus* headers, so - # this dependency might be needed - #libnmdbus_dep, libudev_dep, nm_core_dep, - shared_n_acd_dep + shared_n_acd_dep, + logind_dep, ] if enable_concheck - deps += libcurl_dep + nm_deps += libcurl_dep endif if enable_libaudit - deps += libaudit_dep + nm_deps += libaudit_dep endif if enable_libpsl - deps += libpsl_dep + nm_deps += libpsl_dep endif if enable_selinux - deps += selinux_dep -endif - -if enable_session_tracking - deps += logind_dep + nm_deps += selinux_dep endif libnetwork_manager = static_library( nm_name, sources: sources, - dependencies: deps, + dependencies: nm_deps, c_args: cflags, link_with: [libnetwork_manager_base, libsystemd_nm] ) -ldflags = ['-rdynamic'] - -# FIXME: this doesn't work and it depends on libtool -''' -src/NetworkManager.ver: src/libNetworkManager.la $(core_plugins) - $(AM_V_GEN) NM="$(NM)" "$(srcdir)/tools/create-exports-NetworkManager.sh" --called-from-make "$(srcdir)" - -src_NetworkManager_LDFLAGS = \ - -rdynamic \ - -Wl,--version-script="src/NetworkManager.ver" - -nm = find_program('gcc-nm', 'nm') -create_exports_networkmanager = join_paths(meson.source_root(), 'tools', 'create-exports-NetworkManager.sh') - -symbol_map_name = 'NetworkManager.ver' - -linker_script = custom_target( - symbol_map_name, - input: meson.source_root(), - output: symbol_map_name, - capture: true, - #command: ['NM=' + nm.path(), create_exports_networkmanager, '--called-from-make', '@INPUT@'] - command: [create_exports_networkmanager, '--called-from-make', '@INPUT@'] -) - -ldflags += '-Wl,--version-script,@0@'.format(linker_script) -''' - -network_manager = executable( - nm_name, - 'main.c', - dependencies: deps, - c_args: cflags, - link_with: libnetwork_manager, - link_args: ldflags, - #FIXME - #link_depends: linker_script, - install: true, - install_dir: nm_sbindir -) - deps = [ dl_dep, libndp_dep, @@ -316,4 +245,57 @@ if enable_ppp endif subdir('devices') +subdir('initrd') subdir('settings/plugins') + +# NetworkManager binary + +create_exports_networkmanager = join_paths(meson.source_root(), 'tools', 'create-exports-NetworkManager.sh') +symbol_map_name = 'NetworkManager.ver' + +# libNetworkManager.a, as built by meson doesn't contain all symbols +# from libNetworkManagerBase.a and other static libraries, unless we +# add dependencies with link_whole, only supported in meson >= 0.46. +# Create an executable with full symbols that we use in place of the +# library to enumerate the symbols. +network_manager_sym = executable( + 'nm-full-symbols', + 'main.c', + c_args: nm_cflags, + link_args: '-Wl,--no-gc-sections', + dependencies: nm_deps, + link_whole: [libnetwork_manager, libnetwork_manager_base, libnm_core], + install: false, +) + +# this uses symbols from nm-full-symbols instead of libNetworkManager.a +ver_script = custom_target( + symbol_map_name, + input: meson.source_root(), + output: symbol_map_name, + depends: [ network_manager_sym, core_plugins ], + command: [create_exports_networkmanager, '--called-from-build', '@INPUT@'] +) + +ldflags = ['-rdynamic', '-Wl,--version-script,@0@'.format(ver_script.full_path())] + +network_manager = executable( + nm_name, + 'main.c', + dependencies: nm_deps, + c_args: nm_cflags, + link_with: libnetwork_manager, + link_args: ldflags, + link_depends: ver_script, + install: true, + install_dir: nm_sbindir +) + +if enable_tests + foreach plugin : core_plugins + test ('sym/' + plugin.full_path().split('/')[-1], + network_manager, + args: '--version', + env: ['LD_BIND_NOW=1', 'LD_PRELOAD=' + plugin.full_path()]) + endforeach +endif diff --git a/src/ndisc/nm-fake-ndisc.c b/src/ndisc/nm-fake-ndisc.c index 15abee88..6e9a72c6 100644 --- a/src/ndisc/nm-fake-ndisc.c +++ b/src/ndisc/nm-fake-ndisc.c @@ -296,7 +296,7 @@ receive_ra (gpointer user_data) .dad_counter = 0, }; - if (nm_ndisc_complete_and_add_address (ndisc, &address)) + if (nm_ndisc_complete_and_add_address (ndisc, &address, now)) changed |= NM_NDISC_CONFIG_ADDRESSES; } } diff --git a/src/ndisc/nm-lndp-ndisc.c b/src/ndisc/nm-lndp-ndisc.c index c0a0cd40..9f427d4d 100644 --- a/src/ndisc/nm-lndp-ndisc.c +++ b/src/ndisc/nm-lndp-ndisc.c @@ -221,10 +221,10 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) .preferred = ndp_msg_opt_prefix_preferred_time (msg, offset), }; - if (address.preferred > address.lifetime) - address.preferred = address.lifetime; - if (nm_ndisc_complete_and_add_address (ndisc, &address)) - changed |= NM_NDISC_CONFIG_ADDRESSES; + if (address.preferred <= address.lifetime) { + if (nm_ndisc_complete_and_add_address (ndisc, &address, now)) + changed |= NM_NDISC_CONFIG_ADDRESSES; + } } } ndp_msg_opt_for_each_offset(offset, msg, NDP_MSG_OPT_ROUTE) { @@ -491,13 +491,17 @@ receive_rs (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) static gboolean event_ready (GIOChannel *source, GIOCondition condition, NMNDisc *ndisc) { + gs_unref_object NMNDisc *ndisc_keep_alive = g_object_ref (ndisc); nm_auto_pop_netns NMPNetns *netns = NULL; NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE ((NMLndpNDisc *) ndisc); _LOGD ("processing libndp events"); - if (!nm_ndisc_netns_push (ndisc, &netns)) - return G_SOURCE_CONTINUE; + if (!nm_ndisc_netns_push (ndisc, &netns)) { + /* something is very wrong. Stop handling events. */ + priv->event_id = 0; + return G_SOURCE_REMOVE; + } ndp_callall_eventfd_handler (priv->ndp); return G_SOURCE_CONTINUE; diff --git a/src/ndisc/nm-ndisc-private.h b/src/ndisc/nm-ndisc-private.h index bbecb01a..ae03c0ee 100644 --- a/src/ndisc/nm-ndisc-private.h +++ b/src/ndisc/nm-ndisc-private.h @@ -40,7 +40,7 @@ void nm_ndisc_ra_received (NMNDisc *ndisc, gint32 now, NMNDiscConfigMap changed) void nm_ndisc_rs_received (NMNDisc *ndisc); gboolean nm_ndisc_add_gateway (NMNDisc *ndisc, const NMNDiscGateway *new); -gboolean nm_ndisc_complete_and_add_address (NMNDisc *ndisc, NMNDiscAddress *new); +gboolean nm_ndisc_complete_and_add_address (NMNDisc *ndisc, const NMNDiscAddress *new, gint32 now_s); gboolean nm_ndisc_add_route (NMNDisc *ndisc, const NMNDiscRoute *new); gboolean nm_ndisc_add_dns_server (NMNDisc *ndisc, const NMNDiscDNSServer *new); gboolean nm_ndisc_add_dns_domain (NMNDisc *ndisc, const NMNDiscDNSDomain *new); diff --git a/src/ndisc/nm-ndisc.c b/src/ndisc/nm-ndisc.c index 04f86312..1dd8398c 100644 --- a/src/ndisc/nm-ndisc.c +++ b/src/ndisc/nm-ndisc.c @@ -124,6 +124,79 @@ _preference_to_priority (NMIcmpv6RouterPref pref) /*****************************************************************************/ +/* we rely on the fact, that _EXPIRY_INFINITY > any other valid gint64 timestamps. */ +#define _EXPIRY_INFINITY G_MAXINT64 + +static gint64 +get_expiry_time (guint32 timestamp, guint32 lifetime) +{ + nm_assert (timestamp > 0); + nm_assert (timestamp <= G_MAXINT32); + + if (lifetime == NM_NDISC_INFINITY) + return _EXPIRY_INFINITY; + return ((gint64) timestamp) + ((gint64) lifetime); +} + +#define get_expiry(item) \ + ({ \ + typeof (item) _item = (item); \ + nm_assert (_item); \ + get_expiry_time (_item->timestamp, _item->lifetime); \ + }) + +#define get_expiry_half(item) \ + ({ \ + typeof (item) _item = (item); \ + nm_assert (_item); \ + (_item->lifetime == NM_NDISC_INFINITY) \ + ? _EXPIRY_INFINITY \ + : get_expiry_time (_item->timestamp, _item->lifetime / 2); \ + }) + +#define get_expiry_preferred(item) \ + ({ \ + typeof (item) _item = (item); \ + nm_assert (_item); \ + get_expiry_time (_item->timestamp, _item->preferred); \ + }) + +static gboolean +expiry_next (gint32 now_s, gint64 expiry_timestamp, gint32 *nextevent) +{ + gint32 e; + + if (expiry_timestamp == _EXPIRY_INFINITY) + return TRUE; + e = MIN (expiry_timestamp, ((gint64) (G_MAXINT32 - 1))); + if (now_s >= e) + return FALSE; + if (nextevent) { + if (*nextevent > e) + *nextevent = e; + } + return TRUE; +} + +static const char * +_get_exp (char *buf, gsize buf_size, gint64 now_ns, gint64 expiry_time) +{ + int l; + + if (expiry_time == _EXPIRY_INFINITY) + return "permanent"; + l = g_snprintf (buf, buf_size, + "%.4f", + ((double) ((expiry_time * NM_UTILS_NS_PER_SECOND) - now_ns)) / ((double) NM_UTILS_NS_PER_SECOND)); + nm_assert (l < buf_size); + return buf; +} + +#define get_exp(buf, now_ns, item) \ + _get_exp ((buf), G_N_ELEMENTS (buf), (now_ns), (get_expiry (item))) + +/*****************************************************************************/ + NMPNetns * nm_ndisc_netns_get (NMNDisc *self) { @@ -264,9 +337,12 @@ nm_ndisc_add_gateway (NMNDisc *ndisc, const NMNDiscGateway *new) continue; } + if (get_expiry (item) == get_expiry (new)) + return FALSE; + *item = *new; _ASSERT_data_gateways (rdata); - return FALSE; + return TRUE; } /* Put before less preferable gateways. */ @@ -343,33 +419,101 @@ complete_address (NMNDisc *ndisc, NMNDiscAddress *addr) } static gboolean -nm_ndisc_add_address (NMNDisc *ndisc, const NMNDiscAddress *new) +nm_ndisc_add_address (NMNDisc *ndisc, + const NMNDiscAddress *new, + gint32 now_s, + gboolean from_ra) { NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (ndisc); NMNDiscDataInternal *rdata = &priv->rdata; + NMNDiscAddress new2; + NMNDiscAddress *existing = NULL; guint i; nm_assert (new); nm_assert (new->timestamp > 0 && new->timestamp < G_MAXINT32); nm_assert (!IN6_IS_ADDR_UNSPECIFIED (&new->address)); nm_assert (!IN6_IS_ADDR_LINKLOCAL (&new->address)); + nm_assert (new->preferred <= new->lifetime); + nm_assert (!from_ra || now_s > 0); for (i = 0; i < rdata->addresses->len; i++) { NMNDiscAddress *item = &g_array_index (rdata->addresses, NMNDiscAddress, i); - if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) { - gboolean changed; + if (from_ra) { + /* RFC4862 5.5.3.d, we find an existing address with the same prefix. + * (note that all prefixes at this point have implicity length /64). */ + if (memcmp (&item->address, &new->address, 8) == 0) { + existing = item; + break; + } + } else { + if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) { + existing = item; + break; + } + } + } - if (new->lifetime == 0) { - g_array_remove_index (rdata->addresses, i); - return TRUE; + if (existing) { + if (from_ra) { + const gint32 NM_NDISC_PREFIX_LFT_MIN = 7200; /* seconds, RFC4862 5.5.3.e */ + gint64 old_expiry_lifetime, old_expiry_preferred; + + old_expiry_lifetime = get_expiry (existing); + old_expiry_preferred = get_expiry_preferred (existing); + + if (new->lifetime == NM_NDISC_INFINITY) + existing->lifetime = NM_NDISC_INFINITY; + else { + gint64 new_lifetime, remaining_lifetime; + + /* see RFC4862 5.5.3.e */ + if (existing->lifetime == NM_NDISC_INFINITY) + remaining_lifetime = G_MAXINT64; + else + remaining_lifetime = ((gint64) existing->timestamp) + ((gint64) existing->lifetime) - ((gint64) now_s); + new_lifetime = ((gint64) new->timestamp) + ((gint64) new->lifetime) - ((gint64) now_s); + + if ( new_lifetime > (gint64) NM_NDISC_PREFIX_LFT_MIN + || new_lifetime > remaining_lifetime) { + existing->timestamp = now_s; + existing->lifetime = CLAMP (new_lifetime, (gint64) 0, (gint64) (G_MAXUINT32 - 1)); + } else if (remaining_lifetime <= (gint64) NM_NDISC_PREFIX_LFT_MIN) { + /* keep the current lifetime. */ + } else { + existing->timestamp = now_s; + existing->lifetime = NM_NDISC_PREFIX_LFT_MIN; + } } - changed = item->timestamp + item->lifetime != new->timestamp + new->lifetime || - item->timestamp + item->preferred != new->timestamp + new->preferred; - *item = *new; - return changed; + if (new->preferred == NM_NDISC_INFINITY) { + nm_assert (existing->lifetime == NM_NDISC_INFINITY); + existing->preferred = new->preferred; + } else { + existing->preferred = NM_CLAMP (((gint64) new->timestamp) + ((gint64) new->preferred) - ((gint64) existing->timestamp), + 0, G_MAXUINT32 - 1); + if (existing->lifetime != NM_NDISC_INFINITY) + existing->preferred = MIN (existing->preferred, existing->lifetime); + } + + return old_expiry_lifetime != get_expiry (existing) + || old_expiry_preferred != get_expiry_preferred (existing); } + + if (new->lifetime == 0) { + g_array_remove_index (rdata->addresses, i); + return TRUE; + } + + if ( get_expiry (existing) == get_expiry (new) + && get_expiry_preferred (existing) == get_expiry_preferred (new)) + return FALSE; + + existing->timestamp = new->timestamp; + existing->lifetime = new->lifetime; + existing->preferred = new->preferred; + return TRUE; } /* we create at most max_addresses autoconf addresses. This is different from @@ -380,18 +524,27 @@ nm_ndisc_add_address (NMNDisc *ndisc, const NMNDiscAddress *new) && rdata->addresses->len >= priv->max_addresses) return FALSE; - if (new->lifetime) - g_array_append_val (rdata->addresses, *new); - return !!new->lifetime; + if (new->lifetime == 0) + return FALSE; + + if (from_ra) { + new2 = *new; + new2.dad_counter = 0; + if (!complete_address (ndisc, &new2)) + return FALSE; + new = &new2; + } + + g_array_append_val (rdata->addresses, *new); + return TRUE; } gboolean -nm_ndisc_complete_and_add_address (NMNDisc *ndisc, NMNDiscAddress *new) +nm_ndisc_complete_and_add_address (NMNDisc *ndisc, + const NMNDiscAddress *new, + gint32 now_s) { - if (!complete_address (ndisc, new)) - return FALSE; - - return nm_ndisc_add_address (ndisc, new); + return nm_ndisc_add_address (ndisc, new, now_s, TRUE); } gboolean @@ -419,7 +572,8 @@ nm_ndisc_add_route (NMNDisc *ndisc, const NMNDiscRoute *new) for (i = 0; i < rdata->routes->len; ) { NMNDiscRoute *item = &g_array_index (rdata->routes, NMNDiscRoute, i); - if (IN6_ARE_ADDR_EQUAL (&item->network, &new->network) && item->plen == new->plen) { + if ( IN6_ARE_ADDR_EQUAL (&item->network, &new->network) + && item->plen == new->plen) { if (new->lifetime == 0) { g_array_remove_index (rdata->routes, i); return TRUE; @@ -430,8 +584,12 @@ nm_ndisc_add_route (NMNDisc *ndisc, const NMNDiscRoute *new) continue; } - memcpy (item, new, sizeof (*new)); - return FALSE; + if ( get_expiry (item) == get_expiry (new) + && IN6_ARE_ADDR_EQUAL (&item->gateway, &new->gateway)) + return FALSE; + + *item = *new; + return TRUE; } /* Put before less preferable routes. */ @@ -470,11 +628,12 @@ nm_ndisc_add_dns_server (NMNDisc *ndisc, const NMNDiscDNSServer *new) g_array_remove_index (rdata->dns_servers, i); return TRUE; } - if (item->timestamp != new->timestamp || item->lifetime != new->lifetime) { - *item = *new; - return TRUE; - } - return FALSE; + + if (get_expiry (item) == get_expiry (new)) + return FALSE; + + *item = *new; + return TRUE; } } @@ -499,20 +658,17 @@ nm_ndisc_add_dns_domain (NMNDisc *ndisc, const NMNDiscDNSDomain *new) item = &g_array_index (rdata->dns_domains, NMNDiscDNSDomain, i); if (!g_strcmp0 (item->domain, new->domain)) { - gboolean changed; - if (new->lifetime == 0) { g_array_remove_index (rdata->dns_domains, i); return TRUE; } - changed = (item->timestamp != new->timestamp || - item->lifetime != new->lifetime); - if (changed) { - item->timestamp = new->timestamp; - item->lifetime = new->lifetime; - } - return changed; + if (get_expiry (item) == get_expiry (new)) + return FALSE; + + item->timestamp = new->timestamp; + item->lifetime = new->lifetime; + return TRUE; } } @@ -686,7 +842,7 @@ nm_ndisc_set_config (NMNDisc *ndisc, guint i; for (i = 0; i < addresses->len; i++) { - if (nm_ndisc_add_address (ndisc, &g_array_index (addresses, NMNDiscAddress, i))) + if (nm_ndisc_add_address (ndisc, &g_array_index (addresses, NMNDiscAddress, i), 0, FALSE)) changed = TRUE; } @@ -860,57 +1016,6 @@ dhcp_level_to_string (NMNDiscDHCPLevel dhcp_level) } } -static gint32 -get_expiry_time (guint32 timestamp, guint32 lifetime) -{ - gint64 t; - - /* timestamp is supposed to come from nm_utils_get_monotonic_timestamp_s(). - * It is expected to be within a certain range. */ - nm_assert (timestamp > 0); - nm_assert (timestamp <= G_MAXINT32); - - if (lifetime == NM_NDISC_INFINITY) - return G_MAXINT32; - - t = (gint64) timestamp + (gint64) lifetime; - return CLAMP (t, 0, G_MAXINT32 - 1); -} - -#define get_expiry(item) \ - ({ \ - typeof (item) _item = (item); \ - nm_assert (_item); \ - get_expiry_time ((_item->timestamp), (_item->lifetime)); \ - }) - -#define get_expiry_half(item) \ - ({ \ - typeof (item) _item = (item); \ - nm_assert (_item); \ - get_expiry_time ((_item->timestamp),\ - (_item->lifetime) == NM_NDISC_INFINITY \ - ? NM_NDISC_INFINITY \ - : (_item->lifetime) / 2); \ - }) - -static const char * -_get_exp (char *buf, gsize buf_size, gint64 now_ns, gint32 expiry_time) -{ - int l; - - if (expiry_time == G_MAXINT32) - return "permanent"; - l = g_snprintf (buf, buf_size, - "%.4f", - ((double) ((expiry_time * NM_UTILS_NS_PER_SECOND) - now_ns)) / ((double) NM_UTILS_NS_PER_SECOND)); - nm_assert (l < buf_size); - return buf; -} - -#define get_exp(buf, now_ns, item) \ - _get_exp ((buf), G_N_ELEMENTS (buf), (now_ns), (get_expiry (item))) - static void _config_changed_log (NMNDisc *ndisc, NMNDiscConfigMap changed) { @@ -984,17 +1089,12 @@ clean_gateways (NMNDisc *ndisc, gint32 now, NMNDiscConfigMap *changed, gint32 *n for (i = 0; i < rdata->gateways->len; ) { NMNDiscGateway *item = &g_array_index (rdata->gateways, NMNDiscGateway, i); - if (item->lifetime != NM_NDISC_INFINITY) { - gint32 expiry = get_expiry (item); - - if (now >= expiry) { - g_array_remove_index (rdata->gateways, i); - *changed |= NM_NDISC_CONFIG_GATEWAYS; - continue; - } - if (*nextevent > expiry) - *nextevent = expiry; + if (!expiry_next (now, get_expiry (item), nextevent)) { + g_array_remove_index (rdata->gateways, i); + *changed |= NM_NDISC_CONFIG_GATEWAYS; + continue; } + i++; } @@ -1012,17 +1112,12 @@ clean_addresses (NMNDisc *ndisc, gint32 now, NMNDiscConfigMap *changed, gint32 * for (i = 0; i < rdata->addresses->len; ) { const NMNDiscAddress *item = &g_array_index (rdata->addresses, NMNDiscAddress, i); - if (item->lifetime != NM_NDISC_INFINITY) { - gint32 expiry = get_expiry (item); - - if (now >= expiry) { - g_array_remove_index (rdata->addresses, i); - *changed |= NM_NDISC_CONFIG_ADDRESSES; - continue; - } - if (*nextevent > expiry) - *nextevent = expiry; + if (!expiry_next (now, get_expiry (item), nextevent)) { + g_array_remove_index (rdata->addresses, i); + *changed |= NM_NDISC_CONFIG_ADDRESSES; + continue; } + i++; } } @@ -1038,17 +1133,12 @@ clean_routes (NMNDisc *ndisc, gint32 now, NMNDiscConfigMap *changed, gint32 *nex for (i = 0; i < rdata->routes->len; ) { NMNDiscRoute *item = &g_array_index (rdata->routes, NMNDiscRoute, i); - if (item->lifetime != NM_NDISC_INFINITY) { - gint32 expiry = get_expiry (item); - - if (now >= expiry) { - g_array_remove_index (rdata->routes, i); - *changed |= NM_NDISC_CONFIG_ROUTES; - continue; - } - if (*nextevent > expiry) - *nextevent = expiry; + if (!expiry_next (now, get_expiry (item), nextevent)) { + g_array_remove_index (rdata->routes, i); + *changed |= NM_NDISC_CONFIG_ROUTES; + continue; } + i++; } } @@ -1063,18 +1153,16 @@ clean_dns_servers (NMNDisc *ndisc, gint32 now, NMNDiscConfigMap *changed, gint32 for (i = 0; i < rdata->dns_servers->len; ) { NMNDiscDNSServer *item = &g_array_index (rdata->dns_servers, NMNDiscDNSServer, i); + gint64 refresh; - if (item->lifetime != NM_NDISC_INFINITY) { - gint32 expiry = get_expiry (item); - gint32 refresh; - - if (now >= expiry) { + refresh = get_expiry_half (item); + if (refresh != _EXPIRY_INFINITY) { + if (!expiry_next (now, get_expiry (item), NULL)) { g_array_remove_index (rdata->dns_servers, i); *changed |= NM_NDISC_CONFIG_DNS_SERVERS; continue; } - refresh = get_expiry_half (item); if (now >= refresh) solicit_routers (ndisc); else if (*nextevent > refresh) @@ -1094,18 +1182,16 @@ clean_dns_domains (NMNDisc *ndisc, gint32 now, NMNDiscConfigMap *changed, gint32 for (i = 0; i < rdata->dns_domains->len; ) { NMNDiscDNSDomain *item = &g_array_index (rdata->dns_domains, NMNDiscDNSDomain, i); + gint64 refresh; - if (item->lifetime != NM_NDISC_INFINITY) { - gint32 expiry = get_expiry (item); - gint32 refresh; - - if (now >= expiry) { + refresh = get_expiry_half (item); + if (refresh != _EXPIRY_INFINITY) { + if (!expiry_next (now, get_expiry (item), NULL)) { g_array_remove_index (rdata->dns_domains, i); *changed |= NM_NDISC_CONFIG_DNS_DOMAINS; continue; } - refresh = get_expiry_half (item); if (now >= refresh) solicit_routers (ndisc); else if (*nextevent > refresh) @@ -1132,9 +1218,6 @@ check_timestamps (NMNDisc *ndisc, gint32 now, NMNDiscConfigMap changed) clean_dns_servers (ndisc, now, &changed, &nextevent); clean_dns_domains (ndisc, now, &changed, &nextevent); - if (changed) - nm_ndisc_emit_config_change (ndisc, changed); - if (nextevent != G_MAXINT32) { if (nextevent <= now) g_return_if_reached (); @@ -1142,6 +1225,9 @@ check_timestamps (NMNDisc *ndisc, gint32 now, NMNDiscConfigMap changed) (int) (nextevent - now)); priv->timeout_id = g_timeout_add_seconds (nextevent - now, timeout_cb, ndisc); } + + if (changed) + nm_ndisc_emit_config_change (ndisc, changed); } static gboolean @@ -1192,7 +1278,7 @@ set_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PLATFORM: /* construct-only */ - priv->platform = g_value_get_object (value) ? : NM_PLATFORM_GET; + priv->platform = g_value_get_object (value) ?: NM_PLATFORM_GET; if (!priv->platform) g_return_if_reached (); diff --git a/src/ndisc/nm-ndisc.h b/src/ndisc/nm-ndisc.h index fdc5615f..73eef368 100644 --- a/src/ndisc/nm-ndisc.h +++ b/src/ndisc/nm-ndisc.h @@ -58,6 +58,9 @@ typedef enum { NM_NDISC_DHCP_LEVEL_MANAGED } NMNDiscDHCPLevel; +/* we rely on the fact that NM_NDISC_INFINITY is the largest possible + * time duration (G_MAXUINT32) and that the range of finite values + * goes from 0 to G_MAXUINT32-1. */ #define NM_NDISC_INFINITY G_MAXUINT32 struct _NMNDiscGateway { diff --git a/src/ndisc/tests/test-ndisc-fake.c b/src/ndisc/tests/test-ndisc-fake.c index e99d2fc5..268f3b49 100644 --- a/src/ndisc/tests/test-ndisc-fake.c +++ b/src/ndisc/tests/test-ndisc-fake.c @@ -233,8 +233,9 @@ test_everything_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed g_assert_cmpint (rdata->gateways_n, ==, 1); match_gateway (rdata, 0, "fe80::2", data->timestamp1, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM); - g_assert_cmpint (rdata->addresses_n, ==, 1); - match_address (rdata, 0, "2001:db8:a:b::1", data->timestamp1, 10, 10); + g_assert_cmpint (rdata->addresses_n, ==, 2); + match_address (rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 0); + match_address (rdata, 1, "2001:db8:a:b::1", data->timestamp1, 10, 10); g_assert_cmpint (rdata->routes_n, ==, 1); match_route (rdata, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1, 10, 10); g_assert_cmpint (rdata->dns_servers_n, ==, 1); @@ -384,7 +385,7 @@ test_preference_changed_cb (NMNDisc *ndisc, const NMNDiscData *rdata, guint chan match_gateway (rdata, 0, "fe80::1", data->timestamp1 + 2, 10, NM_ICMPV6_ROUTER_PREF_HIGH); match_gateway (rdata, 1, "fe80::2", data->timestamp1 + 1, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM); g_assert_cmpint (rdata->addresses_n, ==, 2); - match_address (rdata, 0, "2001:db8:a:a::1", data->timestamp1 + 2, 10, 10); + match_address (rdata, 0, "2001:db8:a:a::1", data->timestamp1 + 3, 9, 9); match_address (rdata, 1, "2001:db8:a:b::1", data->timestamp1 + 1, 10, 10); g_assert_cmpint (rdata->routes_n, ==, 2); match_route (rdata, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1 + 2, 10, 15); diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index aa83d6d5..a2f9ae4a 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -174,7 +174,7 @@ NM_UTILS_FLAGS2STR_DEFINE_STATIC (_state_flags_to_string, NMActivationStateFlags /*****************************************************************************/ static void -_settings_connection_updated (NMSettingsConnection *connection, +_settings_connection_updated (NMSettingsConnection *sett_conn, gboolean by_user, gpointer user_data) { @@ -196,24 +196,24 @@ _settings_connection_updated (NMSettingsConnection *connection, } static void -_set_settings_connection (NMActiveConnection *self, NMSettingsConnection *connection) +_set_settings_connection (NMActiveConnection *self, NMSettingsConnection *sett_conn) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - if (priv->settings_connection.obj == connection) + if (priv->settings_connection.obj == sett_conn) return; if (priv->settings_connection.obj) { g_signal_handlers_disconnect_by_func (priv->settings_connection.obj, _settings_connection_updated, self); g_signal_handlers_disconnect_by_func (priv->settings_connection.obj, _settings_connection_flags_changed, self); } - if (connection) { - g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, (GCallback) _settings_connection_updated, self); + if (sett_conn) { + g_signal_connect (sett_conn, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, (GCallback) _settings_connection_updated, self); if (nm_active_connection_get_activation_type (self) == NM_ACTIVATION_TYPE_EXTERNAL) - g_signal_connect (connection, NM_SETTINGS_CONNECTION_FLAGS_CHANGED, (GCallback) _settings_connection_flags_changed, self); + g_signal_connect (sett_conn, NM_SETTINGS_CONNECTION_FLAGS_CHANGED, (GCallback) _settings_connection_flags_changed, self); } - nm_dbus_track_obj_path_set (&priv->settings_connection, connection, TRUE); + nm_dbus_track_obj_path_set (&priv->settings_connection, sett_conn, TRUE); } NMActiveConnectionState @@ -367,13 +367,13 @@ nm_active_connection_set_state_flags_full (NMActiveConnection *self, const char * nm_active_connection_get_settings_connection_id (NMActiveConnection *self) { - NMSettingsConnection *con; + NMSettingsConnection *sett_conn; g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); - con = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection.obj; - return con - ? nm_connection_get_id (NM_CONNECTION (con)) + sett_conn = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection.obj; + return sett_conn + ? nm_settings_connection_get_id (sett_conn) : NULL; } @@ -388,31 +388,31 @@ _nm_active_connection_get_settings_connection (NMActiveConnection *self) NMSettingsConnection * nm_active_connection_get_settings_connection (NMActiveConnection *self) { - NMSettingsConnection *con; + NMSettingsConnection *sett_conn; - con = _nm_active_connection_get_settings_connection (self); + sett_conn = _nm_active_connection_get_settings_connection (self); /* Only call this function on an active-connection that is already * fully set-up (i.e. that has a settings-connection). Other uses * indicate a bug. */ - g_return_val_if_fail (con, NULL); - return con; + g_return_val_if_fail (sett_conn, NULL); + return sett_conn; } NMConnection * nm_active_connection_get_applied_connection (NMActiveConnection *self) { - NMConnection *con; + NMConnection *connection; g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); - con = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->applied_connection; + connection = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->applied_connection; /* Only call this function on an active-connection that is already * fully set-up (i.e. that has a settings-connection). Other uses * indicate a bug. */ - g_return_val_if_fail (con, NULL); - return con; + g_return_val_if_fail (connection, NULL); + return connection; } static void @@ -447,7 +447,7 @@ _set_applied_connection_take (NMActiveConnection *self, void nm_active_connection_set_settings_connection (NMActiveConnection *self, - NMSettingsConnection *connection) + NMSettingsConnection *sett_conn) { NMActiveConnectionPrivate *priv; @@ -455,7 +455,7 @@ nm_active_connection_set_settings_connection (NMActiveConnection *self, priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (sett_conn)); g_return_if_fail (!priv->settings_connection.obj); g_return_if_fail (!priv->applied_connection); @@ -468,10 +468,10 @@ nm_active_connection_set_settings_connection (NMActiveConnection *self, * For example, we'd have to cancel all pending seret requests. */ g_return_if_fail (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (self))); - _set_settings_connection (self, connection); + _set_settings_connection (self, sett_conn); _set_applied_connection_take (self, - nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection.obj))); + nm_simple_connection_new_clone (nm_settings_connection_get_connection (priv->settings_connection.obj))); } gboolean @@ -503,8 +503,10 @@ nm_active_connection_clear_secrets (NMActiveConnection *self) if (nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection.obj, priv->applied_connection, - NM_SETTING_COMPARE_FLAG_NONE)) - nm_connection_clear_secrets ((NMConnection *) priv->settings_connection.obj); + NM_SETTING_COMPARE_FLAG_NONE)) { + /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */ + nm_connection_clear_secrets (nm_settings_connection_get_connection (priv->settings_connection.obj)); + } nm_connection_clear_secrets (priv->applied_connection); } @@ -921,7 +923,7 @@ _settings_connection_flags_changed (NMSettingsConnection *settings_connection, _set_activation_type_managed (self); if (!nm_device_reapply (nm_active_connection_get_device (self), - NM_CONNECTION (nm_active_connection_get_settings_connection (self)), + nm_settings_connection_get_connection ((nm_active_connection_get_settings_connection (self))), &error)) { _LOGW ("failed to reapply new device settings on previously externally managed device: %s", error->message); @@ -1112,7 +1114,7 @@ nm_active_connection_authorize (NMActiveConnection *self, { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); const char *wifi_permission = NULL; - NMConnection *con; + NMConnection *connection; g_return_if_fail (result_func); g_return_if_fail (!priv->auth.call_id_network_control); @@ -1122,11 +1124,11 @@ nm_active_connection_authorize (NMActiveConnection *self, g_return_if_fail (NM_IS_CONNECTION (initial_connection)); g_return_if_fail (!priv->settings_connection.obj); g_return_if_fail (!priv->applied_connection); - con = initial_connection; + connection = initial_connection; } else { g_return_if_fail (NM_IS_SETTINGS_CONNECTION (priv->settings_connection.obj)); g_return_if_fail (NM_IS_CONNECTION (priv->applied_connection)); - con = priv->applied_connection; + connection = priv->applied_connection; } priv->auth.call_id_network_control = nm_auth_manager_check_authorization (nm_auth_manager_get (), @@ -1137,7 +1139,7 @@ nm_active_connection_authorize (NMActiveConnection *self, self); /* Shared wifi connections require special permissions too */ - wifi_permission = nm_utils_get_shared_wifi_permission (con); + wifi_permission = nm_utils_get_shared_wifi_permission (connection); if (wifi_permission) { priv->auth.call_id_wifi_shared_permission = nm_auth_manager_check_authorization (nm_auth_manager_get (), priv->subject, @@ -1227,13 +1229,13 @@ get_property (GObject *object, guint prop_id, g_value_set_string (value, nm_dbus_track_obj_path_get (&priv->settings_connection)); break; case PROP_ID: - g_value_set_string (value, nm_connection_get_id (NM_CONNECTION (priv->settings_connection.obj))); + g_value_set_string (value, nm_settings_connection_get_id (priv->settings_connection.obj)); break; case PROP_UUID: - g_value_set_string (value, nm_connection_get_uuid (NM_CONNECTION (priv->settings_connection.obj))); + g_value_set_string (value, nm_settings_connection_get_uuid (priv->settings_connection.obj)); break; case PROP_TYPE: - g_value_set_string (value, nm_connection_get_connection_type (NM_CONNECTION (priv->settings_connection.obj))); + g_value_set_string (value, nm_settings_connection_get_connection_type (priv->settings_connection.obj)); break; case PROP_SPECIFIC_OBJECT: @@ -1304,16 +1306,16 @@ set_property (GObject *object, guint prop_id, NMActiveConnection *self = (NMActiveConnection *) object; NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); const char *tmp; - NMSettingsConnection *con; + NMSettingsConnection *sett_conn; NMConnection *acon; int i; switch (prop_id) { case PROP_INT_SETTINGS_CONNECTION: /* construct-only */ - con = g_value_get_object (value); - if (con) - _set_settings_connection (self, con); + sett_conn = g_value_get_object (value); + if (sett_conn) + _set_settings_connection (self, sett_conn); break; case PROP_INT_APPLIED_CONNECTION: /* construct-only */ @@ -1410,7 +1412,7 @@ constructed (GObject *object) if ( !priv->applied_connection && priv->settings_connection.obj) - priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection.obj)); + priv->applied_connection = nm_simple_connection_new_clone (nm_settings_connection_get_connection (priv->settings_connection.obj)); _LOGD ("constructed (%s, version-id %llu, type %s)", G_OBJECT_TYPE_NAME (self), diff --git a/src/nm-auth-subject.c b/src/nm-auth-subject.c index 117a3815..9ed65e2d 100644 --- a/src/nm-auth-subject.c +++ b/src/nm-auth-subject.c @@ -200,7 +200,7 @@ _new_unix_process (GDBusMethodInvocation *context, return NULL; g_return_val_if_fail (dbus_sender && *dbus_sender, NULL); - /* polkit glib library stores uid and pid as gint. There might be some + /* polkit glib library stores uid and pid as int. There might be some * pitfalls if the id ever happens to be larger then that. Just assert against * it here. */ g_return_val_if_fail (uid <= MIN (G_MAXINT, G_MAXINT32), NULL); @@ -356,7 +356,7 @@ constructed (GObject *object) return; case NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS: /* Ensure pid and uid to be representable as int32. - * DBUS treats them as uint32, polkit library as gint. */ + * DBUS treats them as uint32, polkit library as int. */ if (priv->unix_process.pid > MIN (G_MAXINT, G_MAXINT32)) break; if (priv->unix_process.uid > MIN (G_MAXINT, G_MAXINT32)) { diff --git a/src/nm-checkpoint-manager.c b/src/nm-checkpoint-manager.c index 7e8c8aea..0c2af831 100644 --- a/src/nm-checkpoint-manager.c +++ b/src/nm-checkpoint-manager.c @@ -265,8 +265,8 @@ nm_checkpoint_manager_lookup_by_path (NMCheckpointManager *self, const char *pat g_return_val_if_fail (self, NULL); - checkpoint = (NMCheckpoint *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (GET_MANAGER (self))), - path); + checkpoint = nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (GET_MANAGER (self))), + path); if ( !checkpoint || !NM_IS_CHECKPOINT (checkpoint)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_INVALID_ARGUMENTS, diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c index a17f7eda..b0cf1f51 100644 --- a/src/nm-checkpoint.c +++ b/src/nm-checkpoint.c @@ -159,7 +159,7 @@ find_settings_connection (NMCheckpoint *self, { NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); NMActiveConnection *active; - NMSettingsConnection *connection; + NMSettingsConnection *sett_conn; const char *uuid, *ac_uuid; const CList *tmp_clist; @@ -167,14 +167,14 @@ find_settings_connection (NMCheckpoint *self, *need_update = FALSE; uuid = nm_connection_get_uuid (dev_checkpoint->settings_connection); - connection = nm_settings_get_connection_by_uuid (nm_settings_get (), uuid); + sett_conn = nm_settings_get_connection_by_uuid (nm_settings_get (), uuid); - if (!connection) + if (!sett_conn) return NULL; /* Now check if the connection changed, ... */ if (!nm_connection_compare (dev_checkpoint->settings_connection, - NM_CONNECTION (connection), + nm_settings_connection_get_connection (sett_conn), NM_SETTING_COMPARE_FLAG_EXACT)) { _LOGT ("rollback: settings connection %s changed", uuid); *need_update = TRUE; @@ -193,7 +193,7 @@ find_settings_connection (NMCheckpoint *self, if (!active) { _LOGT ("rollback: connection %s is not active", uuid); *need_activation = TRUE; - return connection; + return sett_conn; } /* ... or if the connection was reactivated/reapplied */ @@ -202,7 +202,7 @@ find_settings_connection (NMCheckpoint *self, *need_activation = TRUE; } - return connection; + return sett_conn; } GVariant * @@ -337,8 +337,8 @@ activate: dev_checkpoint->activation_reason, &local_error)) { _LOGW ("rollback: reactivation of connection %s/%s failed: %s", - nm_connection_get_id ((NMConnection *) connection), - nm_connection_get_uuid ((NMConnection *) connection), + nm_settings_connection_get_id (connection), + nm_settings_connection_get_uuid (connection), local_error->message); g_clear_error (&local_error); result = NM_ROLLBACK_RESULT_ERR_FAILED; @@ -436,12 +436,9 @@ device_checkpoint_create (NMDevice *device) applied_connection = nm_act_request_get_applied_connection (act_request); dev_checkpoint->applied_connection = nm_simple_connection_new_clone (applied_connection); - dev_checkpoint->settings_connection = - nm_simple_connection_new_clone (NM_CONNECTION (settings_connection)); - dev_checkpoint->ac_version_id = - nm_active_connection_version_id_get (NM_ACTIVE_CONNECTION (act_request)); - dev_checkpoint->activation_reason = - nm_active_connection_get_activation_reason (NM_ACTIVE_CONNECTION (act_request)); + dev_checkpoint->settings_connection = nm_simple_connection_new_clone (nm_settings_connection_get_connection (settings_connection)); + dev_checkpoint->ac_version_id = nm_active_connection_version_id_get (NM_ACTIVE_CONNECTION (act_request)); + dev_checkpoint->activation_reason = nm_active_connection_get_activation_reason (NM_ACTIVE_CONNECTION (act_request)); } return dev_checkpoint; diff --git a/src/nm-config-data.c b/src/nm-config-data.c index 813ef9c8..8d84e74a 100644 --- a/src/nm-config-data.c +++ b/src/nm-config-data.c @@ -183,11 +183,11 @@ nm_config_data_has_value (const NMConfigData *self, const char *group, const cha return !!value; } -gint -nm_config_data_get_value_boolean (const NMConfigData *self, const char *group, const char *key, gint default_value) +int +nm_config_data_get_value_boolean (const NMConfigData *self, const char *group, const char *key, int default_value) { char *str; - gint value = default_value; + int value = default_value; g_return_val_if_fail (NM_IS_CONFIG_DATA (self), default_value); g_return_val_if_fail (group && *group, default_value); @@ -655,12 +655,12 @@ nm_config_data_log (const NMConfigData *self, const char *group = default_values[g].group; gssize idx; - idx = _nm_utils_array_find_binary_search ((gconstpointer *) groups_full->pdata, - sizeof (char *), - groups_full->len, - &group, - (GCompareDataFunc) _nm_config_data_log_sort, - NULL); + idx = nm_utils_array_find_binary_search ((gconstpointer *) groups_full->pdata, + sizeof (char *), + groups_full->len, + &group, + (GCompareDataFunc) _nm_config_data_log_sort, + NULL); if (idx < 0) g_ptr_array_insert (groups_full, (~idx), (gpointer) group); } @@ -1335,8 +1335,8 @@ gboolean nm_config_data_get_device_config_boolean (const NMConfigData *self, const char *property, NMDevice *device, - gint val_no_match, - gint val_invalid) + int val_no_match, + int val_invalid) { gs_free char *value = NULL; gboolean has_match; @@ -1371,6 +1371,20 @@ nm_config_data_get_connection_default (const NMConfigData *self, return value; } +gint64 +nm_config_data_get_connection_default_int64 (const NMConfigData *self, + const char *property, + NMDevice *device, + gint64 min, + gint64 max, + gint64 fallback) +{ + gs_free char *value = NULL; + + value = nm_config_data_get_connection_default (self, property, device); + return _nm_utils_ascii_str_to_int64 (value, 10, min, max, fallback); +} + static void _get_connection_info_init (MatchSectionInfo *connection_info, GKeyFile *keyfile, char *group) { diff --git a/src/nm-config-data.h b/src/nm-config-data.h index 650fbe14..b52ddcc4 100644 --- a/src/nm-config-data.h +++ b/src/nm-config-data.h @@ -154,7 +154,7 @@ const char *nm_config_data_get_config_description (const NMConfigData *config_da gboolean nm_config_data_has_group (const NMConfigData *self, const char *group); gboolean nm_config_data_has_value (const NMConfigData *self, const char *group, const char *key, NMConfigGetValueFlags flags); char *nm_config_data_get_value (const NMConfigData *config_data, const char *group, const char *key, NMConfigGetValueFlags flags); -gint nm_config_data_get_value_boolean (const NMConfigData *self, const char *group, const char *key, gint default_value); +int nm_config_data_get_value_boolean (const NMConfigData *self, const char *group, const char *key, int default_value); gint64 nm_config_data_get_value_int64 (const NMConfigData *self, const char *group, const char *key, guint base, gint64 min, gint64 max, gint64 fallback); char **nm_config_data_get_plugins (const NMConfigData *config_data, gboolean allow_default); @@ -181,6 +181,13 @@ char *nm_config_data_get_connection_default (const NMConfigData *self, const char *property, NMDevice *device); +gint64 nm_config_data_get_connection_default_int64 (const NMConfigData *self, + const char *property, + NMDevice *device, + gint64 min, + gint64 max, + gint64 fallback); + char *nm_config_data_get_device_config (const NMConfigData *self, const char *property, NMDevice *device, @@ -195,8 +202,8 @@ char *nm_config_data_get_device_config_by_pllink (const NMConfigData *self, gboolean nm_config_data_get_device_config_boolean (const NMConfigData *self, const char *property, NMDevice *device, - gint val_no_match, - gint val_invalid); + int val_no_match, + int val_invalid); char **nm_config_data_get_groups (const NMConfigData *self); char **nm_config_data_get_keys (const NMConfigData *self, const char *group); diff --git a/src/nm-config.c b/src/nm-config.c index d4682ed6..628eca4f 100644 --- a/src/nm-config.c +++ b/src/nm-config.c @@ -51,7 +51,8 @@ struct NMConfigCmdLineOptions { char *state_file; char *no_auto_default_file; char *plugins; - gboolean configure_and_quit; + NMConfigConfigureAndQuitType configure_and_quit; + gboolean is_debug; char *connectivity_uri; @@ -105,7 +106,7 @@ typedef struct { char *log_level; char *log_domains; - gboolean configure_and_quit; + NMConfigConfigureAndQuitType configure_and_quit; char **atomic_section_prefixes; @@ -167,18 +168,18 @@ static void _set_config_data (NMConfig *self, NMConfigData *new_data, NMConfigCh /*****************************************************************************/ -gint +int nm_config_parse_boolean (const char *str, - gint default_value) + int default_value) { return _nm_utils_ascii_str_to_bool (str, default_value); } -gint +int nm_config_keyfile_get_boolean (const GKeyFile *keyfile, const char *section, const char *key, - gint default_value) + int default_value) { gs_free char *str = NULL; @@ -323,7 +324,7 @@ nm_config_get_log_domains (NMConfig *config) return NM_CONFIG_GET_PRIVATE (config)->log_domains; } -gboolean +NMConfigConfigureAndQuitType nm_config_get_configure_and_quit (NMConfig *config) { return NM_CONFIG_GET_PRIVATE (config)->configure_and_quit; @@ -392,9 +393,16 @@ no_auto_default_to_file (const char *no_auto_default_file, const char *const*no_ gboolean nm_config_get_no_auto_default_for_device (NMConfig *self, NMDevice *device) { + NMConfigPrivate *priv; + g_return_val_if_fail (NM_IS_CONFIG (self), FALSE); - return nm_config_data_get_no_auto_default_for_device (NM_CONFIG_GET_PRIVATE (self)->config_data, device); + priv = NM_CONFIG_GET_PRIVATE (self); + + if (priv->configure_and_quit == NM_CONFIG_CONFIGURE_AND_QUIT_INITRD) + return TRUE; + + return nm_config_data_get_no_auto_default_for_device (priv->config_data, device); } void @@ -457,7 +465,7 @@ _nm_config_cmd_line_options_clear (NMConfigCmdLineOptions *cli) g_clear_pointer (&cli->intern_config_file, g_free); g_clear_pointer (&cli->state_file, g_free); g_clear_pointer (&cli->plugins, g_free); - cli->configure_and_quit = FALSE; + cli->configure_and_quit = NM_CONFIG_CONFIGURE_AND_QUIT_DISABLED; cli->is_debug = FALSE; g_clear_pointer (&cli->connectivity_uri, g_free); g_clear_pointer (&cli->connectivity_response, g_free); @@ -509,34 +517,72 @@ nm_config_cmd_line_options_free (NMConfigCmdLineOptions *cli) g_free (cli); } +static NMConfigConfigureAndQuitType +string_to_configure_and_quit (const char *value, GError **error) +{ + NMConfigConfigureAndQuitType ret; + + if (value == NULL) + return NM_CONFIG_CONFIGURE_AND_QUIT_DISABLED; + + if (strcmp (value, "initrd") == 0) + return NM_CONFIG_CONFIGURE_AND_QUIT_INITRD; + + ret = nm_config_parse_boolean (value, NM_CONFIG_CONFIGURE_AND_QUIT_INVALID); + if (ret == NM_CONFIG_CONFIGURE_AND_QUIT_INVALID) + g_set_error (error, 1, 0, N_("'%s' is not valid"), value); + + return ret; +} + +static gboolean +parse_configure_and_quit (const char *option_name, const char *value, gpointer user_data, GError **error) +{ + NMConfigCmdLineOptions *cli = user_data; + + if (value == NULL) + cli->configure_and_quit = NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED; + else + cli->configure_and_quit = string_to_configure_and_quit (value, error); + + if (cli->configure_and_quit == NM_CONFIG_CONFIGURE_AND_QUIT_INVALID) { + g_prefix_error (error, N_("Bad '%s' option: "), option_name); + return FALSE; + } + + return TRUE; +} + void nm_config_cmd_line_options_add_to_entries (NMConfigCmdLineOptions *cli, GOptionContext *opt_ctx) { + GOptionGroup *group; + GOptionEntry config_options[] = { + { "config", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_main_file, N_("Config file location"), DEFAULT_CONFIG_MAIN_FILE }, + { "config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_dir, N_("Config directory location"), DEFAULT_CONFIG_DIR }, + { "system-config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->system_config_dir, N_("System config directory location"), DEFAULT_SYSTEM_CONFIG_DIR }, + { "intern-config", 0, 0, G_OPTION_ARG_FILENAME, &cli->intern_config_file, N_("Internal config file location"), DEFAULT_INTERN_CONFIG_FILE }, + { "state-file", 0, 0, G_OPTION_ARG_FILENAME, &cli->state_file, N_("State file location"), DEFAULT_STATE_FILE }, + { "no-auto-default", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME, &cli->no_auto_default_file, N_("State file for no-auto-default devices"), DEFAULT_NO_AUTO_DEFAULT_FILE }, + { "plugins", 0, 0, G_OPTION_ARG_STRING, &cli->plugins, N_("List of plugins separated by ','"), NM_CONFIG_DEFAULT_MAIN_PLUGINS }, + { "configure-and-quit", 0, G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, parse_configure_and_quit, N_("Quit after initial configuration"), NULL }, + { "debug", 'd', 0, G_OPTION_ARG_NONE, &cli->is_debug, N_("Don't become a daemon, and log to stderr"), NULL }, + + /* These three are hidden for now, and should eventually just go away. */ + { "connectivity-uri", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_uri, N_("An http(s) address for checking internet connectivity"), "http://example.com" }, + { "connectivity-interval", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &cli->connectivity_interval, N_("The interval between connectivity checks (in seconds)"), G_STRINGIFY (NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL) }, + { "connectivity-response", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_response, N_("The expected start of the response"), NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE }, + { 0 }, + }; + g_return_if_fail (opt_ctx); g_return_if_fail (cli); - { - GOptionEntry config_options[] = { - { "config", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_main_file, N_("Config file location"), DEFAULT_CONFIG_MAIN_FILE }, - { "config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_dir, N_("Config directory location"), DEFAULT_CONFIG_DIR }, - { "system-config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->system_config_dir, N_("System config directory location"), DEFAULT_SYSTEM_CONFIG_DIR }, - { "intern-config", 0, 0, G_OPTION_ARG_FILENAME, &cli->intern_config_file, N_("Internal config file location"), DEFAULT_INTERN_CONFIG_FILE }, - { "state-file", 0, 0, G_OPTION_ARG_FILENAME, &cli->state_file, N_("State file location"), DEFAULT_STATE_FILE }, - { "no-auto-default", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME, &cli->no_auto_default_file, N_("State file for no-auto-default devices"), DEFAULT_NO_AUTO_DEFAULT_FILE }, - { "plugins", 0, 0, G_OPTION_ARG_STRING, &cli->plugins, N_("List of plugins separated by ','"), NM_CONFIG_DEFAULT_MAIN_PLUGINS }, - { "configure-and-quit", 0, 0, G_OPTION_ARG_NONE, &cli->configure_and_quit, N_("Quit after initial configuration"), NULL }, - { "debug", 'd', 0, G_OPTION_ARG_NONE, &cli->is_debug, N_("Don't become a daemon, and log to stderr"), NULL }, - - /* These three are hidden for now, and should eventually just go away. */ - { "connectivity-uri", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_uri, N_("An http(s) address for checking internet connectivity"), "http://example.com" }, - { "connectivity-interval", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &cli->connectivity_interval, N_("The interval between connectivity checks (in seconds)"), G_STRINGIFY (NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL) }, - { "connectivity-response", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_response, N_("The expected start of the response"), NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE }, - { 0 }, - }; + group = g_option_group_new ("nm", N_("NetworkManager options" ), N_("Show NetworkManager options"), cli, NULL); - g_option_context_add_main_entries (opt_ctx, config_options, NULL); - } + g_option_group_add_entries (group, config_options); + g_option_context_add_group (opt_ctx, group); } /*****************************************************************************/ @@ -892,7 +938,7 @@ read_base_config (GKeyFile *keyfile, } if (!g_error_matches (my_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND)) { - _LOGW ("Old default config file invalid: %s\n", + _LOGW ("Old default config file invalid: %s", my_error->message); } g_clear_error (&my_error); @@ -904,7 +950,7 @@ read_base_config (GKeyFile *keyfile, } if (!g_error_matches (my_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND)) { - _LOGW ("Default config file invalid: %s\n", + _LOGW ("Default config file invalid: %s", my_error->message); g_propagate_error (error, my_error); return FALSE; @@ -915,7 +961,7 @@ read_base_config (GKeyFile *keyfile, * config file path. */ *out_config_main_file = g_strdup (DEFAULT_CONFIG_MAIN_FILE); - _LOGI ("No config file found or given; using %s\n", + _LOGI ("No config file found or given; using %s", DEFAULT_CONFIG_MAIN_FILE); return TRUE; } @@ -1046,19 +1092,36 @@ read_entire_config (const NMConfigCmdLineOptions *cli, /* Merge settings from command line. They overwrite everything read from * config files. */ - if (cli && cli->plugins) { - /* plugins is a string list. Set the value directly, so the user has to do proper escaping - * on the command line. */ - g_key_file_set_value (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "plugins", cli->plugins); - } - if (cli && cli->configure_and_quit) - g_key_file_set_boolean (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "configure-and-quit", TRUE); - if (cli && cli->connectivity_uri && cli->connectivity_uri[0]) - g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "uri", cli->connectivity_uri); - if (cli && cli->connectivity_interval >= 0) - g_key_file_set_integer (keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "interval", cli->connectivity_interval); - if (cli && cli->connectivity_response && cli->connectivity_response[0]) - g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "response", cli->connectivity_response); + + if (cli) { + if (cli->plugins) { + /* plugins is a string list. Set the value directly, so the user has to do proper escaping + * on the command line. */ + g_key_file_set_value (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "plugins", cli->plugins); + } + + switch (cli->configure_and_quit) { + case NM_CONFIG_CONFIGURE_AND_QUIT_INVALID: + g_assert_not_reached (); + break; + case NM_CONFIG_CONFIGURE_AND_QUIT_DISABLED: + /* do nothing */ + break; + case NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED: + g_key_file_set_boolean (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "configure-and-quit", TRUE); + break; + case NM_CONFIG_CONFIGURE_AND_QUIT_INITRD: + g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "configure-and-quit", "initrd"); + break; + } + + if (cli->connectivity_uri && cli->connectivity_uri[0]) + g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "uri", cli->connectivity_uri); + if (cli->connectivity_interval >= 0) + g_key_file_set_integer (keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "interval", cli->connectivity_interval); + if (cli->connectivity_response && cli->connectivity_response[0]) + g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "response", cli->connectivity_response); + } if (out_config_description) { GString *str; @@ -1690,7 +1753,7 @@ nm_config_set_values (NMConfig *self, GError *local = NULL; NMConfigData *new_data = NULL; gs_strfreev char **groups = NULL; - gint g; + int g; g_return_if_fail (NM_IS_CONFIG (self)); @@ -1837,6 +1900,9 @@ state_write (NMConfig *self) GString *str; GError *error = NULL; + if (priv->configure_and_quit != NM_CONFIG_CONFIGURE_AND_QUIT_DISABLED) + return; + filename = state_get_filename (&priv->cli); if (!filename) { @@ -1931,6 +1997,7 @@ _nm_config_state_set (NMConfig *self, #define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_NM_OWNED "nm-owned" #define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROUTE_METRIC_DEFAULT_ASPIRED "route-metric-default-aspired" #define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROUTE_METRIC_DEFAULT_EFFECTIVE "route-metric-default-effective" +#define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROOT_PATH "root-path" NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_device_state_managed_type_to_str, NMConfigDeviceStateManagedType, NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"), @@ -1948,7 +2015,7 @@ _config_device_state_data_new (int ifindex, GKeyFile *kf) gs_free char *perm_hw_addr_fake = NULL; gsize connection_uuid_len; gsize perm_hw_addr_fake_len; - gint nm_owned = -1; + int nm_owned = -1; char *p; guint32 route_metric_default_effective; guint32 route_metric_default_aspired; @@ -2126,9 +2193,10 @@ nm_config_device_state_write (int ifindex, NMConfigDeviceStateManagedType managed, const char *perm_hw_addr_fake, const char *connection_uuid, - gint nm_owned, + int nm_owned, guint32 route_metric_default_aspired, - guint32 route_metric_default_effective) + guint32 route_metric_default_effective, + const char *root_path) { char path[NM_STRLEN (NM_CONFIG_DEVICE_STATE_DIR) + 60]; GError *local = NULL; @@ -2182,19 +2250,26 @@ nm_config_device_state_write (int ifindex, route_metric_default_aspired); } } + if (root_path) { + g_key_file_set_string (kf, + DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE, + DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROOT_PATH, + root_path); + } if (!g_key_file_save_to_file (kf, path, &local)) { _LOGW ("device-state: write #%d (%s) failed: %s", ifindex, path, local->message); g_error_free (local); return FALSE; } - _LOGT ("device-state: write #%d (%s); managed=%s%s%s%s%s%s%s, route-metric-default=%"G_GUINT32_FORMAT"-%"G_GUINT32_FORMAT"", + _LOGT ("device-state: write #%d (%s); managed=%s%s%s%s%s%s%s, route-metric-default=%"G_GUINT32_FORMAT"-%"G_GUINT32_FORMAT"%s%s%s", ifindex, path, _device_state_managed_type_to_str (managed), NM_PRINT_FMT_QUOTED (connection_uuid, ", connection-uuid=", connection_uuid, "", ""), NM_PRINT_FMT_QUOTED (perm_hw_addr_fake, ", perm-hw-addr-fake=", perm_hw_addr_fake, "", ""), route_metric_default_aspired, - route_metric_default_effective); + route_metric_default_effective, + NM_PRINT_FMT_QUOTED (root_path, ", root-path=", root_path, "", "")); return TRUE; } @@ -2332,7 +2407,11 @@ nm_config_reload (NMConfig *self, NMConfigChangeFlags reload_flags) (const char *const*) priv->atomic_section_prefixes, NULL); } - new_data = nm_config_data_new (config_main_file, config_description, (const char *const*) no_auto_default, keyfile, keyfile_intern); + new_data = nm_config_data_new (config_main_file, + config_description, + (const char *const*) no_auto_default, + keyfile, + keyfile_intern); g_free (config_main_file); g_free (config_description); g_key_file_unref (keyfile); @@ -2482,6 +2561,7 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error) char *config_main_file = NULL; char *config_description = NULL; gs_strfreev char **no_auto_default = NULL; + gs_free char *configure_and_quit = NULL; gboolean intern_config_needs_rewrite; const char *s; @@ -2528,7 +2608,10 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error) priv->log_level = nm_strstrip (g_key_file_get_string (keyfile, NM_CONFIG_KEYFILE_GROUP_LOGGING, "level", NULL)); priv->log_domains = nm_strstrip (g_key_file_get_string (keyfile, NM_CONFIG_KEYFILE_GROUP_LOGGING, "domains", NULL)); - priv->configure_and_quit = nm_config_keyfile_get_boolean (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "configure-and-quit", FALSE); + configure_and_quit = nm_strstrip (g_key_file_get_string (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "configure-and-quit", NULL)); + priv->configure_and_quit = string_to_configure_and_quit (configure_and_quit, error); + if (priv->configure_and_quit == NM_CONFIG_CONFIGURE_AND_QUIT_INVALID) + return FALSE; no_auto_default = no_auto_default_from_file (priv->no_auto_default_file); @@ -2536,12 +2619,17 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error) keyfile, (const char *const*) priv->atomic_section_prefixes, &intern_config_needs_rewrite); - if (intern_config_needs_rewrite) { + if ( intern_config_needs_rewrite + && priv->configure_and_quit == NM_CONFIG_CONFIGURE_AND_QUIT_DISABLED) { intern_config_write (priv->intern_config_file, keyfile_intern, keyfile, (const char *const*) priv->atomic_section_prefixes, NULL); } - priv->config_data_orig = nm_config_data_new (config_main_file, config_description, (const char *const*) no_auto_default, keyfile, keyfile_intern); + priv->config_data_orig = nm_config_data_new (config_main_file, + config_description, + (const char *const*) no_auto_default, + keyfile, + keyfile_intern); priv->config_data = g_object_ref (priv->config_data_orig); diff --git a/src/nm-config.h b/src/nm-config.h index 5d027ce0..c65572ce 100644 --- a/src/nm-config.h +++ b/src/nm-config.h @@ -101,6 +101,13 @@ typedef enum { NM_CONFIG_STATE_PROPERTY_WWAN_ENABLED, } NMConfigRunStatePropertyType; +typedef enum { + NM_CONFIG_CONFIGURE_AND_QUIT_INVALID = -1, + NM_CONFIG_CONFIGURE_AND_QUIT_DISABLED = FALSE, + NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED = TRUE, + NM_CONFIG_CONFIGURE_AND_QUIT_INITRD, +} NMConfigConfigureAndQuitType; + typedef struct { bool net_enabled; bool wifi_enabled; @@ -127,7 +134,7 @@ NMConfigData *nm_config_get_data_orig (NMConfig *config); gboolean nm_config_get_monitor_connection_files (NMConfig *config); const char *nm_config_get_log_level (NMConfig *config); const char *nm_config_get_log_domains (NMConfig *config); -gboolean nm_config_get_configure_and_quit (NMConfig *config); +NMConfigConfigureAndQuitType nm_config_get_configure_and_quit (NMConfig *config); gboolean nm_config_get_is_debug (NMConfig *config); gboolean nm_config_get_first_start (NMConfig *config); @@ -159,13 +166,13 @@ void _nm_config_state_set (NMConfig *config, #define nm_config_state_set(config, allow_persist, force_persist, ...) \ _nm_config_state_set (config, allow_persist, force_persist, ##__VA_ARGS__, 0) -gint nm_config_parse_boolean (const char *str, gint default_value); +int nm_config_parse_boolean (const char *str, int default_value); GKeyFile *nm_config_create_keyfile (void); -gint nm_config_keyfile_get_boolean (const GKeyFile *keyfile, +int nm_config_keyfile_get_boolean (const GKeyFile *keyfile, const char *section, const char *key, - gint default_value); + int default_value); gint64 nm_config_keyfile_get_int64 (const GKeyFile *keyfile, const char *section, const char *key, @@ -234,9 +241,10 @@ gboolean nm_config_device_state_write (int ifindex, NMConfigDeviceStateManagedType managed, const char *perm_hw_addr_fake, const char *connection_uuid, - gint nm_owned, + int nm_owned, guint32 route_metric_default_aspired, - guint32 route_metric_default_effective); + guint32 route_metric_default_effective, + const char *root_path); void nm_config_device_state_prune_unseen (GHashTable *seen_ifindexes); diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c index db26218b..8a6e955a 100644 --- a/src/nm-connectivity.c +++ b/src/nm-connectivity.c @@ -277,7 +277,7 @@ _con_curl_check_connectivity (CURLM *mhandle, int sockfd, int ev_bitmask) NMConnectivityCheckHandle *cb_data; CURLMsg *msg; CURLcode eret; - gint m_left; + int m_left; long response_code; CURLMcode ret; int running_handles; diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 54ccdb83..ca8c9526 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.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 2004 - 2014 Red Hat, Inc. + * Copyright 2004 - 2018 Red Hat, Inc. * Copyright 2005 - 2008 Novell, Inc. */ @@ -25,6 +25,7 @@ #include <errno.h> #include <fcntl.h> +#include <fnmatch.h> #include <string.h> #include <unistd.h> #include <stdlib.h> @@ -37,6 +38,7 @@ #include <net/ethernet.h> #include "nm-utils/nm-random-utils.h" +#include "nm-utils/nm-io-utils.h" #include "nm-utils.h" #include "nm-core-internal.h" #include "nm-setting-connection.h" @@ -45,15 +47,6 @@ #include "nm-setting-wireless.h" #include "nm-setting-wireless-security.h" -/* - * Some toolchains (E.G. uClibc 0.9.33 and earlier) don't export - * CLOCK_BOOTTIME even though the kernel supports it, so provide a - * local definition - */ -#ifndef CLOCK_BOOTTIME -#define CLOCK_BOOTTIME 7 -#endif - G_STATIC_ASSERT (sizeof (NMUtilsTestFlags) <= sizeof (int)); static int _nm_utils_testing = 0; @@ -532,7 +525,7 @@ _kc_waited_to_string (char *buf, gint64 wait_start_us) } static void -_kc_cb_watch_child (GPid pid, gint status, gpointer user_data) +_kc_cb_watch_child (GPid pid, int status, gpointer user_data) { KillChildAsyncData *data = user_data; char buf_exit[KC_EXIT_TO_STRING_BUF_SIZE], buf_wait[KC_WAITED_TO_STRING]; @@ -1455,7 +1448,7 @@ match_config_eval (const char *str, const char *tag, guint cur_nm_version) { gs_free char *s_ver = NULL; gs_strfreev char **s_ver_tokens = NULL; - gint v_maj = -1, v_min = -1, v_mic = -1; + int v_maj = -1, v_min = -1, v_mic = -1; guint c_maj = -1, c_min = -1, c_mic = -1; guint n_tokens; @@ -1587,9 +1580,9 @@ nm_match_spec_split (const char *value) /* Copied from glibs g_key_file_parse_value_as_string() function * and adjusted. */ - string_value = g_new (gchar, strlen (value) + 1); + string_value = g_new (char, strlen (value) + 1); - p = (gchar *) value; + p = (char *) value; /* skip over leading whitespace */ while (g_ascii_isspace (*p)) @@ -1739,6 +1732,33 @@ nm_match_spec_join (GSList *specs) return g_string_free (str, FALSE); } +gboolean +nm_wildcard_match_check (const char *str, + const char *const *patterns, + guint num_patterns) +{ + guint i, neg = 0; + + for (i = 0; i < num_patterns; i++) { + if (patterns[i][0] == '!') { + neg++; + if (!fnmatch (patterns[i] + 1, str, 0)) + return FALSE; + } + } + + if (neg == num_patterns) + return TRUE; + + for (i = 0; i < num_patterns; i++) { + if ( patterns[i][0] != '!' + && !fnmatch (patterns[i], str, 0)) + return TRUE; + } + + return FALSE; +} + /*****************************************************************************/ char * @@ -2036,7 +2056,7 @@ typedef struct NMSettingDiffResult diff_result; } LogConnectionSettingItem; -static gint +static int _log_connection_sort_hashes_fcn (gconstpointer a, gconstpointer b) { const LogConnectionSettingData *v1 = a; @@ -2079,7 +2099,7 @@ _log_connection_sort_hashes (NMConnection *connection, NMConnection *diff_base, return sorted_hashes; } -static gint +static int _log_connection_sort_names_fcn (gconstpointer a, gconstpointer b) { const LogConnectionSettingItem *v1 = a; @@ -2541,262 +2561,6 @@ nm_utils_machine_id_read (void) /*****************************************************************************/ -_nm_printf (3, 4) -static int -_get_contents_error (GError **error, int errsv, const char *format, ...) -{ - if (errsv < 0) - errsv = -errsv; - else if (!errsv) - errsv = errno; - - if (error) { - char *msg; - va_list args; - - va_start (args, format); - msg = g_strdup_vprintf (format, args); - va_end (args); - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "%s: %s", - msg, g_strerror (errsv)); - g_free (msg); - } - return -errsv; -} - -/** - * nm_utils_fd_get_contents: - * @fd: open file descriptor to read. The fd will not be closed, - * but don't rely on its state afterwards. - * @close_fd: if %TRUE, @fd will be closed by the function. - * Passing %TRUE here might safe a syscall for dup(). - * @max_length: allocate at most @max_length bytes. If the - * file is larger, reading will fail. Set to zero to use - * a very large default. - * - * WARNING: @max_length is here to avoid a crash for huge/unlimited files. - * For example, stat(/sys/class/net/enp0s25/ifindex) gives a filesize of - * 4K, although the actual real is small. @max_length is the memory - * allocated in the process of reading the file, thus it must be at least - * the size reported by fstat. - * If you set it to 1K, read will fail because fstat() claims the - * file is larger. - * - * @contents: the output buffer with the file read. It is always - * NUL terminated. The buffer is at most @max_length long, including - * the NUL byte. That is, it reads only files up to a length of - * @max_length - 1 bytes. - * @length: optional output argument of the read file size. - * - * A reimplementation of g_file_get_contents() with a few differences: - * - accepts an open fd, instead of a path name. This allows you to - * use openat(). - * - limits the maxium filesize to max_length. - * - * Returns: a negative error code on failure. - */ -int -nm_utils_fd_get_contents (int fd, - gboolean close_fd, - gsize max_length, - char **contents, - gsize *length, - GError **error) -{ - nm_auto_close int fd_keeper = close_fd ? fd : -1; - struct stat stat_buf; - gs_free char *str = NULL; - - g_return_val_if_fail (fd >= 0, -EINVAL); - g_return_val_if_fail (contents, -EINVAL); - g_return_val_if_fail (!error || !*error, -EINVAL); - - if (fstat (fd, &stat_buf) < 0) - return _get_contents_error (error, 0, "failure during fstat"); - - if (!max_length) { - /* default to a very large size, but not extreme */ - max_length = 2 * 1024 * 1024; - } - - if ( stat_buf.st_size > 0 - && S_ISREG (stat_buf.st_mode)) { - const gsize n_stat = stat_buf.st_size; - ssize_t n_read; - - if (n_stat > max_length - 1) - return _get_contents_error (error, EMSGSIZE, "file too large (%zu+1 bytes with maximum %zu bytes)", n_stat, max_length); - - str = g_try_malloc (n_stat + 1); - if (!str) - return _get_contents_error (error, ENOMEM, "failure to allocate buffer of %zu+1 bytes", n_stat); - - n_read = nm_utils_fd_read_loop (fd, str, n_stat, TRUE); - if (n_read < 0) - return _get_contents_error (error, n_read, "error reading %zu bytes from file descriptor", n_stat); - str[n_read] = '\0'; - - if (n_read < n_stat) { - char *tmp; - - tmp = g_try_realloc (str, n_read + 1); - if (!tmp) - return _get_contents_error (error, ENOMEM, "failure to reallocate buffer with %zu bytes", n_read + 1); - str = tmp; - } - NM_SET_OUT (length, n_read); - } else { - nm_auto_fclose FILE *f = NULL; - char buf[4096]; - gsize n_have, n_alloc; - int fd2; - - if (fd_keeper >= 0) - fd2 = nm_steal_fd (&fd_keeper); - else { - fd2 = fcntl (fd, F_DUPFD_CLOEXEC, 0); - if (fd2 < 0) - return _get_contents_error (error, 0, "error during dup"); - } - - if (!(f = fdopen (fd2, "r"))) { - nm_close (fd2); - return _get_contents_error (error, 0, "failure during fdopen"); - } - - n_have = 0; - n_alloc = 0; - - while (!feof (f)) { - int errsv; - gsize n_read; - - n_read = fread (buf, 1, sizeof (buf), f); - errsv = errno; - if (ferror (f)) - return _get_contents_error (error, errsv, "error during fread"); - - if ( n_have > G_MAXSIZE - 1 - n_read - || n_have + n_read + 1 > max_length) { - return _get_contents_error (error, EMSGSIZE, "file stream too large (%zu+1 bytes with maximum %zu bytes)", - (n_have > G_MAXSIZE - 1 - n_read) ? G_MAXSIZE : n_have + n_read, - max_length); - } - - if (n_have + n_read + 1 >= n_alloc) { - char *tmp; - - if (str) { - if (n_alloc >= max_length / 2) - n_alloc = max_length; - else - n_alloc *= 2; - } else - n_alloc = NM_MIN (n_read + 1, sizeof (buf)); - - tmp = g_try_realloc (str, n_alloc); - if (!tmp) - return _get_contents_error (error, ENOMEM, "failure to allocate buffer of %zu bytes", n_alloc); - str = tmp; - } - - memcpy (str + n_have, buf, n_read); - n_have += n_read; - } - - if (n_alloc == 0) - str = g_new0 (gchar, 1); - else { - str[n_have] = '\0'; - if (n_have + 1 < n_alloc) { - char *tmp; - - tmp = g_try_realloc (str, n_have + 1); - if (!tmp) - return _get_contents_error (error, ENOMEM, "failure to truncate buffer to %zu bytes", n_have + 1); - str = tmp; - } - } - - NM_SET_OUT (length, n_have); - } - - *contents = g_steal_pointer (&str); - return 0; -} - -/** - * nm_utils_file_get_contents: - * @dirfd: optional file descriptor to use openat(). If negative, use plain open(). - * @filename: the filename to open. Possibly relative to @dirfd. - * @max_length: allocate at most @max_length bytes. - * WARNING: see nm_utils_fd_get_contents() hint about @max_length. - * @contents: the output buffer with the file read. It is always - * NUL terminated. The buffer is at most @max_length long, including - * the NUL byte. That is, it reads only files up to a length of - * @max_length - 1 bytes. - * @length: optional output argument of the read file size. - * - * A reimplementation of g_file_get_contents() with a few differences: - * - accepts an @dirfd to open @filename relative to that path via openat(). - * - limits the maxium filesize to max_length. - * - uses O_CLOEXEC on internal file descriptor - * - * Returns: a negative error code on failure. - */ -int -nm_utils_file_get_contents (int dirfd, - const char *filename, - gsize max_length, - char **contents, - gsize *length, - GError **error) -{ - int fd; - int errsv; - - g_return_val_if_fail (filename && filename[0], -EINVAL); - - if (dirfd >= 0) { - fd = openat (dirfd, filename, O_RDONLY | O_CLOEXEC); - if (fd < 0) { - errsv = errno; - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "Failed to open file \"%s\" with openat: %s", - filename, - g_strerror (errsv)); - return -errsv; - } - } else { - fd = open (filename, O_RDONLY | O_CLOEXEC); - if (fd < 0) { - errsv = errno; - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "Failed to open file \"%s\": %s", - filename, - g_strerror (errsv)); - return -errsv; - } - } - return nm_utils_fd_get_contents (fd, - TRUE, - max_length, - contents, - length, - error); -} - -/*****************************************************************************/ - static gboolean _secret_key_read (guint8 **out_secret_key, gsize *out_key_len) @@ -2923,6 +2687,7 @@ nm_utils_get_boot_id (void) gs_free char *contents = NULL; nm_utils_file_get_contents (-1, "/proc/sys/kernel/random/boot_id", 0, + NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, &contents, NULL, NULL); if (contents) { g_strstrip (contents); @@ -3017,7 +2782,6 @@ nm_utils_get_ipv6_interface_identifier (NMLinkType link_type, out_iid->id_u8[0] |= 0x02; return TRUE; case NM_LINK_TYPE_GRE: - case NM_LINK_TYPE_GRETAP: /* Hardware address is the network-endian IPv4 address */ g_return_val_if_fail (hwaddr_len == 4, FALSE); addr = * (guint32 *) hwaddr; @@ -3027,6 +2791,11 @@ nm_utils_get_ipv6_interface_identifier (NMLinkType link_type, out_iid->id_u8[3] = 0xFE; memcpy (out_iid->id_u8 + 4, &addr, 4); return TRUE; + case NM_LINK_TYPE_6LOWPAN: + /* The hardware address is already 64-bit. This is the case for + * IEEE 802.15.4 networks. */ + memcpy (out_iid->id_u8, hwaddr, sizeof (out_iid->id_u8)); + return TRUE; default: if (hwaddr_len == ETH_ALEN) { /* Translate 48-bit MAC address to a 64-bit Modified EUI-64. See @@ -3661,8 +3430,8 @@ nm_utils_g_value_set_strv (GValue *value, GPtrArray *strings) /*****************************************************************************/ static gboolean -debug_key_matches (const gchar *key, - const gchar *token, +debug_key_matches (const char *key, + const char *token, guint length) { /* may not call GLib functions: see note in g_parse_debug_string() */ @@ -3964,116 +3733,12 @@ nm_utils_get_reverse_dns_domains_ip6 (const struct in6_addr *ip, guint8 plen, GP #undef N_SHIFT } -/** - * Copied from GLib's g_file_set_contents() et al., but allows - * specifying a mode for the new file. - */ -gboolean -nm_utils_file_set_contents (const gchar *filename, - const gchar *contents, - gssize length, - mode_t mode, - GError **error) -{ - gs_free char *tmp_name = NULL; - struct stat statbuf; - int errsv; - gssize s; - int fd; - - g_return_val_if_fail (filename, FALSE); - g_return_val_if_fail (contents || !length, FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - g_return_val_if_fail (length >= -1, FALSE); - - if (length == -1) - length = strlen (contents); - - tmp_name = g_strdup_printf ("%s.XXXXXX", filename); - fd = g_mkstemp_full (tmp_name, O_RDWR, mode); - if (fd < 0) { - errsv = errno; - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "failed to create file %s: %s", - tmp_name, - g_strerror (errsv)); - return FALSE; - } - - while (length > 0) { - s = write (fd, contents, length); - if (s < 0) { - errsv = errno; - if (errsv == EINTR) - continue; - - nm_close (fd); - unlink (tmp_name); - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "failed to write to file %s: %s", - tmp_name, - g_strerror (errsv)); - return FALSE; - } - - g_assert (s <= length); - - contents += s; - length -= s; - } - - /* If the final destination exists and is > 0 bytes, we want to sync the - * newly written file to ensure the data is on disk when we rename over - * the destination. Otherwise if we get a system crash we can lose both - * the new and the old file on some filesystems. (I.E. those that don't - * guarantee the data is written to the disk before the metadata.) - */ - if ( lstat (filename, &statbuf) == 0 - && statbuf.st_size > 0 - && fsync (fd) != 0) { - errsv = errno; - - nm_close (fd); - unlink (tmp_name); - - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "failed to fsync %s: %s", - tmp_name, - g_strerror (errsv)); - return FALSE; - } - - nm_close (fd); - - if (rename (tmp_name, filename)) { - errsv = errno; - unlink (tmp_name); - g_set_error (error, - G_FILE_ERROR, - g_file_error_from_errno (errsv), - "failed to rename %s to %s: %s", - tmp_name, - filename, - g_strerror (errsv)); - return FALSE; - } - - return TRUE; -} - struct plugin_info { char *path; struct stat st; }; -static gint +static int read_device_factory_paths_sort_fcn (gconstpointer a, gconstpointer b) { const struct plugin_info *da = a; diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index 08530400..30d1360a 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -204,9 +204,9 @@ typedef enum { NMMatchSpecMatchType nm_match_spec_device (const GSList *specs, const char *interface_name, + const char *device_type, const char *driver, const char *driver_version, - const char *device_type, const char *hwaddr, const char *s390_subchannels); NMMatchSpecMatchType nm_match_spec_config (const GSList *specs, @@ -215,6 +215,10 @@ NMMatchSpecMatchType nm_match_spec_config (const GSList *specs, GSList *nm_match_spec_split (const char *value); char *nm_match_spec_join (GSList *specs); +gboolean nm_wildcard_match_check (const char *str, + const char *const *patterns, + guint num_patterns); + /*****************************************************************************/ const char *nm_utils_get_ip_config_method (NMConnection *connection, @@ -260,26 +264,6 @@ gboolean nm_utils_sysctl_ip_conf_is_path (int addr_family, const char *path, con gboolean nm_utils_is_specific_hostname (const char *name); -int nm_utils_fd_get_contents (int fd, - gboolean close_fd, - gsize max_length, - char **contents, - gsize *length, - GError **error); - -int nm_utils_file_get_contents (int dirfd, - const char *filename, - gsize max_length, - char **contents, - gsize *length, - GError **error); - -gboolean nm_utils_file_set_contents (const gchar *filename, - const gchar *contents, - gssize length, - mode_t mode, - GError **error); - char *nm_utils_machine_id_read (void); gboolean nm_utils_machine_id_parse (const char *id_str, /*uuid_t*/ guchar *out_uuid); diff --git a/src/nm-dbus-manager.c b/src/nm-dbus-manager.c index 7f1121f6..ca7bde57 100644 --- a/src/nm-dbus-manager.c +++ b/src/nm-dbus-manager.c @@ -1084,7 +1084,7 @@ _obj_unregister (NMDBusManager *self, NULL); } -NMDBusObject * +gpointer nm_dbus_manager_lookup_object (NMDBusManager *self, const char *path) { NMDBusManagerPrivate *priv; @@ -1480,7 +1480,11 @@ nm_dbus_manager_start (NMDBusManager *self, g_return_if_fail (NM_IS_DBUS_MANAGER (self)); priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - g_return_if_fail (priv->connection); + + if (!priv->connection) { + /* Do nothing. We're presumably in the configure-and-quit mode. */ + return; + } priv->set_property_handler = set_property_handler; priv->set_property_handler_data = set_property_handler_data; @@ -1505,29 +1509,17 @@ nm_dbus_manager_acquire_bus (NMDBusManager *self) priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - /* we will create the D-Bus connection and registering the name synchronously. - * The reason why that is necessary is because: - * (1) if we are unable to create a D-Bus connection, it means D-Bus is not - * available and we run in D-Bus less mode. We do not support creating - * a D-Bus connection later on. This disconnected mode is useful for initrd - * (well, currently not yet, but will be). - * (2) if we are able to create the connection and register the name, - * all is good and we run with D-Bus. Note that D-Bus disconnects - * from D-Bus are ignored. Essentially, we do not support restarting - * D-Bus. - * (3) if we are able to create the connection but registration fails, - * it means that something is borked. Quite possibly another NetworkManager - * instance is running. We need to exit right away. - * To appease (1) and (3), we cannot initalize synchronously, because we need - * to know right away whether another NetworkManager instance is running (3). - **/ - + /* Create the D-Bus connection and registering the name synchronously. + * That is necessary because we need to exit right away if we can't + * acquire the name despite connecting to the bus successfully. + * It means that something is gravely broken -- such as another NetworkManager + * instance running. */ connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); if (!connection) { - _LOGI ("cannot connect to D-Bus and proceed without (%s)", error->message); - return TRUE; + _LOGI ("cannot connect to D-Bus: %s", error->message); + return FALSE; } g_dbus_connection_set_exit_on_close (connection, FALSE); diff --git a/src/nm-dbus-manager.h b/src/nm-dbus-manager.h index a0741316..04c42bb0 100644 --- a/src/nm-dbus-manager.h +++ b/src/nm-dbus-manager.h @@ -61,7 +61,7 @@ gboolean nm_dbus_manager_is_stopping (NMDBusManager *self); GDBusConnection *nm_dbus_manager_get_connection (NMDBusManager *self); -NMDBusObject *nm_dbus_manager_lookup_object (NMDBusManager *self, const char *path); +gpointer nm_dbus_manager_lookup_object (NMDBusManager *self, const char *path); void _nm_dbus_manager_obj_export (NMDBusObject *obj); void _nm_dbus_manager_obj_unexport (NMDBusObject *obj); diff --git a/src/nm-dcb.c b/src/nm-dcb.c index 140e7c36..5a46fa00 100644 --- a/src/nm-dcb.c +++ b/src/nm-dcb.c @@ -104,7 +104,7 @@ G_STMT_START { \ #define SET_APP(f, s, tag) \ G_STMT_START { \ - gint prio = nm_setting_dcb_get_app_##tag##_priority (s); \ + int prio = nm_setting_dcb_get_app_##tag##_priority (s); \ \ SET_FLAGS (f, "app:" #tag); \ if ((f & NM_SETTING_DCB_FLAG_ENABLE) && (prio >= 0)) { \ diff --git a/src/nm-hostname-manager.c b/src/nm-hostname-manager.c index f569ab86..88ff1604 100644 --- a/src/nm-hostname-manager.c +++ b/src/nm-hostname-manager.c @@ -48,8 +48,7 @@ #define HOSTNAME_FILE_UCASE_HOSTNAME "/etc/HOSTNAME" #define HOSTNAME_FILE_GENTOO "/etc/conf.d/hostname" -#define IFCFG_DIR SYSCONFDIR "/sysconfig/network" -#define CONF_DHCP IFCFG_DIR "/dhcp" +#define CONF_DHCP SYSCONFDIR "/sysconfig/network/dhcp" #if (defined(HOSTNAME_PERSIST_SUSE) + defined(HOSTNAME_PERSIST_SLACKWARE) + defined(HOSTNAME_PERSIST_GENTOO)) > 1 #error "Can only define one of HOSTNAME_PERSIST_*" @@ -103,7 +102,7 @@ NM_DEFINE_SINGLETON_GETTER (NMHostnameManager, nm_hostname_manager_get, NM_TYPE_ /*****************************************************************************/ #if defined(HOSTNAME_PERSIST_GENTOO) -static gchar * +static char * read_hostname_gentoo (const char *path) { gs_free char *contents = NULL; @@ -129,7 +128,7 @@ read_hostname_gentoo (const char *path) #endif #if defined(HOSTNAME_PERSIST_SLACKWARE) -static gchar * +static char * read_hostname_slackware (const char *path) { gs_free char *contents = NULL; diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index 308c9e1f..6ae2b9d2 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -380,7 +380,7 @@ int main (int argc, char *argv[]) { char *bad_domains = NULL; - GError *error = NULL; + gs_free_error GError *error = NULL; gboolean wrote_pidfile = FALSE; gs_free char *pidfile = NULL; gs_unref_object NMDhcpClient *dhcp4_client = NULL; @@ -516,8 +516,11 @@ main (int argc, char *argv[]) client_id, NM_DHCP_TIMEOUT_DEFAULT, NULL, - global_opt.dhcp4_address); - g_assert (dhcp4_client); + global_opt.dhcp4_address, + &error); + if (!dhcp4_client) + g_error ("failure to start DHCP: %s", error->message); + g_signal_connect (dhcp4_client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (dhcp4_state_changed), @@ -624,10 +627,10 @@ nm_config_data_get_value (const NMConfigData *config_data, const char *group, co return NULL; } -gboolean +NMConfigConfigureAndQuitType nm_config_get_configure_and_quit (NMConfig *config) { - return TRUE; + return NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED; } NMDBusManager * diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 657ebfc0..6604711c 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -278,10 +278,12 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMIP4Config, PROP_ROUTE_DATA, PROP_ROUTES, PROP_GATEWAY, + PROP_NAMESERVER_DATA, PROP_NAMESERVERS, PROP_DOMAINS, PROP_SEARCHES, PROP_DNS_OPTIONS, + PROP_WINS_SERVER_DATA, PROP_WINS_SERVERS, PROP_DNS_PRIORITY, ); @@ -291,8 +293,9 @@ typedef struct { guint32 mtu; int ifindex; NMIPConfigSource mtu_source; - gint dns_priority; + int dns_priority; NMSettingConnectionMdns mdns; + NMSettingConnectionLlmnr llmnr; GArray *nameservers; GPtrArray *domains; GPtrArray *searches; @@ -509,8 +512,8 @@ _notify_addresses (NMIP4Config *self) nm_clear_g_variant (&priv->address_data_variant); nm_clear_g_variant (&priv->addresses_variant); - _notify (self, PROP_ADDRESS_DATA); - _notify (self, PROP_ADDRESSES); + nm_gobject_notify_together (self, PROP_ADDRESS_DATA, + PROP_ADDRESSES); } static void @@ -521,13 +524,13 @@ _notify_routes (NMIP4Config *self) nm_assert (priv->best_default_route == _nm_ip4_config_best_default_route_find (self)); nm_clear_g_variant (&priv->route_data_variant); nm_clear_g_variant (&priv->routes_variant); - _notify (self, PROP_ROUTE_DATA); - _notify (self, PROP_ROUTES); + nm_gobject_notify_together (self, PROP_ROUTE_DATA, + PROP_ROUTES); } /*****************************************************************************/ -static gint +static int _addresses_sort_cmp_get_prio (in_addr_t addr) { if (nm_utils_ip4_address_is_link_local (addr)) @@ -538,7 +541,7 @@ _addresses_sort_cmp_get_prio (in_addr_t addr) static int _addresses_sort_cmp (gconstpointer a, gconstpointer b, gpointer user_data) { - gint p1, p2; + int p1, p2; const NMPlatformIP4Address *a1 = NMP_OBJECT_CAST_IP4_ADDRESS (*((const NMPObject **) a)); const NMPlatformIP4Address *a2 = NMP_OBJECT_CAST_IP4_ADDRESS (*((const NMPObject **) b)); guint32 n1, n2; @@ -914,6 +917,7 @@ void nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, NMSettingConnectionMdns mdns, + NMSettingConnectionLlmnr llmnr, guint32 route_table, guint32 route_metric) { @@ -1031,6 +1035,7 @@ nm_ip4_config_merge_setting (NMIP4Config *self, nm_ip4_config_set_dns_priority (self, priority); nm_ip4_config_mdns_set (self, mdns); + nm_ip4_config_llmnr_set (self, llmnr); g_object_thaw_notify (G_OBJECT (self)); } @@ -1251,6 +1256,10 @@ nm_ip4_config_merge (NMIP4Config *dst, nm_ip4_config_mdns_set (dst, NM_MAX (nm_ip4_config_mdns_get (src), nm_ip4_config_mdns_get (dst))); + /* LLMNR */ + nm_ip4_config_llmnr_set (dst, + NM_MAX (nm_ip4_config_llmnr_get (src), + nm_ip4_config_llmnr_get (dst))); g_object_thaw_notify (G_OBJECT (dst)); } @@ -1367,7 +1376,7 @@ nm_ip4_config_subtract (NMIP4Config *dst, { NMIP4ConfigPrivate *dst_priv; guint i; - gint idx; + int idx; const NMPlatformIP4Address *a; const NMPlatformIP4Route *r; NMDedupMultiIter ipconf_iter; @@ -1492,12 +1501,17 @@ nm_ip4_config_subtract (NMIP4Config *dst, if (nm_ip4_config_mdns_get (src) == nm_ip4_config_mdns_get (dst)) nm_ip4_config_mdns_set (dst, NM_SETTING_CONNECTION_MDNS_DEFAULT); + /* LLMNR */ + if (nm_ip4_config_llmnr_get (src) == nm_ip4_config_llmnr_get (dst)) + nm_ip4_config_llmnr_set (dst, NM_SETTING_CONNECTION_LLMNR_DEFAULT); + g_object_thaw_notify (G_OBJECT (dst)); } static gboolean _nm_ip4_config_intersect_helper (NMIP4Config *dst, const NMIP4Config *src, + gboolean intersect_routes, guint32 default_route_metric_penalty, gboolean update_dst) { @@ -1542,6 +1556,9 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, /* ignore nameservers */ /* routes */ + if (!intersect_routes) + goto skip_routes; + changed = FALSE; new_best_default_route = NULL; nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, dst, &r) { @@ -1582,6 +1599,7 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, _notify (dst, PROP_GATEWAY); } +skip_routes: if (changed) { _notify_routes (dst); result = TRUE; @@ -1593,6 +1611,7 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, /* ignore NIS */ /* ignore WINS */ /* ignore mdns */ + /* ignore LLMNR */ if (update_dst) g_object_thaw_notify (G_OBJECT (dst)); @@ -1611,9 +1630,10 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src, + gboolean intersect_routes, guint32 default_route_metric_penalty) { - _nm_ip4_config_intersect_helper (dst, src, default_route_metric_penalty, TRUE); + _nm_ip4_config_intersect_helper (dst, src, intersect_routes, default_route_metric_penalty, TRUE); } /** @@ -1634,14 +1654,17 @@ nm_ip4_config_intersect (NMIP4Config *dst, NMIP4Config * nm_ip4_config_intersect_alloc (const NMIP4Config *a, const NMIP4Config *b, + gboolean intersect_routes, guint32 default_route_metric_penalty) { NMIP4Config *a_copy; if (_nm_ip4_config_intersect_helper ((NMIP4Config *) a, b, + intersect_routes, default_route_metric_penalty, FALSE)) { a_copy = nm_ip4_config_clone (a); - _nm_ip4_config_intersect_helper (a_copy, b, default_route_metric_penalty, TRUE); + _nm_ip4_config_intersect_helper (a_copy, b, intersect_routes, + default_route_metric_penalty, TRUE); return a_copy; } else return NULL; @@ -1871,7 +1894,15 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev has_relevant_changes = TRUE; } - dst_priv->mdns = src_priv->mdns; + if (src_priv->mdns != dst_priv->mdns) { + dst_priv->mdns = src_priv->mdns; + has_relevant_changes = TRUE; + } + + if (src_priv->llmnr != dst_priv->llmnr) { + dst_priv->llmnr = src_priv->llmnr; + has_relevant_changes = TRUE; + } /* DNS priority */ if (src_priv->dns_priority != dst_priv->dns_priority) { @@ -1949,71 +1980,90 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev } void -nm_ip4_config_dump (const NMIP4Config *self, const char *detail) +nm_ip_config_dump (const NMIPConfig *self, + const char *detail, + NMLogLevel level, + NMLogDomain domain) { - guint32 tmp; - guint i; - const char *str; NMDedupMultiIter ipconf_iter; - const NMPlatformIP4Address *address; - const NMPlatformIP4Route *route; - - g_message ("--------- NMIP4Config %p (%s)", self, detail); + const NMPlatformIP4Address *addr4; + const NMPlatformIP6Address *addr6; + const NMPlatformIP4Route *route4; + const NMPlatformIP6Route *route6; + const NMIP4Config *ip4; + const NMIP6Config *ip6; + int addr_family = AF_UNSPEC; + char addr_family_char = '?'; + const char *path; + gconstpointer ptr; + guint i; - if (self == NULL) { - g_message (" (null)"); - return; + if (self) { + addr_family = nm_ip_config_get_addr_family (self); + addr_family_char = nm_utils_addr_family_to_char (addr_family); } - str = nm_dbus_object_get_path (NM_DBUS_OBJECT (self)); - if (str) - g_message (" path: %s", str); - - /* addresses */ - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, self, &address) - g_message (" a: %s", nm_platform_ip4_address_to_string (address, NULL, 0)); - - /* nameservers */ - for (i = 0; i < nm_ip4_config_get_num_nameservers (self); i++) { - tmp = nm_ip4_config_get_nameserver (self, i); - g_message (" ns: %s", nm_utils_inet4_ntop (tmp, NULL)); - } + nm_log (level, domain, NULL, NULL, + "---- NMIP%cConfig %p (%s)", + addr_family_char, + self, + detail); - /* routes */ - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, &route) - g_message (" rt: %s", nm_platform_ip4_route_to_string (route, NULL, 0)); + if (!self) + return; - /* domains */ - for (i = 0; i < nm_ip4_config_get_num_domains (self); i++) - g_message (" domain: %s", nm_ip4_config_get_domain (self, i)); + path = nm_dbus_object_get_path (NM_DBUS_OBJECT (self)); + if (path) + nm_log (level, domain, NULL, NULL, " path : %s", path); - /* dns searches */ - for (i = 0; i < nm_ip4_config_get_num_searches (self); i++) - g_message (" search: %s", nm_ip4_config_get_search (self, i)); + if (addr_family == AF_INET) { + ip4 = NM_IP4_CONFIG (self); + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &addr4) { + nm_log (level, domain, NULL, NULL, " address : %s", + nm_platform_ip4_address_to_string (addr4, NULL, 0)); + } + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route4) { + nm_log (level, domain, NULL, NULL, " route : %s", + nm_platform_ip4_route_to_string (route4, NULL, 0)); + } + } else { + ip6 = NM_IP6_CONFIG (self); + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &addr6) { + nm_log (level, domain, NULL, NULL, " address : %s", + nm_platform_ip6_address_to_string (addr6, NULL, 0)); + } + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route6) { + nm_log (level, domain, NULL, NULL, " route : %s", + nm_platform_ip6_route_to_string (route6, NULL, 0)); + } + } - /* dns options */ - for (i = 0; i < nm_ip4_config_get_num_dns_options (self); i++) - g_message (" dnsopt: %s", nm_ip4_config_get_dns_option (self, i)); + for (i = 0; i < nm_ip_config_get_num_nameservers (self); i++) { + ptr = nm_ip_config_get_nameserver (self, i); + nm_log (level, domain, NULL, NULL, " dns : %s", + nm_utils_inet_ntop (addr_family, ptr, NULL)); + } - g_message (" dnspri: %d", nm_ip4_config_get_dns_priority (self)); + for (i = 0; i < nm_ip_config_get_num_domains (self); i++) + nm_log (level, domain, NULL, NULL, " domain : %s", nm_ip_config_get_domain (self, i)); - g_message (" mtu: %"G_GUINT32_FORMAT" (source: %d)", nm_ip4_config_get_mtu (self), (int) nm_ip4_config_get_mtu_source (self)); + for (i = 0; i < nm_ip_config_get_num_searches (self); i++) + nm_log (level, domain, NULL, NULL, " search : %s", nm_ip_config_get_search (self, i)); - /* NIS */ - for (i = 0; i < nm_ip4_config_get_num_nis_servers (self); i++) { - tmp = nm_ip4_config_get_nis_server (self, i); - g_message (" nis: %s", nm_utils_inet4_ntop (tmp, NULL)); - } + for (i = 0; i < nm_ip_config_get_num_dns_options (self); i++) + nm_log (level, domain, NULL, NULL, "dns-option: %s", nm_ip_config_get_dns_option (self, i)); - g_message (" nisdmn: %s", nm_ip4_config_get_nis_domain (self) ?: "(none)"); + nm_log (level, domain, NULL, NULL, " dns-prio : %d", nm_ip_config_get_dns_priority (self)); - /* WINS */ - for (i = 0; i < nm_ip4_config_get_num_wins (self); i++) { - tmp = nm_ip4_config_get_wins (self, i); - g_message (" wins: %s", nm_utils_inet4_ntop (tmp, NULL)); + if (addr_family == AF_INET) { + ip4 = NM_IP4_CONFIG (self); + nm_log (level, domain, NULL, NULL, + " mtu : %"G_GUINT32_FORMAT" (source: %d)", + nm_ip4_config_get_mtu (ip4), + (int) nm_ip4_config_get_mtu_source (ip4)); + nm_log (level, domain, NULL, NULL, " metered : %d", + (int) nm_ip4_config_get_metered (ip4)); } - - g_message (" mtrd: %d", (int) nm_ip4_config_get_metered (self)); } /*****************************************************************************/ @@ -2307,7 +2357,8 @@ nm_ip4_config_reset_nameservers (NMIP4Config *self) if (priv->nameservers->len != 0) { g_array_set_size (priv->nameservers, 0); - _notify (self, PROP_NAMESERVERS); + nm_gobject_notify_together (self, PROP_NAMESERVER_DATA, + PROP_NAMESERVERS); } } @@ -2324,7 +2375,8 @@ nm_ip4_config_add_nameserver (NMIP4Config *self, guint32 new) return; g_array_append_val (priv->nameservers, new); - _notify (self, PROP_NAMESERVERS); + nm_gobject_notify_together (self, PROP_NAMESERVER_DATA, + PROP_NAMESERVERS); } void @@ -2335,7 +2387,8 @@ nm_ip4_config_del_nameserver (NMIP4Config *self, guint i) g_return_if_fail (i < priv->nameservers->len); g_array_remove_index (priv->nameservers, i); - _notify (self, PROP_NAMESERVERS); + nm_gobject_notify_together (self, PROP_NAMESERVER_DATA, + PROP_NAMESERVERS); } guint @@ -2557,10 +2610,23 @@ nm_ip4_config_mdns_set (NMIP4Config *self, NM_IP4_CONFIG_GET_PRIVATE (self)->mdns = mdns; } +NMSettingConnectionLlmnr +nm_ip4_config_llmnr_get (const NMIP4Config *self) +{ + return NM_IP4_CONFIG_GET_PRIVATE (self)->llmnr; +} + +void +nm_ip4_config_llmnr_set (NMIP4Config *self, + NMSettingConnectionLlmnr llmnr) +{ + NM_IP4_CONFIG_GET_PRIVATE (self)->llmnr = llmnr; +} + /*****************************************************************************/ void -nm_ip4_config_set_dns_priority (NMIP4Config *self, gint priority) +nm_ip4_config_set_dns_priority (NMIP4Config *self, int priority) { NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); @@ -2570,7 +2636,7 @@ nm_ip4_config_set_dns_priority (NMIP4Config *self, gint priority) } } -gint +int nm_ip4_config_get_dns_priority (const NMIP4Config *self) { const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); @@ -2653,7 +2719,8 @@ nm_ip4_config_reset_wins (NMIP4Config *self) if (priv->wins->len != 0) { g_array_set_size (priv->wins, 0); - _notify (self, PROP_WINS_SERVERS); + nm_gobject_notify_together (self, PROP_WINS_SERVER_DATA, + PROP_WINS_SERVERS); } } @@ -2670,7 +2737,8 @@ nm_ip4_config_add_wins (NMIP4Config *self, guint32 wins) return; g_array_append_val (priv->wins, wins); - _notify (self, PROP_WINS_SERVERS); + nm_gobject_notify_together (self, PROP_WINS_SERVER_DATA, + PROP_WINS_SERVERS); } void @@ -2681,7 +2749,8 @@ nm_ip4_config_del_wins (NMIP4Config *self, guint i) g_return_if_fail (i < priv->wins->len); g_array_remove_index (priv->wins, i); - _notify (self, PROP_WINS_SERVERS); + nm_gobject_notify_together (self, PROP_WINS_SERVER_DATA, + PROP_WINS_SERVERS); } guint @@ -2843,6 +2912,7 @@ nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only) NMDedupMultiIter ipconf_iter; const NMPlatformIP4Address *address; const NMPlatformIP4Route *route; + int val; g_return_if_fail (self); g_return_if_fail (sum); @@ -2889,6 +2959,25 @@ nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only) s = nm_ip4_config_get_dns_option (self, i); g_checksum_update (sum, (const guint8 *) s, strlen (s)); } + + val = nm_ip4_config_mdns_get (self); + if (val != NM_SETTING_CONNECTION_MDNS_DEFAULT) + g_checksum_update (sum, (const guint8 *) &val, sizeof (val)); + + val = nm_ip4_config_llmnr_get (self); + if (val != NM_SETTING_CONNECTION_LLMNR_DEFAULT) + g_checksum_update (sum, (const guint8 *) &val, sizeof (val)); + + /* FIXME(ip-config-checksum): the DNS priority should be considered relevant + * and added into the checksum as well, but this can't be done right now + * because in the DNS manager we rely on the fact that an empty + * configuration (i.e. just created) has a zero checksum. This is needed to + * avoid rewriting resolv.conf when there is no change. + * + * The DNS priority initial value depends on the connection type (VPN or + * not), so it's a bit difficult to add it to checksum maintaining the + * assumption of checksum(empty)=0 + */ } /** @@ -2944,6 +3033,7 @@ get_property (GObject *object, guint prop_id, NMDedupMultiIter ipconf_iter; const NMPlatformIP4Route *route; GVariantBuilder builder_data, builder_legacy; + guint i; switch (prop_id) { case PROP_IFINDEX: @@ -2962,7 +3052,7 @@ get_property (GObject *object, guint prop_id, head_entry = nm_ip4_config_lookup_addresses (self); if (head_entry) { gs_free const NMPObject **addresses = NULL; - guint naddr, i; + guint naddr; addresses = (const NMPObject **) nm_dedup_multi_objs_to_array_head (head_entry, NULL, NULL, &naddr); nm_assert (addresses && naddr); @@ -3098,6 +3188,26 @@ out_routes_cached: } else g_value_set_string (value, NULL); break; + case PROP_NAMESERVER_DATA: + g_variant_builder_init (&builder_data, G_VARIANT_TYPE ("aa{sv}")); + + for (i = 0; i < priv->nameservers->len; i++) { + GVariantBuilder nested_builder; + char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + + nm_utils_inet4_ntop (g_array_index (priv->nameservers, in_addr_t, i), + addr_str); + + g_variant_builder_init (&nested_builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&nested_builder, "{sv}", + "address", + g_variant_new_string (addr_str)); + g_variant_builder_add (&builder_data, "a{sv}", &nested_builder); + } + + g_value_take_variant (value, + g_variant_builder_end (&builder_data)); + break; case PROP_NAMESERVERS: g_value_take_variant (value, g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, @@ -3117,6 +3227,19 @@ out_routes_cached: case PROP_DNS_PRIORITY: g_value_set_int (value, priv->dns_priority); break; + case PROP_WINS_SERVER_DATA: + g_variant_builder_init (&builder_data, G_VARIANT_TYPE ("as")); + for (i = 0; i < priv->wins->len; i++) { + char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + + g_variant_builder_add (&builder_data, + "s", + nm_utils_inet4_ntop (g_array_index (priv->wins, in_addr_t, i), + addr_str)); + } + g_value_take_variant (value, + g_variant_builder_end (&builder_data)); + break; case PROP_WINS_SERVERS: g_value_take_variant (value, g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, @@ -3170,6 +3293,7 @@ nm_ip4_config_init (NMIP4Config *self) NMP_OBJECT_TYPE_IP4_ROUTE); priv->mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; + priv->llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; priv->nameservers = g_array_new (FALSE, FALSE, sizeof (guint32)); priv->domains = g_ptr_array_new_with_free_func (g_free); priv->searches = g_ptr_array_new_with_free_func (g_free); @@ -3224,17 +3348,19 @@ static const NMDBusInterfaceInfoExtended interface_info_ip4_config = { &nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Addresses", "aau", NM_IP4_CONFIG_ADDRESSES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("AddressData", "aa{sv}", NM_IP4_CONFIG_ADDRESS_DATA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Gateway", "s", NM_IP4_CONFIG_GATEWAY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Routes", "aau", NM_IP4_CONFIG_ROUTES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("RouteData", "aa{sv}", NM_IP4_CONFIG_ROUTE_DATA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Nameservers", "au", NM_IP4_CONFIG_NAMESERVERS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Domains", "as", NM_IP4_CONFIG_DOMAINS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Searches", "as", NM_IP4_CONFIG_SEARCHES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DnsOptions", "as", NM_IP4_CONFIG_DNS_OPTIONS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DnsPriority", "i", NM_IP4_CONFIG_DNS_PRIORITY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("WinsServers", "au", NM_IP4_CONFIG_WINS_SERVERS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Addresses", "aau", NM_IP4_CONFIG_ADDRESSES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("AddressData", "aa{sv}", NM_IP4_CONFIG_ADDRESS_DATA), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Gateway", "s", NM_IP4_CONFIG_GATEWAY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Routes", "aau", NM_IP4_CONFIG_ROUTES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("RouteData", "aa{sv}", NM_IP4_CONFIG_ROUTE_DATA), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("NameserverData", "aa{sv}", NM_IP4_CONFIG_NAMESERVER_DATA), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Nameservers", "au", NM_IP4_CONFIG_NAMESERVERS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Domains", "as", NM_IP4_CONFIG_DOMAINS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Searches", "as", NM_IP4_CONFIG_SEARCHES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DnsOptions", "as", NM_IP4_CONFIG_DNS_OPTIONS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("DnsPriority", "i", NM_IP4_CONFIG_DNS_PRIORITY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE ("WinsServerData", "as", NM_IP4_CONFIG_WINS_SERVER_DATA), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("WinsServers", "au", NM_IP4_CONFIG_WINS_SERVERS), ), ), .legacy_property_changed = TRUE, @@ -3293,6 +3419,12 @@ nm_ip4_config_class_init (NMIP4ConfigClass *config_class) NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_NAMESERVER_DATA] = + g_param_spec_variant (NM_IP4_CONFIG_NAMESERVER_DATA, "", "", + G_VARIANT_TYPE ("aa{sv}"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_NAMESERVERS] = g_param_spec_variant (NM_IP4_CONFIG_NAMESERVERS, "", "", G_VARIANT_TYPE ("au"), @@ -3319,6 +3451,12 @@ nm_ip4_config_class_init (NMIP4ConfigClass *config_class) G_MININT32, G_MAXINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_WINS_SERVER_DATA] = + g_param_spec_variant (NM_IP4_CONFIG_WINS_SERVER_DATA, "", "", + G_VARIANT_TYPE ("as"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_WINS_SERVERS] = g_param_spec_variant (NM_IP4_CONFIG_WINS_SERVERS, "", "", G_VARIANT_TYPE ("au"), diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 45c1fa3f..07fb7f12 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -138,16 +138,18 @@ typedef struct _NMIP4ConfigClass NMIP4ConfigClass; #define NM_IP4_CONFIG_ADDRESS_DATA "address-data" #define NM_IP4_CONFIG_ROUTE_DATA "route-data" #define NM_IP4_CONFIG_GATEWAY "gateway" -#define NM_IP4_CONFIG_NAMESERVERS "nameservers" +#define NM_IP4_CONFIG_NAMESERVER_DATA "nameserver-data" #define NM_IP4_CONFIG_DOMAINS "domains" #define NM_IP4_CONFIG_SEARCHES "searches" #define NM_IP4_CONFIG_DNS_OPTIONS "dns-options" #define NM_IP4_CONFIG_DNS_PRIORITY "dns-priority" -#define NM_IP4_CONFIG_WINS_SERVERS "wins-servers" +#define NM_IP4_CONFIG_WINS_SERVER_DATA "wins-server-data" /* deprecated */ #define NM_IP4_CONFIG_ADDRESSES "addresses" #define NM_IP4_CONFIG_ROUTES "routes" +#define NM_IP4_CONFIG_NAMESERVERS "nameservers" +#define NM_IP4_CONFIG_WINS_SERVERS "wins-servers" GType nm_ip4_config_get_type (void); @@ -173,6 +175,7 @@ gboolean nm_ip4_config_commit (const NMIP4Config *self, void nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, NMSettingConnectionMdns mdns, + NMSettingConnectionLlmnr llmnr, guint32 route_table, guint32 route_metric); NMSetting *nm_ip4_config_create_setting (const NMIP4Config *self); @@ -186,12 +189,13 @@ void nm_ip4_config_subtract (NMIP4Config *dst, guint32 default_route_metric_penalty); void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src, + gboolean intersect_routes, guint32 default_route_metric_penalty); NMIP4Config *nm_ip4_config_intersect_alloc (const NMIP4Config *a, const NMIP4Config *b, + gboolean intersect_routes, guint32 default_route_metric_penalty); gboolean nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relevant_changes); -void nm_ip4_config_dump (const NMIP4Config *self, const char *detail); const NMPObject *nm_ip4_config_best_default_route_get (const NMIP4Config *self); const NMPObject *_nm_ip4_config_best_default_route_find (const NMIP4Config *self); @@ -201,6 +205,9 @@ in_addr_t nmtst_ip4_config_get_gateway (NMIP4Config *config); NMSettingConnectionMdns nm_ip4_config_mdns_get (const NMIP4Config *self); void nm_ip4_config_mdns_set (NMIP4Config *self, NMSettingConnectionMdns mdns); +NMSettingConnectionLlmnr nm_ip4_config_llmnr_get (const NMIP4Config *self); +void nm_ip4_config_llmnr_set (NMIP4Config *self, + NMSettingConnectionLlmnr llmnr); const NMDedupMultiHeadEntry *nm_ip4_config_lookup_addresses (const NMIP4Config *self); void nm_ip4_config_reset_addresses (NMIP4Config *self); @@ -257,8 +264,8 @@ void nm_ip4_config_del_dns_option (NMIP4Config *self, guint i); guint nm_ip4_config_get_num_dns_options (const NMIP4Config *self); const char * nm_ip4_config_get_dns_option (const NMIP4Config *self, guint i); -void nm_ip4_config_set_dns_priority (NMIP4Config *self, gint priority); -gint nm_ip4_config_get_dns_priority (const NMIP4Config *self); +void nm_ip4_config_set_dns_priority (NMIP4Config *self, int priority); +int nm_ip4_config_get_dns_priority (const NMIP4Config *self); void nm_ip4_config_reset_nis_servers (NMIP4Config *self); void nm_ip4_config_add_nis_server (NMIP4Config *self, guint32 nis); @@ -291,6 +298,11 @@ gboolean nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b); gboolean _nm_ip_config_check_and_add_domain (GPtrArray *array, const char *domain); +void nm_ip_config_dump (const NMIPConfig *self, + const char *detail, + NMLogLevel level, + NMLogDomain domain); + /*****************************************************************************/ #include "nm-ip6-config.h" @@ -431,7 +443,7 @@ nm_ip_config_get_dns_priority (const NMIPConfig *self) } static inline void -nm_ip_config_set_dns_priority (NMIPConfig *self, gint priority) +nm_ip_config_set_dns_priority (NMIPConfig *self, int priority) { _NM_IP_CONFIG_DISPATCH_VOID (self, nm_ip4_config_set_dns_priority, nm_ip6_config_set_dns_priority, priority); } @@ -531,11 +543,13 @@ nm_ip_config_best_default_route_get (const NMIPConfig *self) static inline void nm_ip_config_intersect (NMIPConfig *dst, const NMIPConfig *src, + gboolean intersect_routes, guint32 default_route_metric_penalty) { _NM_IP_CONFIG_DISPATCH_SET_OP (, dst, src, nm_ip4_config_intersect, nm_ip6_config_intersect, + intersect_routes, default_route_metric_penalty); } @@ -577,18 +591,21 @@ nm_ip_config_replace (NMIPConfig *dst, static inline NMIPConfig * nm_ip_config_intersect_alloc (const NMIPConfig *a, const NMIPConfig *b, + gboolean intersect_routes, guint32 default_route_metric_penalty) { if (NM_IS_IP4_CONFIG (a)) { nm_assert (NM_IS_IP4_CONFIG (b)); return (NMIPConfig *) nm_ip4_config_intersect_alloc ((const NMIP4Config *) a, (const NMIP4Config *) b, + intersect_routes, default_route_metric_penalty); } else { nm_assert (NM_IS_IP6_CONFIG (a)); nm_assert (NM_IS_IP6_CONFIG (b)); return (NMIPConfig *) nm_ip6_config_intersect_alloc ((const NMIP6Config *) a, (const NMIP6Config *) b, + intersect_routes, default_route_metric_penalty); } } diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 3869fee8..a8c4aecd 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -208,8 +208,8 @@ _notify_addresses (NMIP6Config *self) nm_clear_g_variant (&priv->address_data_variant); nm_clear_g_variant (&priv->addresses_variant); - _notify (self, PROP_ADDRESS_DATA); - _notify (self, PROP_ADDRESSES); + nm_gobject_notify_together (self, PROP_ADDRESS_DATA, + PROP_ADDRESSES); } static void @@ -220,13 +220,13 @@ _notify_routes (NMIP6Config *self) nm_assert (priv->best_default_route == _nm_ip6_config_best_default_route_find (self)); nm_clear_g_variant (&priv->route_data_variant); nm_clear_g_variant (&priv->routes_variant); - _notify (self, PROP_ROUTE_DATA); - _notify (self, PROP_ROUTES); + nm_gobject_notify_together (self, PROP_ROUTE_DATA, + PROP_ROUTES); } /*****************************************************************************/ -static gint +static int _addresses_sort_cmp_get_prio (const struct in6_addr *addr) { if (IN6_IS_ADDR_V4MAPPED (addr)) @@ -249,7 +249,7 @@ _addresses_sort_cmp (const NMPlatformIP6Address *a1, const NMPlatformIP6Address *a2, gboolean prefer_temp) { - gint p1, p2, c; + int p1, p2, c; gboolean perm1, perm2, tent1, tent2; gboolean ipv6_privacy1, ipv6_privacy2; @@ -979,7 +979,7 @@ nm_ip6_config_subtract (NMIP6Config *dst, { NMIP6ConfigPrivate *dst_priv; guint i; - gint idx; + int idx; const NMPlatformIP6Address *a; const NMPlatformIP6Route *r; NMDedupMultiIter ipconf_iter; @@ -1084,6 +1084,7 @@ nm_ip6_config_subtract (NMIP6Config *dst, static gboolean _nm_ip6_config_intersect_helper (NMIP6Config *dst, const NMIP6Config *src, + gboolean intersect_routes, guint32 default_route_metric_penalty, gboolean update_dst) { @@ -1128,6 +1129,9 @@ _nm_ip6_config_intersect_helper (NMIP6Config *dst, /* ignore nameservers */ /* routes */ + if (!intersect_routes) + goto skip_routes; + changed = FALSE; new_best_default_route = NULL; nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, dst, &r) { @@ -1172,6 +1176,7 @@ _nm_ip6_config_intersect_helper (NMIP6Config *dst, result = TRUE; } +skip_routes: /* ignore domains */ /* ignore dns searches */ /* ignore dns options */ @@ -1194,9 +1199,10 @@ _nm_ip6_config_intersect_helper (NMIP6Config *dst, void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src, + gboolean intersect_routes, guint32 default_route_metric_penalty) { - _nm_ip6_config_intersect_helper (dst, src, default_route_metric_penalty, TRUE); + _nm_ip6_config_intersect_helper (dst, src, intersect_routes, default_route_metric_penalty, TRUE); } /** @@ -1217,14 +1223,17 @@ nm_ip6_config_intersect (NMIP6Config *dst, NMIP6Config * nm_ip6_config_intersect_alloc (const NMIP6Config *a, const NMIP6Config *b, + gboolean intersect_routes, guint32 default_route_metric_penalty) { NMIP6Config *a_copy; if (_nm_ip6_config_intersect_helper ((NMIP6Config *) a, b, + intersect_routes, default_route_metric_penalty, FALSE)) { a_copy = nm_ip6_config_clone (a); - _nm_ip6_config_intersect_helper (a_copy, b, default_route_metric_penalty, TRUE); + _nm_ip6_config_intersect_helper (a_copy, b, intersect_routes, + default_route_metric_penalty, TRUE); return a_copy; } else return NULL; @@ -1483,53 +1492,6 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev return has_relevant_changes || has_minor_changes; } -void -nm_ip6_config_dump (const NMIP6Config *self, const char *detail) -{ - const struct in6_addr *tmp; - guint32 i; - const char *str; - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Address *address; - const NMPlatformIP6Route *route; - - g_return_if_fail (self != NULL); - - g_message ("--------- NMIP6Config %p (%s)", self, detail); - - str = nm_dbus_object_get_path (NM_DBUS_OBJECT (self)); - if (str) - g_message (" path: %s", str); - - /* addresses */ - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &address) - g_message (" a: %s", nm_platform_ip6_address_to_string (address, NULL, 0)); - - /* nameservers */ - for (i = 0; i < nm_ip6_config_get_num_nameservers (self); i++) { - tmp = nm_ip6_config_get_nameserver (self, i); - g_message (" ns: %s", nm_utils_inet6_ntop (tmp, NULL)); - } - - /* routes */ - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, self, &route) - g_message (" rt: %s", nm_platform_ip6_route_to_string (route, NULL, 0)); - - /* domains */ - for (i = 0; i < nm_ip6_config_get_num_domains (self); i++) - g_message (" domain: %s", nm_ip6_config_get_domain (self, i)); - - /* dns searches */ - for (i = 0; i < nm_ip6_config_get_num_searches (self); i++) - g_message (" search: %s", nm_ip6_config_get_search (self, i)); - - /* dns options */ - for (i = 0; i < nm_ip6_config_get_num_dns_options (self); i++) - g_message (" dnsopt: %s", nm_ip6_config_get_dns_option (self, i)); - - g_message (" dnspri: %d", nm_ip6_config_get_dns_priority (self)); -} - /*****************************************************************************/ void @@ -2289,7 +2251,7 @@ nm_ip6_config_get_dns_option (const NMIP6Config *self, guint i) /*****************************************************************************/ void -nm_ip6_config_set_dns_priority (NMIP6Config *self, gint priority) +nm_ip6_config_set_dns_priority (NMIP6Config *self, int priority) { NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); @@ -2299,7 +2261,7 @@ nm_ip6_config_set_dns_priority (NMIP6Config *self, gint priority) } } -gint +int nm_ip6_config_get_dns_priority (const NMIP6Config *self) { const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index b8e80410..862f237d 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -130,12 +130,13 @@ void nm_ip6_config_subtract (NMIP6Config *dst, guint32 default_route_metric_penalty); void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src, + gboolean intersect_routes, guint32 default_route_metric_penalty); NMIP6Config *nm_ip6_config_intersect_alloc (const NMIP6Config *a, const NMIP6Config *b, + gboolean intersect_routes, guint32 default_route_metric_penalty); gboolean nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relevant_changes); -void nm_ip6_config_dump (const NMIP6Config *self, const char *detail); const NMPObject *nm_ip6_config_best_default_route_get (const NMIP6Config *self); const NMPObject *_nm_ip6_config_best_default_route_find (const NMIP6Config *self); @@ -194,8 +195,8 @@ void nm_ip6_config_del_dns_option (NMIP6Config *self, guint i); guint nm_ip6_config_get_num_dns_options (const NMIP6Config *self); const char * nm_ip6_config_get_dns_option (const NMIP6Config *self, guint i); -void nm_ip6_config_set_dns_priority (NMIP6Config *self, gint priority); -gint nm_ip6_config_get_dns_priority (const NMIP6Config *self); +void nm_ip6_config_set_dns_priority (NMIP6Config *self, int priority); +int nm_ip6_config_get_dns_priority (const NMIP6Config *self); const NMPObject *nm_ip6_config_nmpobj_lookup (const NMIP6Config *self, const NMPObject *needle); diff --git a/src/nm-logging.c b/src/nm-logging.c index c5553791..9e7d3892 100644 --- a/src/nm-logging.c +++ b/src/nm-logging.c @@ -54,9 +54,9 @@ void (*_nm_logging_clear_platform_logging_cache) (void); static void -nm_log_handler (const gchar *log_domain, +nm_log_handler (const char *log_domain, GLogLevelFlags level, - const gchar *message, + const char *message, gpointer ignored); typedef struct { @@ -745,9 +745,9 @@ _nm_log_impl (const char *file, /*****************************************************************************/ static void -nm_log_handler (const gchar *log_domain, +nm_log_handler (const char *log_domain, GLogLevelFlags level, - const gchar *message, + const char *message, gpointer ignored) { int syslog_priority; diff --git a/src/nm-logging.h b/src/nm-logging.h index 70c14a5e..0737bbd6 100644 --- a/src/nm-logging.h +++ b/src/nm-logging.h @@ -271,7 +271,7 @@ gboolean nm_logging_syslog_enabled (void); /* _LOGT() and _LOGt() both log with level TRACE, but the latter is disabled by default, * unless building with --with-more-logging. */ -#ifdef NM_MORE_LOGGING +#if NM_MORE_LOGGING #define _LOGt_ENABLED(...) _NMLOG_ENABLED (LOGL_TRACE, ##__VA_ARGS__) #define _LOGt(...) _NMLOG (LOGL_TRACE, __VA_ARGS__) #define _LOGt_err(errsv, ...) _NMLOG_err (errsv, LOGL_TRACE, __VA_ARGS__) @@ -311,7 +311,7 @@ gboolean nm_logging_syslog_enabled (void); #define _LOG2W_err(errsv, ...) _NMLOG2_err (errsv, LOGL_WARN , __VA_ARGS__) #define _LOG2E_err(errsv, ...) _NMLOG2_err (errsv, LOGL_ERR , __VA_ARGS__) -#ifdef NM_MORE_LOGGING +#if NM_MORE_LOGGING #define _LOG2t_ENABLED(...) _NMLOG2_ENABLED (LOGL_TRACE, ##__VA_ARGS__) #define _LOG2t(...) _NMLOG2 (LOGL_TRACE, __VA_ARGS__) #define _LOG2t_err(errsv, ...) _NMLOG2_err (errsv, LOGL_TRACE, __VA_ARGS__) @@ -342,7 +342,7 @@ gboolean nm_logging_syslog_enabled (void); #define _LOG3W_err(errsv, ...) _NMLOG3_err (errsv, LOGL_WARN , __VA_ARGS__) #define _LOG3E_err(errsv, ...) _NMLOG3_err (errsv, LOGL_ERR , __VA_ARGS__) -#ifdef NM_MORE_LOGGING +#if NM_MORE_LOGGING #define _LOG3t_ENABLED(...) _NMLOG3_ENABLED (LOGL_TRACE, ##__VA_ARGS__) #define _LOG3t(...) _NMLOG3 (LOGL_TRACE, __VA_ARGS__) #define _LOG3t_err(errsv, ...) _NMLOG3_err (errsv, LOGL_TRACE, __VA_ARGS__) diff --git a/src/nm-manager.c b/src/nm-manager.c index ad906169..7598995d 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -310,7 +310,8 @@ static void _emit_device_added_removed (NMManager *self, static NMActiveConnection *_new_active_connection (NMManager *self, gboolean is_vpn, - NMConnection *connection, + NMSettingsConnection *sett_conn, + NMConnection *incompl_conn, NMConnection *applied, const char *specific_object, NMDevice *device, @@ -319,7 +320,7 @@ static NMActiveConnection *_new_active_connection (NMManager *self, NMActivationReason activation_reason, GError **error); -static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data); +static void policy_activating_ac_changed (GObject *object, GParamSpec *pspec, gpointer user_data); static gboolean find_master (NMManager *self, NMConnection *connection, @@ -331,7 +332,8 @@ static gboolean find_master (NMManager *self, static void nm_manager_update_state (NMManager *manager); -static void connection_changed (NMManager *self, NMConnection *connection); +static void connection_changed (NMManager *self, + NMSettingsConnection *sett_conn); static void device_sleep_cb (NMDevice *device, GParamSpec *pspec, NMManager *self); @@ -353,7 +355,7 @@ static void active_connection_parent_active (NMActiveConnection *active, NMManager *self); static NMActiveConnection *active_connection_find (NMManager *self, - NMSettingsConnection *settings_connection, + NMSettingsConnection *sett_conn, const char *uuid, NMActiveConnectionState max_state, GPtrArray **out_all_matching); @@ -947,7 +949,7 @@ nm_manager_get_active_connections (NMManager *manager) static NMActiveConnection * active_connection_find (NMManager *self, - NMSettingsConnection *settings_connection, + NMSettingsConnection *sett_conn, const char *uuid, NMActiveConnectionState max_state /* candidates in state @max_state will be found */, GPtrArray **out_all_matching) @@ -957,16 +959,18 @@ active_connection_find (NMManager *self, NMActiveConnection *best_ac = NULL; GPtrArray *all = NULL; - nm_assert (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection)); + nm_assert (!sett_conn || NM_IS_SETTINGS_CONNECTION (sett_conn)); nm_assert (!out_all_matching || !*out_all_matching); c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { - NMSettingsConnection *con; + NMSettingsConnection *ac_conn; - con = nm_active_connection_get_settings_connection (ac); - if (settings_connection && con != settings_connection) + ac_conn = nm_active_connection_get_settings_connection (ac); + if ( sett_conn + && sett_conn != ac_conn) continue; - if (uuid && !nm_streq0 (uuid, nm_connection_get_uuid (NM_CONNECTION (con)))) + if ( uuid + && !nm_streq0 (uuid, nm_settings_connection_get_uuid (ac_conn))) continue; if (nm_active_connection_get_state (ac) > max_state) continue; @@ -1005,47 +1009,73 @@ active_connection_find (NMManager *self, static NMActiveConnection * active_connection_find_by_connection (NMManager *self, + NMSettingsConnection *sett_conn, NMConnection *connection, NMActiveConnectionState max_state, GPtrArray **out_all_matching) { - gboolean is_settings_connection; - nm_assert (NM_IS_MANAGER (self)); - nm_assert (NM_IS_CONNECTION (connection)); + nm_assert (!sett_conn || NM_IS_SETTINGS_CONNECTION (sett_conn)); + nm_assert (!connection || NM_IS_CONNECTION (connection)); + nm_assert (sett_conn || connection); + nm_assert (!connection || !sett_conn || connection == nm_settings_connection_get_connection (sett_conn)); - is_settings_connection = NM_IS_SETTINGS_CONNECTION (connection); /* Depending on whether connection is a settings connection, * either lookup by object-identity of @connection, or compare the UUID */ return active_connection_find (self, - is_settings_connection ? NM_SETTINGS_CONNECTION (connection) : NULL, - is_settings_connection ? NULL : nm_connection_get_uuid (connection), + sett_conn, + sett_conn ? NULL : nm_connection_get_uuid (connection), max_state, out_all_matching); } +typedef struct { + NMManager *self; + gboolean for_auto_activation; +} GetActivatableConnectionsFilterData; + static gboolean _get_activatable_connections_filter (NMSettings *settings, - NMSettingsConnection *connection, + NMSettingsConnection *sett_conn, gpointer user_data) { - if (NM_FLAGS_HAS (nm_settings_connection_get_flags (connection), + const GetActivatableConnectionsFilterData *d = user_data; + NMConnectionMultiConnect multi_connect; + + if (NM_FLAGS_HAS (nm_settings_connection_get_flags (sett_conn), NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE)) return FALSE; + multi_connect = _nm_connection_get_multi_connect (nm_settings_connection_get_connection (sett_conn)); + if ( multi_connect == NM_CONNECTION_MULTI_CONNECT_MULTIPLE + || ( multi_connect == NM_CONNECTION_MULTI_CONNECT_MANUAL_MULTIPLE + && !d->for_auto_activation)) + return TRUE; + /* the connection is activatable, if it has no active-connections that are in state * activated, activating, or waiting to be activated. */ - return !active_connection_find (user_data, connection, NULL, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, NULL); + return !active_connection_find (d->self, + sett_conn, + NULL, + NM_ACTIVE_CONNECTION_STATE_ACTIVATED, + NULL); } NMSettingsConnection ** -nm_manager_get_activatable_connections (NMManager *manager, guint *out_len, gboolean sort) +nm_manager_get_activatable_connections (NMManager *manager, + gboolean for_auto_activation, + gboolean sort, + guint *out_len) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); + const GetActivatableConnectionsFilterData d = { + .self = manager, + .for_auto_activation = for_auto_activation, + }; return nm_settings_get_connections_clone (priv->settings, out_len, _get_activatable_connections_filter, - manager, + (gpointer) &d, sort ? nm_settings_connection_cmp_autoconnect_priority_p_with_data : NULL, NULL); } @@ -1056,8 +1086,8 @@ active_connection_get_by_path (NMManager *self, const char *path) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMActiveConnection *ac; - ac = (NMActiveConnection *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), - path); + ac = nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), + path); if ( !ac || !NM_IS_ACTIVE_CONNECTION (ac) || c_list_is_empty (&ac->active_connections_lst)) @@ -1193,8 +1223,8 @@ nm_manager_get_device_by_path (NMManager *self, const char *path) g_return_val_if_fail (path, NULL); - device = (NMDevice *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), - path); + device = nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), + path); if ( !device || !NM_IS_DEVICE (device) || c_list_is_empty (&device->devices_lst)) @@ -1244,7 +1274,7 @@ find_device_by_permanent_hw_addr (NMManager *self, const char *hwaddr) } static NMDevice * -find_device_by_ip_iface (NMManager *self, const gchar *iface) +find_device_by_ip_iface (NMManager *self, const char *iface) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDevice *device; @@ -1290,7 +1320,7 @@ find_device_by_iface (NMManager *self, if (strcmp (nm_device_get_iface (candidate), iface)) continue; - if (connection && !nm_device_check_connection_compatible (candidate, connection)) + if (connection && !nm_device_check_connection_compatible (candidate, connection, NULL)) continue; if (slave) { if (!nm_device_is_master (candidate)) @@ -1459,20 +1489,23 @@ manager_device_state_changed (NMDevice *device, && new_state > NM_DEVICE_STATE_UNMANAGED) retry_connections_for_parent_device (self, device); - switch (new_state) { - case NM_DEVICE_STATE_UNMANAGED: - case NM_DEVICE_STATE_UNAVAILABLE: - case NM_DEVICE_STATE_DISCONNECTED: - case NM_DEVICE_STATE_PREPARE: - case NM_DEVICE_STATE_FAILED: + if (NM_IN_SET (new_state, + NM_DEVICE_STATE_UNMANAGED, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_PREPARE, + NM_DEVICE_STATE_FAILED)) _notify (self, PROP_ACTIVE_CONNECTIONS); - break; - default: - break; - } - if ( new_state == NM_DEVICE_STATE_UNAVAILABLE - || new_state == NM_DEVICE_STATE_DISCONNECTED) + if (NM_IN_SET (new_state, + NM_DEVICE_STATE_UNMANAGED, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_ACTIVATED)) + nm_manager_write_device_state (self, device); + + if (NM_IN_SET (new_state, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_DISCONNECTED)) nm_settings_device_added (priv->settings, device); } @@ -1599,7 +1632,7 @@ remove_device (NMManager *self, nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_REMOVED); nm_device_set_unmanaged_by_flags (device, NM_UNMANAGED_PLATFORM_INIT, TRUE, NM_DEVICE_STATE_REASON_REMOVED); } - } else if (quitting && nm_config_get_configure_and_quit (priv->config)) { + } else if (quitting && nm_config_get_configure_and_quit (priv->config) == NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED) { nm_device_spawn_iface_helper (device); } } @@ -1707,7 +1740,9 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM return candidate; if ( !first_compatible - && nm_device_check_connection_compatible (candidate, NM_CONNECTION (parent_connection))) + && nm_device_check_connection_compatible (candidate, + nm_settings_connection_get_connection (parent_connection), + NULL)) first_compatible = candidate; } @@ -1801,13 +1836,13 @@ const char * nm_manager_iface_for_uuid (NMManager *self, const char *uuid) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMSettingsConnection *connection; + NMSettingsConnection *sett_conn; - connection = nm_settings_get_connection_by_uuid (priv->settings, uuid); - if (!connection) + sett_conn = nm_settings_get_connection_by_uuid (priv->settings, uuid); + if (!sett_conn) return NULL; - return nm_connection_get_interface_name (NM_CONNECTION (connection)); + return nm_connection_get_interface_name (nm_settings_connection_get_connection (sett_conn)); } NMDevice * @@ -1877,7 +1912,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) /* See if there's a device that is already compatible with this connection */ c_list_for_each_entry (dev_candidate, &priv->devices_lst_head, devices_lst) { - if (nm_device_check_connection_compatible (dev_candidate, connection)) { + if (nm_device_check_connection_compatible (dev_candidate, connection, NULL)) { if (nm_device_is_real (dev_candidate)) { _LOG3D (LOGD_DEVICE, connection, "already created virtual interface name %s", iface); @@ -1930,10 +1965,10 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) NULL, NULL, nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; connections[i]; i++) { - NMConnection *candidate = NM_CONNECTION (connections[i]); + NMConnection *candidate = nm_settings_connection_get_connection (connections[i]); NMSettingConnection *s_con; - if (!nm_device_check_connection_compatible (device, candidate)) + if (!nm_device_check_connection_compatible (device, candidate, NULL)) continue; s_con = nm_connection_get_setting_connection (candidate); @@ -1976,18 +2011,19 @@ retry_connections_for_parent_device (NMManager *self, NMDevice *device) NULL, NULL, nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; connections[i]; i++) { - NMConnection *candidate = NM_CONNECTION (connections[i]); + NMSettingsConnection *sett_conn = connections[i]; + NMConnection *connection = nm_settings_connection_get_connection (sett_conn); gs_free_error GError *error = NULL; gs_free char *ifname = NULL; NMDevice *parent; - parent = find_parent_device_for_connection (self, candidate, NULL); + parent = find_parent_device_for_connection (self, connection, NULL); if (parent == device) { /* Only try to activate devices that don't already exist */ - ifname = nm_manager_get_connection_iface (self, candidate, &parent, &error); + ifname = nm_manager_get_connection_iface (self, connection, &parent, &error); if (ifname) { if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, ifname)) - connection_changed (self, candidate); + connection_changed (self, sett_conn); } } } @@ -1995,9 +2031,10 @@ retry_connections_for_parent_device (NMManager *self, NMDevice *device) static void connection_changed (NMManager *self, - NMConnection *connection) + NMSettingsConnection *sett_conn) { NMDevice *device; + NMConnection *connection = nm_settings_connection_get_connection (sett_conn); if (!nm_connection_is_virtual (connection)) return; @@ -2014,20 +2051,20 @@ connection_changed (NMManager *self, static void connection_added_cb (NMSettings *settings, - NMConnection *connection, + NMSettingsConnection *sett_conn, NMManager *self) { - connection_changed (self, connection); + connection_changed (self, sett_conn); } static void connection_updated_cb (NMSettings *settings, - NMConnection *connection, + NMSettingsConnection *sett_conn, gboolean by_user, NMManager *self) { if (by_user) - connection_changed (self, connection); + connection_changed (self, sett_conn); } /*****************************************************************************/ @@ -2370,6 +2407,20 @@ done: g_clear_error (&error); } +static gboolean +new_activation_allowed_for_connection (NMManager *self, + NMSettingsConnection *connection) +{ + if (NM_IN_SET (_nm_connection_get_multi_connect (nm_settings_connection_get_connection (connection)), + NM_CONNECTION_MULTI_CONNECT_MANUAL_MULTIPLE, + NM_CONNECTION_MULTI_CONNECT_MULTIPLE)) + return TRUE; + + return !active_connection_find (self, connection, NULL, + NM_ACTIVE_CONNECTION_STATE_ACTIVATED, + NULL); +} + /** * get_existing_connection: * @manager: #NMManager instance @@ -2386,12 +2437,12 @@ get_existing_connection (NMManager *self, { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); gs_unref_object NMConnection *connection = NULL; - NMSettingsConnection *added = NULL; + NMSettingsConnection *added; GError *error = NULL; gs_free_error GError *gen_error = NULL; NMDevice *master = NULL; int ifindex = nm_device_get_ifindex (device); - NMSettingsConnection *matched; + NMSettingsConnection *matched = NULL; NMSettingsConnection *connection_checked = NULL; gboolean assume_state_guess_assume = FALSE; const char *assume_state_connection_uuid = NULL; @@ -2457,28 +2508,25 @@ get_existing_connection (NMManager *self, */ if ( assume_state_connection_uuid && (connection_checked = nm_settings_get_connection_by_uuid (priv->settings, assume_state_connection_uuid)) - && !active_connection_find (self, connection_checked, NULL, - NM_ACTIVE_CONNECTION_STATE_ACTIVATED, - NULL) - && nm_device_check_connection_compatible (device, NM_CONNECTION (connection_checked))) { + && new_activation_allowed_for_connection (self, connection_checked) + && nm_device_check_connection_compatible (device, + nm_settings_connection_get_connection (connection_checked), + NULL)) { if (connection) { - NMConnection *const connections[] = { - NM_CONNECTION (connection_checked), - NULL, - }; - - matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection (connections, - connection, - TRUE, - nm_device_has_carrier (device), - nm_device_get_route_metric (device, AF_INET), - nm_device_get_route_metric (device, AF_INET6), - NULL, NULL)); + NMConnection *con = nm_settings_connection_get_connection (connection_checked); + + if (nm_utils_match_connection ((NMConnection *[]) { con, NULL }, + connection, + TRUE, + nm_device_has_carrier (device), + nm_device_get_route_metric (device, AF_INET), + nm_device_get_route_metric (device, AF_INET6), + NULL, NULL)) + matched = connection_checked; } else matched = connection_checked; - } else - matched = NULL; + } if (!matched && only_by_uuid) { _LOG2D (LOGD_DEVICE, device, "assume: cannot generate connection: %s", @@ -2487,32 +2535,51 @@ get_existing_connection (NMManager *self, } if (!matched && assume_state_guess_assume) { - gs_free NMSettingsConnection **connections = NULL; + gs_free NMSettingsConnection **sett_conns = NULL; guint len, i, j; /* the state file doesn't indicate a connection UUID to assume. Search the * persistent connections for a matching candidate. */ - connections = nm_manager_get_activatable_connections (self, &len, FALSE); + sett_conns = nm_manager_get_activatable_connections (self, FALSE, FALSE, &len); if (len > 0) { for (i = 0, j = 0; i < len; i++) { - NMConnection *con = NM_CONNECTION (connections[i]); + NMSettingsConnection *sett_conn = sett_conns[i]; - if ( con != NM_CONNECTION (connection_checked) - && nm_device_check_connection_compatible (device, con)) - connections[j++] = connections[i]; + if ( sett_conn != connection_checked + && nm_device_check_connection_compatible (device, + nm_settings_connection_get_connection (sett_conn), + NULL)) + sett_conns[j++] = sett_conn; } - connections[j] = NULL; + sett_conns[j] = NULL; len = j; - g_qsort_with_data (connections, len, sizeof (connections[0]), - nm_settings_connection_cmp_timestamp_p_with_data, NULL); - - matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection ((NMConnection *const*) connections, - connection, - FALSE, - nm_device_has_carrier (device), - nm_device_get_route_metric (device, AF_INET), - nm_device_get_route_metric (device, AF_INET6), - NULL, NULL)); + if (len > 0) { + gs_free NMConnection **conns = NULL; + NMConnection *con; + + g_qsort_with_data (sett_conns, len, sizeof (sett_conns[0]), + nm_settings_connection_cmp_timestamp_p_with_data, NULL); + + conns = nm_settings_connections_array_to_connections (sett_conns, len); + + con = nm_utils_match_connection (conns, + connection, + FALSE, + nm_device_has_carrier (device), + nm_device_get_route_metric (device, AF_INET), + nm_device_get_route_metric (device, AF_INET6), + NULL, + NULL); + if (con) { + for (i = 0; i < len; i++) { + if (conns[i] == con) { + matched = sett_conns[i]; + break; + } + } + nm_assert (matched); + } + } } } @@ -2541,7 +2608,7 @@ get_existing_connection (NMManager *self, return NULL; } - nm_settings_connection_set_flags (NM_SETTINGS_CONNECTION (added), + nm_settings_connection_set_flags (added, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED | NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE, TRUE); @@ -2553,7 +2620,7 @@ static gboolean recheck_assume_connection (NMManager *self, NMDevice *device) { - NMSettingsConnection *connection; + NMSettingsConnection *sett_conn; gboolean was_unmanaged = FALSE; gboolean generated = FALSE; NMDeviceState state; @@ -2575,9 +2642,9 @@ recheck_assume_connection (NMManager *self, return FALSE; } - connection = get_existing_connection (self, device, &generated); + sett_conn = get_existing_connection (self, device, &generated); /* log no reason. get_existing_connection() already does it. */ - if (!connection) + if (!sett_conn) return FALSE; nm_device_sys_iface_state_set (device, @@ -2609,7 +2676,8 @@ recheck_assume_connection (NMManager *self, subject = nm_auth_subject_new_internal (); active = _new_active_connection (self, FALSE, - NM_CONNECTION (connection), + sett_conn, + NULL, NULL, NULL, device, @@ -2620,7 +2688,7 @@ recheck_assume_connection (NMManager *self, if (!active) { _LOGW (LOGD_DEVICE, "assume: assumed connection %s failed to activate: %s", - nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)), + nm_dbus_object_get_path (NM_DBUS_OBJECT (sett_conn)), error->message); g_error_free (error); @@ -2632,7 +2700,7 @@ recheck_assume_connection (NMManager *self, if (generated) { _LOG2D (LOGD_DEVICE, device, "assume: deleting generated connection after assuming failed"); - nm_settings_connection_delete (connection, NULL); + nm_settings_connection_delete (sett_conn, NULL); } else { if (nm_device_sys_iface_state_get (device) == NM_DEVICE_SYS_IFACE_STATE_ASSUME) nm_device_sys_iface_state_set (device, NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); @@ -2642,7 +2710,14 @@ recheck_assume_connection (NMManager *self, /* If the device is a slave or VLAN, find the master ActiveConnection */ master_ac = NULL; - if (find_master (self, NM_CONNECTION (connection), device, NULL, NULL, &master_ac, NULL) && master_ac) + if ( find_master (self, + nm_settings_connection_get_connection (sett_conn), + device, + NULL, + NULL, + &master_ac, + NULL) + && master_ac) nm_active_connection_set_master (active, master_ac); active_connection_add (self, active); @@ -3244,29 +3319,133 @@ nm_manager_get_devices (NMManager *manager) return &NM_MANAGER_GET_PRIVATE (manager)->devices_lst_head; } +typedef enum { + DEVICE_ACTIVATION_PRIO_NONE, + DEVICE_ACTIVATION_PRIO_UNMANAGED, + DEVICE_ACTIVATION_PRIO_UNAVAILABLE, + DEVICE_ACTIVATION_PRIO_DEACTIVATING, + DEVICE_ACTIVATION_PRIO_ACTIVATING, + DEVICE_ACTIVATION_PRIO_ACTIVATED, + DEVICE_ACTIVATION_PRIO_DISCONNECTED, + + _DEVICE_ACTIVATION_PRIO_BEST = DEVICE_ACTIVATION_PRIO_DISCONNECTED, +} DeviceActivationPrio; + +static DeviceActivationPrio +_device_get_activation_prio (NMDevice *device) +{ + if (!nm_device_get_managed (device, TRUE)) + return DEVICE_ACTIVATION_PRIO_NONE; + + switch (nm_device_get_state (device)) { + case NM_DEVICE_STATE_DISCONNECTED: + return DEVICE_ACTIVATION_PRIO_DISCONNECTED; + case NM_DEVICE_STATE_ACTIVATED: + return DEVICE_ACTIVATION_PRIO_ACTIVATED; + case NM_DEVICE_STATE_PREPARE: + case NM_DEVICE_STATE_CONFIG: + case NM_DEVICE_STATE_NEED_AUTH: + case NM_DEVICE_STATE_IP_CONFIG: + case NM_DEVICE_STATE_IP_CHECK: + case NM_DEVICE_STATE_SECONDARIES: + return DEVICE_ACTIVATION_PRIO_ACTIVATING; + case NM_DEVICE_STATE_DEACTIVATING: + case NM_DEVICE_STATE_FAILED: + return DEVICE_ACTIVATION_PRIO_DEACTIVATING; + case NM_DEVICE_STATE_UNAVAILABLE: + return DEVICE_ACTIVATION_PRIO_UNAVAILABLE; + case NM_DEVICE_STATE_UNKNOWN: + case NM_DEVICE_STATE_UNMANAGED: + return DEVICE_ACTIVATION_PRIO_UNMANAGED; + } + + g_return_val_if_reached (DEVICE_ACTIVATION_PRIO_UNAVAILABLE); +} + static NMDevice * nm_manager_get_best_device_for_connection (NMManager *self, + NMSettingsConnection *sett_conn, NMConnection *connection, gboolean for_user_request, - GHashTable *unavailable_devices) + GHashTable *unavailable_devices, + GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMActiveConnectionState ac_state; NMActiveConnection *ac; NMDevice *ac_device; NMDevice *device; + struct { + NMDevice *device; + DeviceActivationPrio prio; + } best = { + .device = NULL, + .prio = DEVICE_ACTIVATION_PRIO_NONE, + }; NMDeviceCheckConAvailableFlags flags; gs_unref_ptrarray GPtrArray *all_ac_arr = NULL; + gs_free_error GError *local_best = NULL; + NMConnectionMultiConnect multi_connect; + + nm_assert (!sett_conn || NM_IS_SETTINGS_CONNECTION (sett_conn)); + nm_assert (!connection || NM_IS_CONNECTION (connection)); + nm_assert (sett_conn || connection); + nm_assert (!connection || !sett_conn || connection == nm_settings_connection_get_connection (sett_conn)); + + if (!connection) + connection = nm_settings_connection_get_connection (sett_conn); + + multi_connect = _nm_connection_get_multi_connect (connection); - flags = for_user_request ? NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST : NM_DEVICE_CHECK_CON_AVAILABLE_NONE; + if (!for_user_request) + flags = NM_DEVICE_CHECK_CON_AVAILABLE_NONE; + else { + /* if the profile is multi-connect=single, we also consider devices which + * are marked as unmanaged. And explicit user-request shows sufficent user + * intent to make the device managed. + * That is also, because we expect that such profile is suitably tied + * to the intended device. So when an unmanaged device matches, the user's + * intent is clear. + * + * For multi-connect != single devices that is different. The profile + * is not restricted to a particular device. + * For that reason, plain `nmcli connection up "$MULIT_PROFILE"` seems + * less suitable for multi-connect profiles, because the target device is + * left unspecified. Anyway, if a user issues + * + * $ nmcli device set "$DEVICE" managed no + * $ nmcli connection up "$MULIT_PROFILE" + * + * then it is reasonable for multi-connect profiles to not consider + * the device a suitable candidate. + * + * This may be seen inconsistent, but I think that it makes a lot of + * sense. Also note that "connection.multi-connect" work quite differently + * in aspects like activation. E.g. `nmcli connection up` of multi-connect + * "single" profile, will deactivate the profile if it is active already. + * That is different from multi-connect profiles, where it will aim to + * activate the profile one more time on an hitherto disconnected device. + */ + if (multi_connect == NM_CONNECTION_MULTI_CONNECT_SINGLE) + flags = NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST; + else + flags = NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST & ~_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_OVERRULE_UNMANAGED; + } - ac = active_connection_find_by_connection (self, connection, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING, &all_ac_arr); - if (ac) { + if ( multi_connect == NM_CONNECTION_MULTI_CONNECT_SINGLE + && (ac = active_connection_find_by_connection (self, sett_conn, connection, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING, &all_ac_arr))) { + /* if we have a profile which may activate on only one device (multi-connect single), then + * we prefer the device on which the profile is already active. It means to reactivate + * the profile on the same device. + * + * If the profile can be activated on multiple devices, we don't do this. In fact, the + * check below for the DeviceActivationPrio will prefer devices which are not already + * activated (with this or another) profile. */ ac_device = nm_active_connection_get_device (ac); if ( ac_device && ( (unavailable_devices && g_hash_table_contains (unavailable_devices, ac_device)) - || !nm_device_check_connection_available (ac_device, connection, flags, NULL))) + || !nm_device_check_connection_available (ac_device, connection, flags, NULL, NULL))) ac_device = NULL; if (all_ac_arr) { @@ -3283,7 +3462,7 @@ nm_manager_get_best_device_for_connection (NMManager *self, if ( !ac_device2 || (unavailable_devices && g_hash_table_contains (unavailable_devices, ac_device2)) - || !nm_device_check_connection_available (ac_device2, connection, flags, NULL)) + || !nm_device_check_connection_available (ac_device2, connection, flags, NULL, NULL)) continue; ac_state2 = nm_active_connection_get_state (ac2); @@ -3331,15 +3510,87 @@ found_better: /* Pick the first device that's compatible with the connection. */ c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { + GError *local = NULL; + DeviceActivationPrio prio; - if (unavailable_devices && g_hash_table_contains (unavailable_devices, device)) + if ( unavailable_devices + && g_hash_table_contains (unavailable_devices, device)) continue; - if (nm_device_check_connection_available (device, connection, flags, NULL)) - return device; + /* determine the priority of this device. Currently this priority is independent + * of the profile (connection) and the device's details (aside the state). + * + * Maybe nm_device_check_connection_available() should instead return a priority, + * as it has more information available. + * + * For example, if you have multiple Wi-Fi devices, currently a user-request would + * also select the device if the AP is not visible. Optimally, if one of the two + * devices sees the AP and the other one doesn't, the former would be preferred. + * For that, the priority would need to be determined by nm_device_check_connection_available(). */ + prio = _device_get_activation_prio (device); + if ( prio <= best.prio + && best.device) { + /* we already have a matching device with a better priority. This candidate + * cannot be better. Skip the check. + * + * Also note, that below we collect the best error message @local_best. + * Since we already have best.device, the error message does not matter + * either, and we can skip nm_device_check_connection_available() altogether. */ + continue; + } + + if (nm_device_check_connection_available (device, + connection, + flags, + NULL, + error ? &local : NULL)) { + if (prio == _DEVICE_ACTIVATION_PRIO_BEST) { + /* this device already has the best priority. It cannot get better + * and finish the search. */ + return device; + } + best.prio = prio; + best.device = device; + continue; + } + + if (error) { + gboolean reset_error; + + if (!local_best) + reset_error = TRUE; + else if (local_best->domain != NM_UTILS_ERROR) + reset_error = (local->domain == NM_UTILS_ERROR); + else { + reset_error = ( local->domain == NM_UTILS_ERROR + && local_best->code < local->code); + } + + if (reset_error) { + g_clear_error (&local_best); + g_set_error (&local_best, + local->domain, + local->code, + "device %s not available because %s", + nm_device_get_iface (device), + local->message); + } + g_error_free (local); + } } - /* No luck. :( */ + if (best.device) + return best.device; + + if (error) { + if (local_best) + g_propagate_error (error, g_steal_pointer (&local_best)); + else { + nm_utils_error_set_literal (error, + NM_UTILS_ERROR_UNKNOWN, + "no suitable device found"); + } + } return NULL; } @@ -3508,7 +3759,7 @@ find_master (NMManager *self, NMSettingConnection *s_con; const char *master; NMDevice *master_device = NULL; - NMSettingsConnection *master_connection = NULL; + NMSettingsConnection *master_connection; s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); @@ -3527,7 +3778,9 @@ find_master (NMManager *self, } master_connection = nm_device_get_settings_connection (master_device); - if (master_connection && !is_compatible_with_slave (NM_CONNECTION (master_connection), connection)) { + if ( master_connection + && !is_compatible_with_slave (nm_settings_connection_get_connection (master_connection), + connection)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, "The active connection on %s is not compatible", nm_device_get_iface (master_device)); @@ -3627,7 +3880,9 @@ ensure_master_active_connection (NMManager *self, * be already activated on the device, eg returned from find_master(). */ g_assert (!master_connection || master_connection == device_connection); - if (device_connection && !is_compatible_with_slave (NM_CONNECTION (device_connection), connection)) { + if ( device_connection + && !is_compatible_with_slave (nm_settings_connection_get_connection (device_connection), + connection)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, "The active connection %s is not compatible", nm_connection_get_id (connection)); @@ -3652,17 +3907,22 @@ ensure_master_active_connection (NMManager *self, g_assert (master_connection == NULL); /* Find a compatible connection and activate this device using it */ - connections = nm_manager_get_activatable_connections (self, NULL, TRUE); + connections = nm_manager_get_activatable_connections (self, FALSE, TRUE, NULL); for (i = 0; connections[i]; i++) { NMSettingsConnection *candidate = connections[i]; + NMConnection *cand_conn = nm_settings_connection_get_connection (candidate); /* Ensure eg bond/team slave and the candidate master is a * bond/team master */ - if (!is_compatible_with_slave (NM_CONNECTION (candidate), connection)) + if (!is_compatible_with_slave (cand_conn, connection)) continue; - if (nm_device_check_connection_available (master_device, NM_CONNECTION (candidate), NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) { + if (nm_device_check_connection_available (master_device, + cand_conn, + NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, + NULL, + NULL)) { master_ac = nm_manager_activate_connection (self, candidate, NULL, @@ -3698,7 +3958,11 @@ ensure_master_active_connection (NMManager *self, continue; } - if (!nm_device_check_connection_available (candidate, NM_CONNECTION (master_connection), NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) + if (!nm_device_check_connection_available (candidate, + nm_settings_connection_get_connection (master_connection), + NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, + NULL, + NULL)) continue; if (!nm_device_is_software (candidate)) { @@ -3737,18 +4001,18 @@ typedef struct { /** * find_slaves: * @manager: #NMManager object - * @connection: the master #NMSettingsConnection to find slave connections for - * @device: the master #NMDevice for the @connection + * @sett_conn: the master #NMSettingsConnection to find slave connections for + * @device: the master #NMDevice for the @sett_conn * @out_n_slaves: on return, the number of slaves found * - * Given an #NMSettingsConnection, attempts to find its slaves. If @connection is not + * Given an #NMSettingsConnection, attempts to find its slaves. If @sett_conn is not * master, or has not any slaves, this will return %NULL. * - * Returns: an array of #SlaveConnectionInfo for given master @connection, or %NULL + * Returns: an array of #SlaveConnectionInfo for given master @sett_conn, or %NULL **/ static SlaveConnectionInfo * find_slaves (NMManager *manager, - NMSettingsConnection *connection, + NMSettingsConnection *sett_conn, NMDevice *device, guint *out_n_slaves) { @@ -3763,7 +4027,7 @@ find_slaves (NMManager *manager, nm_assert (out_n_slaves); - s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); + s_con = nm_connection_get_setting_connection (nm_settings_connection_get_connection (sett_conn)); g_return_val_if_fail (s_con, NULL); devices = g_hash_table_new (nm_direct_hash, NULL); @@ -3778,15 +4042,23 @@ find_slaves (NMManager *manager, for (i = 0; i < n_all_connections; i++) { NMSettingsConnection *master_connection = NULL; NMDevice *master_device = NULL, *slave_device; - NMConnection *candidate = NM_CONNECTION (all_connections[i]); - - find_master (manager, candidate, NULL, &master_connection, &master_device, NULL, NULL); - if ( (master_connection && master_connection == connection) + NMSettingsConnection *candidate = all_connections[i]; + + find_master (manager, + nm_settings_connection_get_connection (candidate), + NULL, + &master_connection, + &master_device, + NULL, + NULL); + if ( (master_connection && master_connection == sett_conn) || (master_device && master_device == device)) { slave_device = nm_manager_get_best_device_for_connection (manager, candidate, + NULL, FALSE, - devices); + devices, + NULL); if (!slaves) { /* what we allocate is quite likely much too large. Don't bother, it is only @@ -3795,7 +4067,7 @@ find_slaves (NMManager *manager, } nm_assert (n_slaves < n_all_connections); - slaves[n_slaves].connection = NM_SETTINGS_CONNECTION (candidate), + slaves[n_slaves].connection = candidate, slaves[n_slaves].device = slave_device, n_slaves++; @@ -3814,32 +4086,29 @@ static gboolean should_connect_slaves (NMConnection *connection, NMDevice *device) { NMSettingConnection *s_con; - NMSettingConnectionAutoconnectSlaves autoconnect_slaves; - gs_free char *value = NULL; + NMSettingConnectionAutoconnectSlaves val; s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); - /* Check autoconnect-slaves property */ - autoconnect_slaves = nm_setting_connection_get_autoconnect_slaves (s_con); - if (autoconnect_slaves != NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT) + val = nm_setting_connection_get_autoconnect_slaves (s_con); + if (val != NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT) goto out; - /* Check configuration default for autoconnect-slaves property */ - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "connection.autoconnect-slaves", device); - if (value) - autoconnect_slaves = _nm_utils_ascii_str_to_int64 (value, 10, 0, 1, -1); + val = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "connection.autoconnect-slaves", + device, + 0, 1, -1); out: - if (autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_NO) + if (val == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_NO) return FALSE; - if (autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_YES) + if (val == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_YES) return TRUE; return FALSE; } -static gint +static int compare_slaves (gconstpointer a, gconstpointer b, gpointer sort_by_name) { const SlaveConnectionInfo *a_info = a; @@ -3867,7 +4136,8 @@ autoconnect_slaves (NMManager *self, { GError *local_err = NULL; - if (should_connect_slaves (NM_CONNECTION (master_connection), master_device)) { + if (should_connect_slaves (nm_settings_connection_get_connection (master_connection), + master_device)) { gs_free SlaveConnectionInfo *slaves = NULL; guint i, n_slaves = 0; @@ -4008,7 +4278,7 @@ active_connection_parent_active (NMActiveConnection *active, { NMDevice *device = nm_active_connection_get_device (active); GError *error = NULL; - NMSettingsConnection *connection; + NMSettingsConnection *sett_conn; NMDevice *parent; g_signal_handlers_disconnect_by_func (active, @@ -4024,10 +4294,13 @@ active_connection_parent_active (NMActiveConnection *active, return; } - connection = nm_active_connection_get_settings_connection (active); + sett_conn = nm_active_connection_get_settings_connection (active); parent = nm_active_connection_get_device (parent_ac); - if (!nm_device_create_and_realize (device, (NMConnection *) connection, parent, &error)) { + if (!nm_device_create_and_realize (device, + nm_settings_connection_get_connection (sett_conn), + parent, + &error)) { _LOGW (LOGD_CORE, "Could not realize device '%s': %s", nm_device_get_iface (device), error->message); nm_active_connection_set_state_fail (active, @@ -4045,11 +4318,13 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * { NMDevice *device, *master_device = NULL; NMConnection *applied; - NMSettingsConnection *connection; + NMSettingsConnection *sett_conn; NMSettingsConnection *master_connection = NULL; NMConnection *existing_connection = NULL; NMActiveConnection *master_ac = NULL; NMAuthSubject *subject; + GError *local = NULL; + NMConnectionMultiConnect multi_connect; g_return_val_if_fail (NM_IS_MANAGER (self), FALSE); g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (active), FALSE); @@ -4060,8 +4335,8 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * device = nm_active_connection_get_device (active); g_return_val_if_fail (device != NULL, FALSE); - connection = nm_active_connection_get_settings_connection (active); - nm_assert (connection); + sett_conn = nm_active_connection_get_settings_connection (active); + nm_assert (sett_conn); applied = nm_active_connection_get_applied_connection (active); @@ -4083,10 +4358,13 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * } /* Final connection must be available on device */ - if (!nm_device_check_connection_available (device, applied, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) { + if (!nm_device_check_connection_available (device, applied, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL, &local)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, - "Connection '%s' is not available on the device %s at this time.", - nm_settings_connection_get_id (connection), nm_device_get_iface (device)); + "Connection '%s' is not available on device %s because %s", + nm_settings_connection_get_id (sett_conn), + nm_device_get_iface (device), + local->message); + g_error_free (local); return FALSE; } @@ -4097,7 +4375,9 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * if (!nm_device_is_real (device)) { NMDevice *parent; - parent = find_parent_device_for_connection (self, (NMConnection *) connection, NULL); + parent = find_parent_device_for_connection (self, + nm_settings_connection_get_connection (sett_conn), + NULL); if (parent && !nm_device_is_real (parent)) { NMSettingsConnection *parent_con; @@ -4109,7 +4389,11 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * return FALSE; } - parent_ac = nm_manager_activate_connection (self, parent_con, NULL, NULL, parent, + parent_ac = nm_manager_activate_connection (self, + parent_con, + NULL, + NULL, + parent, subject, NM_ACTIVATION_TYPE_MANAGED, nm_active_connection_get_activation_reason (active), @@ -4127,7 +4411,10 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * nm_active_connection_set_parent (active, parent_ac); } else { /* We can realize now; no need to wait for a parent device. */ - if (!nm_device_create_and_realize (device, (NMConnection *) connection, parent, error)) { + if (!nm_device_create_and_realize (device, + nm_settings_connection_get_connection (sett_conn), + parent, + error)) { g_prefix_error (error, "%s failed to create resources: ", nm_device_get_iface (device)); return FALSE; } @@ -4135,11 +4422,15 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * } /* Try to find the master connection/device if the connection has a dependency */ - if (!find_master (self, applied, device, - &master_connection, &master_device, &master_ac, + if (!find_master (self, + applied, + device, + &master_connection, + &master_device, + &master_ac, error)) { g_prefix_error (error, "Can not find a master for %s: ", - nm_settings_connection_get_id (connection)); + nm_settings_connection_get_id (sett_conn)); return FALSE; } @@ -4149,21 +4440,23 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * if (master_connection || master_device) { if (master_connection) { _LOGD (LOGD_CORE, "Activation of '%s' requires master connection '%s'", - nm_settings_connection_get_id (connection), + nm_settings_connection_get_id (sett_conn), nm_settings_connection_get_id (master_connection)); } if (master_device) { _LOGD (LOGD_CORE, "Activation of '%s' requires master device '%s'", - nm_settings_connection_get_id (connection), + nm_settings_connection_get_id (sett_conn), nm_device_get_ip_iface (master_device)); } /* Ensure eg bond slave and the candidate master is a bond master */ - if (master_connection && !is_compatible_with_slave (NM_CONNECTION (master_connection), applied)) { + if ( master_connection + && !is_compatible_with_slave (nm_settings_connection_get_connection (master_connection), + applied)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, "The master connection '%s' is not compatible with '%s'", nm_settings_connection_get_id (master_connection), - nm_settings_connection_get_id (connection)); + nm_settings_connection_get_id (sett_conn)); return FALSE; } @@ -4182,7 +4475,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * nm_device_get_ip_iface (device)); } else { g_prefix_error (error, "Master connection '%s' can't be activated: ", - nm_settings_connection_get_id (connection)); + nm_settings_connection_get_id (sett_conn)); } return FALSE; } @@ -4199,22 +4492,30 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * nm_active_connection_set_master (active, master_ac); _LOGD (LOGD_CORE, "Activation of '%s' depends on active connection %p %s", - nm_settings_connection_get_id (connection), + nm_settings_connection_get_id (sett_conn), master_ac, nm_dbus_object_get_path (NM_DBUS_OBJECT (master_ac)) ?: ""); } /* Check slaves for master connection and possibly activate them */ - autoconnect_slaves (self, connection, device, nm_active_connection_get_subject (active)); - - { + autoconnect_slaves (self, sett_conn, device, nm_active_connection_get_subject (active)); + + multi_connect = _nm_connection_get_multi_connect (nm_settings_connection_get_connection (sett_conn)); + if ( multi_connect == NM_CONNECTION_MULTI_CONNECT_MULTIPLE + || ( multi_connect == NM_CONNECTION_MULTI_CONNECT_MANUAL_MULTIPLE + && NM_IN_SET (nm_active_connection_get_activation_reason (active), + NM_ACTIVATION_REASON_ASSUME, + NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES, + NM_ACTIVATION_REASON_USER_REQUEST))) { + /* the profile can be activated multiple times. Proceed. */ + } else { gs_unref_ptrarray GPtrArray *all_ac_arr = NULL; NMActiveConnection *ac; guint i, n_all; /* Disconnect the connection if already connected or queued for activation. * The connection cannot be active multiple times (at the same time). */ - ac = active_connection_find (self, connection, NULL, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, + ac = active_connection_find (self, sett_conn, NULL, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, &all_ac_arr); if (ac) { n_all = all_ac_arr ? all_ac_arr->len : ((guint) 1); @@ -4277,7 +4578,7 @@ _internal_activate_generic (NMManager *self, NMActiveConnection *active, GError * is exported, make sure the manager's activating-connection property * is up-to-date. */ - policy_activating_device_changed (G_OBJECT (priv->policy), NULL, self); + policy_activating_ac_changed (G_OBJECT (priv->policy), NULL, self); } return success; @@ -4286,7 +4587,8 @@ _internal_activate_generic (NMManager *self, NMActiveConnection *active, GError static NMActiveConnection * _new_active_connection (NMManager *self, gboolean is_vpn, - NMConnection *connection, + NMSettingsConnection *sett_conn, + NMConnection *incompl_conn, NMConnection *applied, const char *specific_object, NMDevice *device, @@ -4296,18 +4598,19 @@ _new_active_connection (NMManager *self, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMSettingsConnection *settings_connection = NULL; NMDevice *parent_device; - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); - - nm_assert (is_vpn == _connection_is_vpn (connection)); + nm_assert (!sett_conn || NM_IS_SETTINGS_CONNECTION (sett_conn)); + nm_assert (!incompl_conn || NM_IS_CONNECTION (incompl_conn)); + nm_assert ((!incompl_conn) ^ (!sett_conn)); + nm_assert (NM_IS_AUTH_SUBJECT (subject)); + nm_assert (is_vpn == _connection_is_vpn (sett_conn + ? nm_settings_connection_get_connection (sett_conn) + : incompl_conn)); nm_assert (is_vpn || NM_IS_DEVICE (device)); nm_assert (!nm_streq0 (specific_object, "/")); - - if (NM_IS_SETTINGS_CONNECTION (connection)) - settings_connection = (NMSettingsConnection *) connection; + nm_assert (!applied || NM_IS_CONNECTION (applied)); + nm_assert (!is_vpn || !applied); if (is_vpn) { NMActiveConnection *parent; @@ -4315,21 +4618,20 @@ _new_active_connection (NMManager *self, /* FIXME: for VPN connections, we don't allow re-activating an * already active connection. It's a bug, and should be fixed together * when reworking VPN handling. */ - if (active_connection_find_by_connection (self, connection, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, NULL)) { + if (active_connection_find_by_connection (self, + sett_conn, + incompl_conn, + NM_ACTIVE_CONNECTION_STATE_ACTIVATED, + NULL)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_ALREADY_ACTIVE, "Connection '%s' is already active", - nm_connection_get_id (connection)); + sett_conn ? nm_settings_connection_get_id (sett_conn) : nm_connection_get_id (incompl_conn)); return NULL; } - /* FIXME: apparently, activation here only works if @connection is - * a settings-connection. Which is not the case during AddAndActivatate. - * Probably, AddAndActivate is broken for VPN. */ if (activation_type != NM_ACTIVATION_TYPE_MANAGED) g_return_val_if_reached (NULL); - g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); - if (specific_object) { /* Find the specific connection the client requested we use */ parent = active_connection_get_by_path (self, specific_object); @@ -4360,14 +4662,14 @@ _new_active_connection (NMManager *self, return NULL; } - return (NMActiveConnection *) nm_vpn_connection_new (settings_connection, + return (NMActiveConnection *) nm_vpn_connection_new (sett_conn, parent_device, nm_dbus_object_get_path (NM_DBUS_OBJECT (parent)), activation_reason, subject); } - return (NMActiveConnection *) nm_act_request_new (settings_connection, + return (NMActiveConnection *) nm_act_request_new (sett_conn, applied, specific_object, subject, @@ -4428,17 +4730,17 @@ fail: /** * nm_manager_activate_connection(): * @self: the #NMManager - * @connection: the #NMSettingsConnection to activate on @device + * @sett_conn: the #NMSettingsConnection to activate on @device * @applied: (allow-none): the applied connection to activate on @device * @specific_object: the specific object path, if any, for the activation - * @device: the #NMDevice to activate @connection on. Can be %NULL for VPNs. + * @device: the #NMDevice to activate @sett_conn on. Can be %NULL for VPNs. * @subject: the subject which requested activation * @activation_type: whether to assume the connection. That is, take over gracefully, * non-destructible. * @activation_reason: the reason for activation * @error: return location for an error * - * Begins a new internally-initiated activation of @connection on @device. + * Begins a new internally-initiated activation of @sett_conn on @device. * @subject should be the subject of the activation that triggered this * one, or if this is an autoconnect request, a new internal subject. * The returned #NMActiveConnection is owned by the Manager and should be @@ -4446,11 +4748,11 @@ fail: * is supplied, it shall not be modified by the caller afterwards. * * Returns: (transfer none): the new #NMActiveConnection that tracks - * activation of @connection on @device + * activation of @sett_conn on @device */ NMActiveConnection * nm_manager_activate_connection (NMManager *self, - NMSettingsConnection *connection, + NMSettingsConnection *sett_conn, NMConnection *applied, const char *specific_object, NMDevice *device, @@ -4465,15 +4767,15 @@ nm_manager_activate_connection (NMManager *self, gboolean is_vpn; g_return_val_if_fail (NM_IS_MANAGER (self), NULL); - g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (connection), NULL); - is_vpn = _connection_is_vpn (NM_CONNECTION (connection)); + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (sett_conn), NULL); + is_vpn = _connection_is_vpn (nm_settings_connection_get_connection (sett_conn)); g_return_val_if_fail (is_vpn || NM_IS_DEVICE (device), NULL); g_return_val_if_fail (!error || !*error, NULL); nm_assert (!nm_streq0 (specific_object, "/")); priv = NM_MANAGER_GET_PRIVATE (self); - if (!nm_auth_is_subject_in_acl_set_error (NM_CONNECTION (connection), + if (!nm_auth_is_subject_in_acl_set_error (nm_settings_connection_get_connection (sett_conn), subject, NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, @@ -4491,7 +4793,7 @@ nm_manager_activate_connection (NMManager *self, continue; active = async_op_data->ac_auth.active; - if ( connection == nm_active_connection_get_settings_connection (active) + if ( sett_conn == nm_active_connection_get_settings_connection (active) && nm_streq0 (nm_active_connection_get_specific_object (active), specific_object) && (!device || nm_active_connection_get_device (active) == device) && nm_auth_subject_is_internal (nm_active_connection_get_subject (active)) @@ -4502,7 +4804,8 @@ nm_manager_activate_connection (NMManager *self, active = _new_active_connection (self, is_vpn, - NM_CONNECTION (connection), + sett_conn, + NULL, applied, specific_object, device, @@ -4525,7 +4828,9 @@ nm_manager_activate_connection (NMManager *self, * validate_activation_request: * @self: the #NMManager * @context: the D-Bus context of the requestor - * @connection: the partial or complete #NMConnection to be activated + * @sett_conn: the #NMSettingsConnection to be activated, or %NULL if there + * is only a partial activation. + * @connection: the partial #NMConnection to be activated (if @sett_conn is unspecified) * @device_path: the object path of the device to be activated, or NULL * @out_device: on successful reutrn, the #NMDevice to be activated with @connection * The caller may pass in a device which shortcuts the lookup by path. @@ -4544,6 +4849,7 @@ nm_manager_activate_connection (NMManager *self, static NMAuthSubject * validate_activation_request (NMManager *self, GDBusMethodInvocation *context, + NMSettingsConnection *sett_conn, NMConnection *connection, const char *device_path, NMDevice **out_device, @@ -4554,10 +4860,16 @@ validate_activation_request (NMManager *self, gboolean is_vpn = FALSE; gs_unref_object NMAuthSubject *subject = NULL; - nm_assert (NM_IS_CONNECTION (connection)); + nm_assert (!sett_conn || NM_IS_SETTINGS_CONNECTION (sett_conn)); + nm_assert (!connection || NM_IS_CONNECTION (connection)); + nm_assert (sett_conn || connection); + nm_assert (!connection || !sett_conn || connection == nm_settings_connection_get_connection (sett_conn)); nm_assert (out_device); nm_assert (out_is_vpn); + if (!connection) + connection = nm_settings_connection_get_connection (sett_conn); + /* Validate the caller */ subject = nm_auth_subject_new_unix_process_from_context (context); if (!subject) { @@ -4593,17 +4905,20 @@ validate_activation_request (NMManager *self, return NULL; } } else if (!is_vpn) { - device = nm_manager_get_best_device_for_connection (self, connection, TRUE, NULL); + gs_free_error GError *local = NULL; + + device = nm_manager_get_best_device_for_connection (self, sett_conn, connection, TRUE, NULL, &local); if (!device) { gs_free char *iface = NULL; /* VPN and software-device connections don't need a device yet, * but non-virtual connections do ... */ if (!nm_connection_is_virtual (connection)) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "No suitable device found for this connection."); + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "No suitable device found for this connection (%s).", + local->message); return NULL; } @@ -4689,7 +5004,7 @@ impl_manager_activate_connection (NMDBusObject *obj, NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); gs_unref_object NMActiveConnection *active = NULL; gs_unref_object NMAuthSubject *subject = NULL; - NMSettingsConnection *connection = NULL; + NMSettingsConnection *sett_conn = NULL; NMDevice *device = NULL; gboolean is_vpn = FALSE; GError *error = NULL; @@ -4709,8 +5024,8 @@ impl_manager_activate_connection (NMDBusObject *obj, * (since this is an explicit request, not an auto-activation request). */ if (connection_path) { - connection = nm_settings_get_connection_by_path (priv->settings, connection_path); - if (!connection) { + sett_conn = nm_settings_get_connection_by_path (priv->settings, connection_path); + if (!sett_conn) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, "Connection could not be found."); @@ -4730,14 +5045,15 @@ impl_manager_activate_connection (NMDBusObject *obj, goto error; } - connection = nm_device_get_best_connection (device, specific_object_path, &error); - if (!connection) + sett_conn = nm_device_get_best_connection (device, specific_object_path, &error); + if (!sett_conn) goto error; } subject = validate_activation_request (self, invocation, - NM_CONNECTION (connection), + sett_conn, + NULL, device_path, &device, &is_vpn, @@ -4747,7 +5063,8 @@ impl_manager_activate_connection (NMDBusObject *obj, active = _new_active_connection (self, is_vpn, - NM_CONNECTION (connection), + sett_conn, + NULL, NULL, specific_object_path, device, @@ -4771,8 +5088,8 @@ impl_manager_activate_connection (NMDBusObject *obj, return; error: - if (connection) { - nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, FALSE, NULL, + if (sett_conn) { + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, sett_conn, FALSE, NULL, subject, error->message); } g_dbus_method_invocation_take_error (invocation, error); @@ -4887,7 +5204,7 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, { NMManager *self = NM_MANAGER (obj); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - gs_unref_object NMConnection *connection = NULL; + gs_unref_object NMConnection *incompl_conn = NULL; NMActiveConnection *active = NULL; gs_unref_object NMAuthSubject *subject = NULL; GError *error = NULL; @@ -4896,6 +5213,7 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, gs_unref_variant GVariant *settings = NULL; const char *device_path; const char *specific_object_path; + gs_free NMConnection **conns = NULL; g_variant_get (parameters, "(@a{sa{sv}}&o&o)", &settings, &device_path, &specific_object_path); @@ -4909,13 +5227,14 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, * specific data being in the connection till then (especially in * validate_activation_request()). */ - connection = nm_simple_connection_new (); + incompl_conn = nm_simple_connection_new (); if (settings && g_variant_n_children (settings)) - _nm_connection_replace_settings (connection, settings, NM_SETTING_PARSE_FLAGS_STRICT, NULL); + _nm_connection_replace_settings (incompl_conn, settings, NM_SETTING_PARSE_FLAGS_STRICT, NULL); subject = validate_activation_request (self, invocation, - connection, + NULL, + incompl_conn, device_path, &device, &is_vpn, @@ -4925,7 +5244,7 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, if (is_vpn) { /* Try to fill the VPN's connection setting and name at least */ - if (!nm_connection_get_setting_vpn (connection)) { + if (!nm_connection_get_setting_vpn (incompl_conn)) { error = g_error_new_literal (NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_SETTING, "VPN connections require a 'vpn' setting"); @@ -4933,27 +5252,31 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, goto error; } + conns = nm_settings_connections_array_to_connections (nm_settings_get_connections (priv->settings, NULL), -1); + nm_utils_complete_generic (priv->platform, - connection, + incompl_conn, NM_SETTING_VPN_SETTING_NAME, - (NMConnection *const*) nm_settings_get_connections (priv->settings, NULL), + conns, NULL, _("VPN connection"), NULL, FALSE); /* No IPv6 by default for now */ } else { + conns = nm_settings_connections_array_to_connections (nm_settings_get_connections (priv->settings, NULL), -1); /* Let each device subclass complete the connection */ if (!nm_device_complete_connection (device, - connection, + incompl_conn, specific_object_path, - (NMConnection *const*) nm_settings_get_connections (priv->settings, NULL), + conns, &error)) goto error; } active = _new_active_connection (self, is_vpn, - connection, + NULL, + incompl_conn, NULL, specific_object_path, device, @@ -4964,15 +5287,16 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, if (!active) goto error; - nm_active_connection_authorize (active, connection, + nm_active_connection_authorize (active, + incompl_conn, _async_op_complete_ac_auth_cb, _async_op_data_new_ac_auth_add_and_activate (self, active, invocation, - connection)); + incompl_conn)); /* we passed the pointers on to _async_op_data_new_ac_auth_add_and_activate() */ - g_steal_pointer (&connection); + g_steal_pointer (&incompl_conn); g_steal_pointer (&active); return; @@ -5089,7 +5413,7 @@ impl_manager_deactivate_connection (NMDBusObject *obj, NMManager *self = NM_MANAGER (obj); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMActiveConnection *ac; - NMSettingsConnection *connection = NULL; + NMSettingsConnection *sett_conn = NULL; GError *error = NULL; NMAuthSubject *subject = NULL; NMAuthChain *chain; @@ -5100,9 +5424,9 @@ impl_manager_deactivate_connection (NMDBusObject *obj, /* Find the connection by its object path */ ac = active_connection_get_by_path (self, active_path); if (ac) - connection = nm_active_connection_get_settings_connection (ac); + sett_conn = nm_active_connection_get_settings_connection (ac); - if (!connection) { + if (!sett_conn) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE, "The connection was not active."); @@ -5118,7 +5442,7 @@ impl_manager_deactivate_connection (NMDBusObject *obj, goto done; } - if (!nm_auth_is_subject_in_acl_set_error (NM_CONNECTION (connection), + if (!nm_auth_is_subject_in_acl_set_error (nm_settings_connection_get_connection (sett_conn), subject, NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, @@ -5140,8 +5464,9 @@ impl_manager_deactivate_connection (NMDBusObject *obj, done: if (error) { - if (connection) { - nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DEACTIVATE, connection, FALSE, NULL, + if (sett_conn) { + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DEACTIVATE, + sett_conn, FALSE, NULL, subject, error->message); } g_dbus_method_invocation_take_error (invocation, error); @@ -5890,66 +6215,84 @@ start_factory (NMDeviceFactory *factory, gpointer user_data) nm_device_factory_start (factory); } -void -nm_manager_write_device_state (NMManager *self) +gboolean +nm_manager_write_device_state (NMManager *self, NMDevice *device) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *device; - gs_unref_hashtable GHashTable *seen_ifindexes = NULL; - gint nm_owned; + int ifindex; + gboolean managed; + NMConfigDeviceStateManagedType managed_type; + const char *uuid = NULL; + const char *perm_hw_addr_fake = NULL; + gboolean perm_hw_addr_is_fake; + guint32 route_metric_default_aspired; + guint32 route_metric_default_effective; + int nm_owned; + NMDhcp4Config *dhcp4_config; + const char *root_path = NULL; + + ifindex = nm_device_get_ip_ifindex (device); + if (ifindex <= 0) + return FALSE; + if (ifindex == 1) { + /* ignore loopback */ + return FALSE; + } - seen_ifindexes = g_hash_table_new (nm_direct_hash, NULL); + if (!nm_platform_link_get (priv->platform, ifindex)) + return FALSE; - c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { - int ifindex; - gboolean managed; - NMConfigDeviceStateManagedType managed_type; - NMConnection *settings_connection; - const char *uuid = NULL; - const char *perm_hw_addr_fake = NULL; - gboolean perm_hw_addr_is_fake; - guint32 route_metric_default_aspired; - guint32 route_metric_default_effective; - - ifindex = nm_device_get_ip_ifindex (device); - if (ifindex <= 0) - continue; - if (ifindex == 1) { - /* ignore loopback */ - continue; - } + managed = nm_device_get_managed (device, FALSE); + if (managed) { + NMSettingsConnection *sett_conn = NULL; + + if (nm_device_get_state (device) <= NM_DEVICE_STATE_ACTIVATED) + sett_conn = nm_device_get_settings_connection (device); + if (sett_conn) + uuid = nm_settings_connection_get_uuid (sett_conn); + managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED; + } else if (nm_device_get_unmanaged_flags (device, NM_UNMANAGED_USER_EXPLICIT)) + managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED; + else + managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNKNOWN; - if (!nm_platform_link_get (priv->platform, ifindex)) - continue; + perm_hw_addr_fake = nm_device_get_permanent_hw_address_full (device, FALSE, &perm_hw_addr_is_fake); + if (perm_hw_addr_fake && !perm_hw_addr_is_fake) + perm_hw_addr_fake = NULL; - managed = nm_device_get_managed (device, FALSE); - if (managed) { - settings_connection = NM_CONNECTION (nm_device_get_settings_connection (device)); - if (settings_connection) - uuid = nm_connection_get_uuid (settings_connection); - managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_MANAGED; - } else if (nm_device_get_unmanaged_flags (device, NM_UNMANAGED_USER_EXPLICIT)) - managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED; - else - managed_type = NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNKNOWN; + nm_owned = nm_device_is_software (device) ? nm_device_is_nm_owned (device) : -1; + + route_metric_default_effective = _device_route_metric_get (self, ifindex, NM_DEVICE_TYPE_UNKNOWN, + TRUE, &route_metric_default_aspired); + + dhcp4_config = nm_device_get_dhcp4_config (device); + if (dhcp4_config) + root_path = nm_dhcp4_config_get_option (dhcp4_config, "root_path"); - perm_hw_addr_fake = nm_device_get_permanent_hw_address_full (device, FALSE, &perm_hw_addr_is_fake); - if (perm_hw_addr_fake && !perm_hw_addr_is_fake) - perm_hw_addr_fake = NULL; + return nm_config_device_state_write (ifindex, + managed_type, + perm_hw_addr_fake, + uuid, + nm_owned, + route_metric_default_aspired, + route_metric_default_effective, + root_path); +} - nm_owned = nm_device_is_software (device) ? nm_device_is_nm_owned (device) : -1; +void +nm_manager_write_device_state_all (NMManager *self) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + gs_unref_hashtable GHashTable *seen_ifindexes = NULL; + NMDevice *device; - route_metric_default_effective = _device_route_metric_get (self, ifindex, NM_DEVICE_TYPE_UNKNOWN, - TRUE, &route_metric_default_aspired); + seen_ifindexes = g_hash_table_new (nm_direct_hash, NULL); - if (nm_config_device_state_write (ifindex, - managed_type, - perm_hw_addr_fake, - uuid, - nm_owned, - route_metric_default_aspired, - route_metric_default_effective)) - g_hash_table_add (seen_ifindexes, GINT_TO_POINTER (ifindex)); + c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { + if (nm_manager_write_device_state (self, device)) { + g_hash_table_add (seen_ifindexes, + GINT_TO_POINTER (nm_device_get_ip_ifindex (device))); + } } nm_config_device_state_prune_unseen (seen_ifindexes); @@ -6029,7 +6372,7 @@ nm_manager_start (NMManager *self, GError **error) NULL, NULL, nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; connections[i]; i++) - connection_changed (self, NM_CONNECTION (connections[i])); + connection_changed (self, connections[i]); nm_clear_g_source (&priv->devices_inited_id); priv->devices_inited_id = g_idle_add_full (G_PRIORITY_LOW + 10, devices_inited_cb, self, NULL); @@ -6129,25 +6472,19 @@ connection_metered_changed (GObject *object, } static void -policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data) +policy_default_ac_changed (GObject *object, GParamSpec *pspec, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *best; NMActiveConnection *ac; /* Note: this assumes that it's not possible for the IP4 default * route to be going over the default-ip6-device. If that changes, * we need something more complicated here. */ - best = nm_policy_get_default_ip4_device (priv->policy); - if (!best) - best = nm_policy_get_default_ip6_device (priv->policy); - - if (best) - ac = NM_ACTIVE_CONNECTION (nm_device_get_act_request (best)); - else - ac = NULL; + ac = nm_policy_get_default_ip4_ac (priv->policy); + if (!ac) + ac = nm_policy_get_default_ip6_ac (priv->policy); if (ac != priv->primary_connection) { if (priv->primary_connection) { @@ -6160,10 +6497,12 @@ policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user priv->primary_connection = ac ? g_object_ref (ac) : NULL; if (priv->primary_connection) { - g_signal_connect (priv->primary_connection, NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED, + g_signal_connect (priv->primary_connection, + NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED, G_CALLBACK (connection_metered_changed), self); } - _LOGD (LOGD_CORE, "PrimaryConnection now %s", ac ? nm_active_connection_get_settings_connection_id (ac) : "(none)"); + _LOGD (LOGD_CORE, "PrimaryConnection now %s", + ac ? nm_active_connection_get_settings_connection_id (ac) : "(none)"); _notify (self, PROP_PRIMARY_CONNECTION); _notify (self, PROP_PRIMARY_CONNECTION_TYPE); nm_manager_update_metered (self); @@ -6171,34 +6510,29 @@ policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user } static void -policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data) +policy_activating_ac_changed (GObject *object, GParamSpec *pspec, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDevice *activating, *best; - NMActiveConnection *ac; + NMActiveConnection *activating, *best; - /* We only look at activating-ip6-device if activating-ip4-device - * AND default-ip4-device are NULL; if default-ip4-device is - * non-NULL, then activating-ip6-device is irrelevant, since while - * that device might become the new default-ip6-device, it can't - * become primary-connection while default-ip4-device is set to + /* We only look at activating-ip6-ac if activating-ip4-ac + * AND default-ip4-ac are NULL; if default-ip4-ac is + * non-NULL, then activating-ip6-ac is irrelevant, since while + * that AC might become the new default-ip6-ac, it can't + * become primary-connection while default-ip4-ac is set to * something else. */ - activating = nm_policy_get_activating_ip4_device (priv->policy); - best = nm_policy_get_default_ip4_device (priv->policy); + activating = nm_policy_get_activating_ip4_ac (priv->policy); + best = nm_policy_get_default_ip4_ac (priv->policy); if (!activating && !best) - activating = nm_policy_get_activating_ip6_device (priv->policy); + activating = nm_policy_get_activating_ip6_ac (priv->policy); - if (activating) - ac = NM_ACTIVE_CONNECTION (nm_device_get_act_request (activating)); - else - ac = NULL; - - if (ac != priv->activating_connection) { - g_clear_object (&priv->activating_connection); - priv->activating_connection = ac ? g_object_ref (ac) : NULL; - _LOGD (LOGD_CORE, "ActivatingConnection now %s", ac ? nm_active_connection_get_settings_connection_id (ac) : "(none)"); + if (nm_g_object_ref_set (&priv->activating_connection, activating)) { + _LOGD (LOGD_CORE, "ActivatingConnection now %s", + activating + ? nm_active_connection_get_settings_connection_id (activating) + : "(none)"); _notify (self, PROP_ACTIVATING_CONNECTION); } } @@ -6703,12 +7037,12 @@ nm_manager_set_capability (NMManager *self, priv = NM_MANAGER_GET_PRIVATE (self); - idx = _nm_utils_array_find_binary_search (&g_array_index (priv->capabilities, guint32, 0), - sizeof (guint32), - priv->capabilities->len, - &cap_i, - nm_cmp_uint32_p_with_data, - NULL); + idx = nm_utils_array_find_binary_search (&g_array_index (priv->capabilities, guint32, 0), + sizeof (guint32), + priv->capabilities->len, + &cap_i, + nm_cmp_uint32_p_with_data, + NULL); if (idx >= 0) return; @@ -6789,14 +7123,14 @@ constructed (GObject *object) */ priv->policy = nm_policy_new (self, priv->settings); - g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP4_DEVICE, - G_CALLBACK (policy_default_device_changed), self); - g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP6_DEVICE, - G_CALLBACK (policy_default_device_changed), self); - g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP4_DEVICE, - G_CALLBACK (policy_activating_device_changed), self); - g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP6_DEVICE, - G_CALLBACK (policy_activating_device_changed), self); + g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP4_AC, + G_CALLBACK (policy_default_ac_changed), self); + g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP6_AC, + G_CALLBACK (policy_default_ac_changed), self); + g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP4_AC, + G_CALLBACK (policy_activating_ac_changed), self); + g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP6_AC, + G_CALLBACK (policy_activating_ac_changed), self); priv->config = g_object_ref (nm_config_get ()); g_signal_connect (G_OBJECT (priv->config), @@ -7134,8 +7468,8 @@ dispose (GObject *object) } if (priv->policy) { - g_signal_handlers_disconnect_by_func (priv->policy, policy_default_device_changed, self); - g_signal_handlers_disconnect_by_func (priv->policy, policy_activating_device_changed, self); + g_signal_handlers_disconnect_by_func (priv->policy, policy_default_ac_changed, self); + g_signal_handlers_disconnect_by_func (priv->policy, policy_activating_ac_changed, self); g_clear_object (&priv->policy); } diff --git a/src/nm-manager.h b/src/nm-manager.h index 5a462846..11cba1a5 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -98,10 +98,12 @@ const CList * nm_manager_get_active_connections (NMManager *manager); iter = c_list_entry (iter->active_connections_lst.next, NMActiveConnection, active_connections_lst)) NMSettingsConnection **nm_manager_get_activatable_connections (NMManager *manager, - guint *out_len, - gboolean sort); + gboolean for_auto_activation, + gboolean sort, + guint *out_len); -void nm_manager_write_device_state (NMManager *manager); +void nm_manager_write_device_state_all (NMManager *manager); +gboolean nm_manager_write_device_state (NMManager *manager, NMDevice *device); /* Device handling */ diff --git a/src/nm-policy.c b/src/nm-policy.c index 125f2704..7f8c665c 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -56,10 +56,10 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMPolicy, PROP_MANAGER, PROP_SETTINGS, - PROP_DEFAULT_IP4_DEVICE, - PROP_DEFAULT_IP6_DEVICE, - PROP_ACTIVATING_IP4_DEVICE, - PROP_ACTIVATING_IP6_DEVICE, + PROP_DEFAULT_IP4_AC, + PROP_DEFAULT_IP6_AC, + PROP_ACTIVATING_IP4_AC, + PROP_ACTIVATING_IP6_AC, ); typedef struct { @@ -79,8 +79,8 @@ typedef struct { NMHostnameManager *hostname_manager; - NMDevice *default_device4, *activating_device4; - NMDevice *default_device6, *activating_device6; + NMActiveConnection *default_ac4, *activating_ac4; + NMActiveConnection *default_ac6, *activating_ac6; struct { GInetAddress *addr; @@ -146,6 +146,7 @@ _PRIV_TO_SELF (NMPolicyPrivate *priv) static void schedule_activate_all (NMPolicy *self); static void schedule_activate_check (NMPolicy *self, NMDevice *device); +static NMDevice *get_default_device (NMPolicy *self, int addr_family); /*****************************************************************************/ @@ -367,43 +368,56 @@ device_ip6_subnet_needed (NMDevice *device, _LOGD (LOGD_IP6, "ipv6-pd: %s needs a subnet", nm_device_get_iface (device)); - if (!priv->default_device6) { + if (!priv->default_ac6) { /* We request the prefixes when the default IPv6 device is set. */ _LOGI (LOGD_IP6, "ipv6-pd: no device to obtain a subnet to share on %s from", nm_device_get_iface (device)); return; } - ip6_subnet_from_device (self, priv->default_device6, device); - nm_device_copy_ip6_dns_config (device, priv->default_device6); + ip6_subnet_from_device (self, get_default_device (self, AF_INET6), device); + nm_device_copy_ip6_dns_config (device, get_default_device (self, AF_INET6)); } /*****************************************************************************/ static NMDevice * -get_best_ip_device (NMPolicy *self, - int addr_family, - gboolean fully_activated) +get_default_device (NMPolicy *self, int addr_family) +{ + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); + NMActiveConnection *ac; + + nm_assert_addr_family (addr_family); + + ac = (addr_family == AF_INET) ? priv->default_ac4 : priv->default_ac6; + + return ac ? nm_active_connection_get_device (ac) : NULL; +} + +static NMActiveConnection * +get_best_active_connection (NMPolicy *self, + int addr_family, + gboolean fully_activated) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); const CList *tmp_lst; NMDevice *device; - NMDevice *best_device; - NMDevice *prev_device; guint32 best_metric = G_MAXUINT32; gboolean best_is_fully_activated = FALSE; + NMActiveConnection *best_ac, *prev_ac; nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); - /* we prefer the current device in case of identical metric. - * Hence, try that one first.*/ - best_device = NULL; - prev_device = addr_family == AF_INET - ? (fully_activated ? priv->default_device4 : priv->activating_device4) - : (fully_activated ? priv->default_device6 : priv->activating_device6); + /* we prefer the current AC in case of identical metric. + * Hence, try that one first. */ + prev_ac = addr_family == AF_INET + ? (fully_activated ? priv->default_ac4 : priv->activating_ac4) + : (fully_activated ? priv->default_ac6 : priv->activating_ac6); + best_ac = NULL; nm_manager_for_each_device (priv->manager, device, tmp_lst) { NMDeviceState state; const NMPObject *r; + NMActiveConnection *ac; NMConnection *connection; guint32 metric; gboolean is_fully_activated; @@ -435,26 +449,29 @@ get_best_ip_device (NMPolicy *self, } else continue; - if ( !best_device + ac = (NMActiveConnection *) nm_device_get_act_request (device); + nm_assert (ac); + + if ( !best_ac || (!best_is_fully_activated && is_fully_activated) || ( metric < best_metric - || (metric == best_metric && device == prev_device))) { - best_device = device; + || (metric == best_metric && ac == prev_ac))) { + best_ac = ac; best_metric = metric; best_is_fully_activated = is_fully_activated; } } if ( !fully_activated - && best_device + && best_ac && best_is_fully_activated) { - /* There's only a best activating device if the best device + /* There's a best activating AC only if the best device * among all activating and already-activated devices is a * still-activating one. */ return NULL; } - return best_device; + return best_ac; } static gboolean @@ -668,6 +685,7 @@ update_system_hostname (NMPolicy *self, const char *msg) gboolean external_hostname = FALSE; const NMPlatformIP4Address *addr4; const NMPlatformIP6Address *addr6; + NMDevice *device; g_return_if_fail (self != NULL); @@ -720,11 +738,11 @@ update_system_hostname (NMPolicy *self, const char *msg) return; } - if (priv->default_device4) { + if (priv->default_ac4) { NMDhcp4Config *dhcp4_config; /* Grab a hostname out of the device's DHCP4 config */ - dhcp4_config = nm_device_get_dhcp4_config (priv->default_device4); + dhcp4_config = nm_device_get_dhcp4_config (get_default_device (self, AF_INET)); if (dhcp4_config) { dhcp_hostname = nm_dhcp4_config_get_option (dhcp4_config, "host_name"); if (dhcp_hostname && dhcp_hostname[0]) { @@ -740,11 +758,11 @@ update_system_hostname (NMPolicy *self, const char *msg) } } - if (priv->default_device6) { + if (priv->default_ac6) { NMDhcp6Config *dhcp6_config; /* Grab a hostname out of the device's DHCP6 config */ - dhcp6_config = nm_device_get_dhcp6_config (priv->default_device6); + dhcp6_config = nm_device_get_dhcp6_config (get_default_device (self, AF_INET6)); if (dhcp6_config) { dhcp_hostname = nm_dhcp6_config_get_option (dhcp6_config, "host_name"); if (dhcp_hostname && dhcp_hostname[0]) { @@ -779,7 +797,7 @@ update_system_hostname (NMPolicy *self, const char *msg) priv->dhcp_hostname = FALSE; - if (!priv->default_device4 && !priv->default_device6) { + if (!priv->default_ac4 && !priv->default_ac6) { /* No best device; fall back to the last hostname set externally * to NM or if there wasn't one, 'localhost.localdomain' */ @@ -798,8 +816,11 @@ update_system_hostname (NMPolicy *self, const char *msg) /* No configured hostname, no automatically determined hostname, and no * bootup hostname. Start reverse DNS of the current IPv4 or IPv6 address. */ - ip4_config = priv->default_device4 ? nm_device_get_ip4_config (priv->default_device4) : NULL; - ip6_config = priv->default_device6 ? nm_device_get_ip6_config (priv->default_device6) : NULL; + device = get_default_device (self, AF_INET); + ip4_config = device ? nm_device_get_ip4_config (device) : NULL; + + device = get_default_device (self, AF_INET6); + ip6_config = device ? nm_device_get_ip6_config (device) : NULL; if ( ip4_config && (addr4 = nm_ip4_config_get_first_address (ip4_config))) { @@ -852,16 +873,19 @@ get_best_ip_config (NMPolicy *self, NMVpnConnection **out_vpn) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - NMDevice *device; - gpointer conf; + gpointer conf, best_conf = NULL; const CList *tmp_list; NMActiveConnection *ac; + guint64 best_metric = G_MAXUINT64; + NMVpnConnection *best_vpn = NULL; nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { NMVpnConnection *candidate; NMVpnConnectionState vpn_state; + const NMPObject *obj; + guint32 metric; if (!NM_IS_VPN_CONNECTION (ac)) continue; @@ -879,40 +903,45 @@ get_best_ip_config (NMPolicy *self, if (!conf) continue; - if (addr_family == AF_INET) { - if (!nm_ip4_config_best_default_route_get (conf)) - continue; - } else { - if (!nm_ip6_config_best_default_route_get (conf)) - continue; + if (addr_family == AF_INET) + obj = nm_ip4_config_best_default_route_get (conf); + else + obj = nm_ip6_config_best_default_route_get (conf); + if (!obj) + continue; + + metric = NMP_OBJECT_CAST_IPX_ROUTE (obj)->rx.metric; + if (metric <= best_metric) { + best_metric = metric; + best_conf = conf; + best_vpn = candidate; } + } - /* FIXME: in case of multiple VPN candidates, choose the one with the - * best metric. */ + if (best_metric != G_MAXUINT64) { NM_SET_OUT (out_device, NULL); - NM_SET_OUT (out_vpn, candidate); - NM_SET_OUT (out_ac, ac); - NM_SET_OUT (out_ip_iface, nm_vpn_connection_get_ip_iface (candidate, TRUE)); - return conf; + NM_SET_OUT (out_vpn, best_vpn); + NM_SET_OUT (out_ac, NM_ACTIVE_CONNECTION (best_vpn)); + NM_SET_OUT (out_ip_iface, nm_vpn_connection_get_ip_iface (best_vpn, TRUE)); + return best_conf; } - device = get_best_ip_device (self, addr_family, TRUE); - if (device) { - NMActRequest *req; + ac = get_best_active_connection (self, addr_family, TRUE); + if (ac) { + NMDevice *device = nm_active_connection_get_device (ac); + + nm_assert (device); if (addr_family == AF_INET) conf = nm_device_get_ip4_config (device); else conf = nm_device_get_ip6_config (device); - req = nm_device_get_act_request (device); - if (conf && req) { - NM_SET_OUT (out_device, device); - NM_SET_OUT (out_vpn, NULL); - NM_SET_OUT (out_ac, NM_ACTIVE_CONNECTION (req)); - NM_SET_OUT (out_ip_iface, nm_device_get_ip_iface (device)); - return conf; - } + NM_SET_OUT (out_device, device); + NM_SET_OUT (out_vpn, NULL); + NM_SET_OUT (out_ac, ac); + NM_SET_OUT (out_ip_iface, nm_device_get_ip_iface (device)); + return conf; } NM_SET_OUT (out_device, NULL); @@ -937,17 +966,17 @@ update_ip4_routing (NMPolicy *self, gboolean force_update) * so we can get (vpn != NULL && best == NULL). */ if (!get_best_ip_config (self, AF_INET, &ip_iface, &best_ac, &best, &vpn)) { - if (nm_clear_g_object (&priv->default_device4)) { - _LOGt (LOGD_DNS, "set-default-device-4: %p", NULL); - _notify (self, PROP_DEFAULT_IP4_DEVICE); + if (nm_clear_g_object (&priv->default_ac4)) { + _LOGt (LOGD_DNS, "set-default-ac-4: %p", NULL); + _notify (self, PROP_DEFAULT_IP4_AC); } return; } g_assert ((best || vpn) && best_ac); if ( !force_update - && best - && best == priv->default_device4) + && best_ac + && best_ac == priv->default_ac4) return; if (best) { @@ -959,19 +988,16 @@ update_ip4_routing (NMPolicy *self, gboolean force_update) } } - if (vpn) - best = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); - update_default_ac (self, AF_INET, best_ac); - if (!nm_g_object_ref_set (&priv->default_device4, best)) + if (!nm_g_object_ref_set (&priv->default_ac4, best_ac)) return; - _LOGt (LOGD_DNS, "set-default-device-4: %p", priv->default_device4); + _LOGt (LOGD_DNS, "set-default-ac-4: %p", priv->default_ac4); _LOGI (LOGD_CORE, "set '%s' (%s) as default for IPv4 routing and DNS", nm_connection_get_id (nm_active_connection_get_applied_connection (best_ac)), ip_iface); - _notify (self, PROP_DEFAULT_IP4_DEVICE); + _notify (self, PROP_DEFAULT_IP4_AC); } static void @@ -985,7 +1011,7 @@ update_ip6_dns_delegation (NMPolicy *self) nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { device = nm_active_connection_get_device (ac); if (device && nm_device_needs_ip6_subnet (device)) - nm_device_copy_ip6_dns_config (device, priv->default_device6); + nm_device_copy_ip6_dns_config (device, get_default_device (self, AF_INET6)); } } @@ -1001,7 +1027,7 @@ update_ip6_prefix_delegation (NMPolicy *self) nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { device = nm_active_connection_get_device (ac); if (device && nm_device_needs_ip6_subnet (device)) - ip6_subnet_from_device (self, priv->default_device6, device); + ip6_subnet_from_device (self, get_default_device (self, AF_INET6), device); } } @@ -1020,17 +1046,17 @@ update_ip6_routing (NMPolicy *self, gboolean force_update) * so we can get (vpn != NULL && best == NULL). */ if (!get_best_ip_config (self, AF_INET6, &ip_iface, &best_ac, &best, &vpn)) { - if (nm_clear_g_object (&priv->default_device6)) { - _LOGt (LOGD_DNS, "set-default-device-6: %p", NULL); - _notify (self, PROP_DEFAULT_IP6_DEVICE); + if (nm_clear_g_object (&priv->default_ac6)) { + _LOGt (LOGD_DNS, "set-default-ac-6: %p", NULL); + _notify (self, PROP_DEFAULT_IP6_AC); } return; } g_assert ((best || vpn) && best_ac); if ( !force_update - && best - && best == priv->default_device6) + && best_ac + && best_ac == priv->default_ac6) return; if (best) { @@ -1042,21 +1068,18 @@ update_ip6_routing (NMPolicy *self, gboolean force_update) } } - if (vpn) - best = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); - update_default_ac (self, AF_INET6, best_ac); - if (!nm_g_object_ref_set (&priv->default_device6, best)) + if (!nm_g_object_ref_set (&priv->default_ac6, best_ac)) return; - _LOGt (LOGD_DNS, "set-default-device-6: %p", priv->default_device6); + _LOGt (LOGD_DNS, "set-default-ac-6: %p", priv->default_ac6); update_ip6_prefix_delegation (self); _LOGI (LOGD_CORE, "set '%s' (%s) as default for IPv6 routing and DNS", nm_connection_get_id (nm_active_connection_get_applied_connection (best_ac)), ip_iface); - _notify (self, PROP_DEFAULT_IP6_DEVICE); + _notify (self, PROP_DEFAULT_IP6_AC); } static void @@ -1104,23 +1127,23 @@ update_routing_and_dns (NMPolicy *self, gboolean force_update) } static void -check_activating_devices (NMPolicy *self) +check_activating_active_connections (NMPolicy *self) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - NMDevice *best4, *best6 = NULL; + NMActiveConnection *best4, *best6 = NULL; - best4 = get_best_ip_device (self, AF_INET, FALSE); - best6 = get_best_ip_device (self, AF_INET6, FALSE); + best4 = get_best_active_connection (self, AF_INET, FALSE); + best6 = get_best_active_connection (self, AF_INET6, FALSE); g_object_freeze_notify (G_OBJECT (self)); - if (nm_g_object_ref_set (&priv->activating_device4, best4)) { - _LOGt (LOGD_DNS, "set-activating-device-4: %p", priv->activating_device4); - _notify (self, PROP_ACTIVATING_IP4_DEVICE); + if (nm_g_object_ref_set (&priv->activating_ac4, best4)) { + _LOGt (LOGD_DNS, "set-activating-ac-4: %p", priv->activating_ac4); + _notify (self, PROP_ACTIVATING_IP4_AC); } - if (nm_g_object_ref_set (&priv->activating_device6, best6)) { - _LOGt (LOGD_DNS, "set-activating-device-6: %p", priv->activating_device6); - _notify (self, PROP_ACTIVATING_IP6_DEVICE); + if (nm_g_object_ref_set (&priv->activating_ac6, best6)) { + _LOGt (LOGD_DNS, "set-activating-ac-6: %p", priv->activating_ac6); + _notify (self, PROP_ACTIVATING_IP6_AC); } g_object_thaw_notify (G_OBJECT (self)); @@ -1212,30 +1235,33 @@ auto_activate_device (NMPolicy *self, if (!nm_device_autoconnect_allowed (device)) return; - connections = nm_manager_get_activatable_connections (priv->manager, &len, TRUE); + connections = nm_manager_get_activatable_connections (priv->manager, TRUE, TRUE, &len); if (!connections[0]) return; /* Find the first connection that should be auto-activated */ best_connection = NULL; for (i = 0; i < len; i++) { - NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (connections[i]); + NMSettingsConnection *candidate = connections[i]; + NMConnection *cand_conn; NMSettingConnection *s_con; const char *permission; if (nm_settings_connection_autoconnect_is_blocked (candidate)) continue; - s_con = nm_connection_get_setting_connection (NM_CONNECTION (candidate)); + cand_conn = nm_settings_connection_get_connection (candidate); + + s_con = nm_connection_get_setting_connection (cand_conn); if (!nm_setting_connection_get_autoconnect (s_con)) continue; - permission = nm_utils_get_shared_wifi_permission (NM_CONNECTION (candidate)); + permission = nm_utils_get_shared_wifi_permission (cand_conn); if ( permission && !nm_settings_connection_check_permission (candidate, permission)) continue; - if (nm_device_can_auto_connect (device, (NMConnection *) candidate, &specific_object)) { + if (nm_device_can_auto_connect (device, candidate, &specific_object)) { best_connection = candidate; break; } @@ -1418,34 +1444,36 @@ reset_autoconnect_all (NMPolicy *self, connections = nm_settings_get_connections (priv->settings, NULL); for (i = 0; connections[i]; i++) { - NMSettingsConnection *connection = connections[i]; + NMSettingsConnection *sett_conn = connections[i]; if ( device - && !nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) + && !nm_device_check_connection_compatible (device, + nm_settings_connection_get_connection (sett_conn), + NULL)) continue; if (only_no_secrets) { /* we only reset the no-secrets blocked flag. */ - if (nm_settings_connection_autoconnect_blocked_reason_set (connection, + if (nm_settings_connection_autoconnect_blocked_reason_set (sett_conn, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, FALSE)) { /* maybe the connection is still blocked afterwards for other reasons * and in the larger picture nothing changed. But it's too complicated * to find out exactly. Just assume, something changed to be sure. */ - if (!nm_settings_connection_autoconnect_is_blocked (connection)) + if (!nm_settings_connection_autoconnect_is_blocked (sett_conn)) changed = TRUE; } } else { /* we reset the tries-count and any blocked-reason */ - if (nm_settings_connection_autoconnect_retries_get (connection) == 0) + if (nm_settings_connection_autoconnect_retries_get (sett_conn) == 0) changed = TRUE; - nm_settings_connection_autoconnect_retries_reset (connection); + nm_settings_connection_autoconnect_retries_reset (sett_conn); - if (nm_settings_connection_autoconnect_blocked_reason_set (connection, + if (nm_settings_connection_autoconnect_blocked_reason_set (sett_conn, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL & ~NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, FALSE)) { - if (!nm_settings_connection_autoconnect_is_blocked (connection)) + if (!nm_settings_connection_autoconnect_is_blocked (sett_conn)) changed = TRUE; } } @@ -1566,7 +1594,9 @@ static void activate_slave_connections (NMPolicy *self, NMDevice *device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - const char *master_device, *master_uuid_settings = NULL, *master_uuid_applied = NULL; + const char *master_device; + const char *master_uuid_settings = NULL; + const char *master_uuid_applied = NULL; guint i; NMActRequest *req; gboolean internal_activation = FALSE; @@ -1578,16 +1608,18 @@ activate_slave_connections (NMPolicy *self, NMDevice *device) req = nm_device_get_act_request (device); if (req) { - NMConnection *con; + NMConnection *connection; + NMSettingsConnection *sett_conn; NMAuthSubject *subject; - con = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (req)); - if (con) - master_uuid_applied = nm_connection_get_uuid (con); - con = NM_CONNECTION (nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (req))); - if (con) { - master_uuid_settings = nm_connection_get_uuid (con); - if (!g_strcmp0 (master_uuid_settings, master_uuid_applied)) + connection = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (req)); + if (connection) + master_uuid_applied = nm_connection_get_uuid (connection); + + sett_conn = nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (req)); + if (sett_conn) { + master_uuid_settings = nm_settings_connection_get_uuid (sett_conn); + if (nm_streq0 (master_uuid_settings, master_uuid_applied)) master_uuid_settings = NULL; } @@ -1598,11 +1630,11 @@ activate_slave_connections (NMPolicy *self, NMDevice *device) changed = FALSE; connections = nm_settings_get_connections (priv->settings, NULL); for (i = 0; connections[i]; i++) { - NMSettingsConnection *connection = connections[i]; + NMSettingsConnection *sett_conn = connections[i]; NMSettingConnection *s_slave_con; const char *slave_master; - s_slave_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); + s_slave_con = nm_connection_get_setting_connection (nm_settings_connection_get_connection (sett_conn)); slave_master = nm_setting_connection_get_master (s_slave_con); if (!slave_master) continue; @@ -1612,14 +1644,14 @@ activate_slave_connections (NMPolicy *self, NMDevice *device) continue; if (!internal_activation) { - if (nm_settings_connection_autoconnect_retries_get (connection) == 0) + if (nm_settings_connection_autoconnect_retries_get (sett_conn) == 0) changed = TRUE; - nm_settings_connection_autoconnect_retries_reset (connection); + nm_settings_connection_autoconnect_retries_reset (sett_conn); } - if (nm_settings_connection_autoconnect_blocked_reason_set (connection, + if (nm_settings_connection_autoconnect_blocked_reason_set (sett_conn, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, FALSE)) { - if (!nm_settings_connection_autoconnect_is_blocked (connection)) + if (!nm_settings_connection_autoconnect_is_blocked (sett_conn)) changed = TRUE; } } @@ -1635,7 +1667,6 @@ activate_secondary_connections (NMPolicy *self, { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); NMSettingConnection *s_con; - NMSettingsConnection *settings_con; NMActiveConnection *ac; PendingSecondaryData *secondary_data; GSList *secondary_ac_list = NULL; @@ -1644,22 +1675,25 @@ activate_secondary_connections (NMPolicy *self, gboolean success = TRUE; s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); + nm_assert (s_con); for (i = 0; i < nm_setting_connection_get_num_secondaries (s_con); i++) { + NMSettingsConnection *sett_conn; const char *sec_uuid = nm_setting_connection_get_secondary (s_con, i); NMActRequest *req; - settings_con = nm_settings_get_connection_by_uuid (priv->settings, sec_uuid); - if (!settings_con) { + sett_conn = nm_settings_get_connection_by_uuid (priv->settings, sec_uuid); + if (!sett_conn) { _LOGW (LOGD_DEVICE, "secondary connection '%s' auto-activation failed: The connection doesn't exist.", sec_uuid); success = FALSE; break; } - if (!nm_connection_is_type (NM_CONNECTION (settings_con), NM_SETTING_VPN_SETTING_NAME)) { + + if (!nm_connection_is_type (nm_settings_connection_get_connection (sett_conn), + NM_SETTING_VPN_SETTING_NAME)) { _LOGW (LOGD_DEVICE, "secondary connection '%s (%s)' auto-activation failed: The connection is not a VPN.", - nm_settings_connection_get_id (settings_con), sec_uuid); + nm_settings_connection_get_id (sett_conn), sec_uuid); success = FALSE; break; } @@ -1668,10 +1702,10 @@ activate_secondary_connections (NMPolicy *self, g_assert (req); _LOGD (LOGD_DEVICE, "activating secondary connection '%s (%s)' for base connection '%s (%s)'", - nm_settings_connection_get_id (settings_con), sec_uuid, + nm_settings_connection_get_id (sett_conn), sec_uuid, nm_connection_get_id (connection), nm_connection_get_uuid (connection)); ac = nm_manager_activate_connection (priv->manager, - settings_con, + sett_conn, NULL, nm_dbus_object_get_path (NM_DBUS_OBJECT (req)), device, @@ -1683,7 +1717,7 @@ activate_secondary_connections (NMPolicy *self, secondary_ac_list = g_slist_append (secondary_ac_list, g_object_ref (ac)); else { _LOGW (LOGD_DEVICE, "secondary connection '%s (%s)' auto-activation failed: (%d) %s", - nm_settings_connection_get_id (settings_con), sec_uuid, + nm_settings_connection_get_id (sett_conn), sec_uuid, error->code, error->message); g_clear_error (&error); @@ -1711,7 +1745,7 @@ device_state_changed (NMDevice *device, NMPolicyPrivate *priv = user_data; NMPolicy *self = _PRIV_TO_SELF (priv); NMActiveConnection *ac; - NMSettingsConnection *connection = nm_device_get_settings_connection (device); + NMSettingsConnection *sett_conn = nm_device_get_settings_connection (device); NMIP4Config *ip4_config; NMIP6Config *ip6_config; NMSettingConnection *s_con = NULL; @@ -1729,8 +1763,8 @@ device_state_changed (NMDevice *device, /* Block autoconnect of the just-failed connection for situations * where a retry attempt would just fail again. */ - if (connection) { - nm_settings_connection_autoconnect_blocked_reason_set (connection, + if (sett_conn) { + nm_settings_connection_autoconnect_blocked_reason_set (sett_conn, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, TRUE); } @@ -1744,7 +1778,7 @@ device_state_changed (NMDevice *device, /* Mark the connection invalid if it failed during activation so that * it doesn't get automatically chosen over and over and over again. */ - if ( connection + if ( sett_conn && old_state >= NM_DEVICE_STATE_PREPARE && old_state <= NM_DEVICE_STATE_ACTIVATED) { gboolean block_no_secrets = FALSE; @@ -1765,7 +1799,7 @@ device_state_changed (NMDevice *device, * That can happen when nm_settings_connection_get_secrets() fails early without actually * consulting any agents. */ - con_v = nm_settings_connection_get_last_secret_agent_version_id (connection); + con_v = nm_settings_connection_get_last_secret_agent_version_id (sett_conn); if ( con_v == 0 || con_v == nm_agent_manager_get_agent_version_id (priv->agent_mgr)) block_no_secrets = TRUE; @@ -1773,33 +1807,35 @@ device_state_changed (NMDevice *device, if (block_no_secrets) { _LOGD (LOGD_DEVICE, "connection '%s' now blocked from autoconnect due to no secrets", - nm_settings_connection_get_id (connection)); - nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, TRUE); + nm_settings_connection_get_id (sett_conn)); + nm_settings_connection_autoconnect_blocked_reason_set (sett_conn, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, TRUE); } else { - tries = nm_settings_connection_autoconnect_retries_get (connection); + tries = nm_settings_connection_autoconnect_retries_get (sett_conn); if (tries > 0) { _LOGD (LOGD_DEVICE, "connection '%s' failed to autoconnect; %d tries left", - nm_settings_connection_get_id (connection), tries - 1); - _connection_autoconnect_retries_set (self, connection, tries - 1); + nm_settings_connection_get_id (sett_conn), tries - 1); + _connection_autoconnect_retries_set (self, sett_conn, tries - 1); } else if (tries != 0) { _LOGD (LOGD_DEVICE, "connection '%s' failed to autoconnect; infinite tries left", - nm_settings_connection_get_id (connection)); + nm_settings_connection_get_id (sett_conn)); } } - nm_connection_clear_secrets (NM_CONNECTION (connection)); + /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */ + nm_connection_clear_secrets (nm_settings_connection_get_connection (sett_conn)); } break; case NM_DEVICE_STATE_ACTIVATED: - if (connection) { + if (sett_conn) { /* Reset auto retries back to default since connection was successful */ - nm_settings_connection_autoconnect_retries_reset (connection); + nm_settings_connection_autoconnect_retries_reset (sett_conn); /* And clear secrets so they will always be requested from the * settings service when the next connection is made. */ - nm_connection_clear_secrets (NM_CONNECTION (connection)); + /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */ + nm_connection_clear_secrets (nm_settings_connection_get_connection (sett_conn)); } /* Add device's new IPv4 and IPv6 configs to DNS */ @@ -1823,7 +1859,7 @@ device_state_changed (NMDevice *device, update_routing_and_dns (self, FALSE); break; case NM_DEVICE_STATE_DEACTIVATING: - if (connection) { + if (sett_conn) { NMSettingsAutoconnectBlockedReason blocked_reason = NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE; switch (nm_device_state_reason_check (reason)) { @@ -1838,10 +1874,10 @@ device_state_changed (NMDevice *device, } if (blocked_reason != NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE) { _LOGD (LOGD_DEVICE, "blocking autoconnect of connection '%s': %s", - nm_settings_connection_get_id (connection), + nm_settings_connection_get_id (sett_conn), NM_UTILS_LOOKUP_STR (nm_device_state_reason_to_str, nm_device_state_reason_check (reason))); - nm_settings_connection_autoconnect_blocked_reason_set (connection, blocked_reason, TRUE); + nm_settings_connection_autoconnect_blocked_reason_set (sett_conn, blocked_reason, TRUE); } } ip6_remove_device_prefix_delegations (self, device); @@ -1877,20 +1913,25 @@ device_state_changed (NMDevice *device, break; case NM_DEVICE_STATE_IP_CONFIG: /* We must have secrets if we got here. */ - if (connection) - nm_settings_connection_autoconnect_blocked_reason_set (connection, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL, FALSE); + if (sett_conn) + nm_settings_connection_autoconnect_blocked_reason_set (sett_conn, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL, FALSE); break; case NM_DEVICE_STATE_SECONDARIES: - if (connection) - s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); - if (s_con && nm_setting_connection_get_num_secondaries (s_con) > 0) { + if (sett_conn) + s_con = nm_connection_get_setting_connection (nm_settings_connection_get_connection (sett_conn)); + if ( s_con + && nm_setting_connection_get_num_secondaries (s_con) > 0) { /* Make routes and DNS up-to-date before activating dependent connections */ update_routing_and_dns (self, FALSE); /* Activate secondary (VPN) connections */ - if (!activate_secondary_connections (self, NM_CONNECTION (connection), device)) - nm_device_queue_state (device, NM_DEVICE_STATE_FAILED, + if (!activate_secondary_connections (self, + nm_settings_connection_get_connection (sett_conn), + device)) { + nm_device_queue_state (device, + NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED); + } } else nm_device_queue_state (device, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE); @@ -1900,7 +1941,7 @@ device_state_changed (NMDevice *device, break; } - check_activating_devices (self); + check_activating_active_connections (self); } static void @@ -2382,28 +2423,28 @@ secret_agent_registered (NMSettings *settings, schedule_activate_all (self); } -NMDevice * -nm_policy_get_default_ip4_device (NMPolicy *self) +NMActiveConnection * +nm_policy_get_default_ip4_ac (NMPolicy *self) { - return NM_POLICY_GET_PRIVATE (self)->default_device4; + return NM_POLICY_GET_PRIVATE (self)->default_ac4; } -NMDevice * -nm_policy_get_default_ip6_device (NMPolicy *self) +NMActiveConnection * +nm_policy_get_default_ip6_ac (NMPolicy *self) { - return NM_POLICY_GET_PRIVATE (self)->default_device6; + return NM_POLICY_GET_PRIVATE (self)->default_ac6; } -NMDevice * -nm_policy_get_activating_ip4_device (NMPolicy *self) +NMActiveConnection * +nm_policy_get_activating_ip4_ac (NMPolicy *self) { - return NM_POLICY_GET_PRIVATE (self)->activating_device4; + return NM_POLICY_GET_PRIVATE (self)->activating_ac4; } -NMDevice * -nm_policy_get_activating_ip6_device (NMPolicy *self) +NMActiveConnection * +nm_policy_get_activating_ip6_ac (NMPolicy *self) { - return NM_POLICY_GET_PRIVATE (self)->activating_device6; + return NM_POLICY_GET_PRIVATE (self)->activating_ac6; } /*****************************************************************************/ @@ -2425,17 +2466,17 @@ get_property (GObject *object, guint prop_id, NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); switch (prop_id) { - case PROP_DEFAULT_IP4_DEVICE: - g_value_set_object (value, priv->default_device4); + case PROP_DEFAULT_IP4_AC: + g_value_set_object (value, priv->default_ac4); break; - case PROP_DEFAULT_IP6_DEVICE: - g_value_set_object (value, priv->default_device6); + case PROP_DEFAULT_IP6_AC: + g_value_set_object (value, priv->default_ac6); break; - case PROP_ACTIVATING_IP4_DEVICE: - g_value_set_object (value, priv->activating_device4); + case PROP_ACTIVATING_IP4_AC: + g_value_set_object (value, priv->activating_ac4); break; - case PROP_ACTIVATING_IP6_DEVICE: - g_value_set_object (value, priv->activating_device6); + case PROP_ACTIVATING_IP6_AC: + g_value_set_object (value, priv->activating_ac6); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -2576,10 +2617,10 @@ dispose (GObject *object) g_clear_object (&priv->lookup.addr); g_clear_object (&priv->lookup.resolver); - nm_clear_g_object (&priv->default_device4); - nm_clear_g_object (&priv->default_device6); - nm_clear_g_object (&priv->activating_device4); - nm_clear_g_object (&priv->activating_device6); + nm_clear_g_object (&priv->default_ac4); + nm_clear_g_object (&priv->default_ac6); + nm_clear_g_object (&priv->activating_ac4); + nm_clear_g_object (&priv->activating_ac6); g_clear_pointer (&priv->pending_active_connections, g_hash_table_unref); c_list_for_each_entry_safe (data, data_safe, &priv->pending_activation_checks, pending_lst) @@ -2685,23 +2726,23 @@ nm_policy_class_init (NMPolicyClass *policy_class) G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DEFAULT_IP4_DEVICE] = - g_param_spec_object (NM_POLICY_DEFAULT_IP4_DEVICE, "", "", - NM_TYPE_DEVICE, + obj_properties[PROP_DEFAULT_IP4_AC] = + g_param_spec_object (NM_POLICY_DEFAULT_IP4_AC, "", "", + NM_TYPE_ACTIVE_CONNECTION, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DEFAULT_IP6_DEVICE] = - g_param_spec_object (NM_POLICY_DEFAULT_IP6_DEVICE, "", "", + obj_properties[PROP_DEFAULT_IP6_AC] = + g_param_spec_object (NM_POLICY_DEFAULT_IP6_AC, "", "", NM_TYPE_DEVICE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ACTIVATING_IP4_DEVICE] = - g_param_spec_object (NM_POLICY_ACTIVATING_IP4_DEVICE, "", "", + obj_properties[PROP_ACTIVATING_IP4_AC] = + g_param_spec_object (NM_POLICY_ACTIVATING_IP4_AC, "", "", NM_TYPE_DEVICE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ACTIVATING_IP6_DEVICE] = - g_param_spec_object (NM_POLICY_ACTIVATING_IP6_DEVICE, "", "", + obj_properties[PROP_ACTIVATING_IP6_AC] = + g_param_spec_object (NM_POLICY_ACTIVATING_IP6_AC, "", "", NM_TYPE_DEVICE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); diff --git a/src/nm-policy.h b/src/nm-policy.h index 2c96e6d0..916ede00 100644 --- a/src/nm-policy.h +++ b/src/nm-policy.h @@ -31,10 +31,10 @@ #define NM_POLICY_MANAGER "manager" #define NM_POLICY_SETTINGS "settings" -#define NM_POLICY_DEFAULT_IP4_DEVICE "default-ip4-device" -#define NM_POLICY_DEFAULT_IP6_DEVICE "default-ip6-device" -#define NM_POLICY_ACTIVATING_IP4_DEVICE "activating-ip4-device" -#define NM_POLICY_ACTIVATING_IP6_DEVICE "activating-ip6-device" +#define NM_POLICY_DEFAULT_IP4_AC "default-ip4-ac" +#define NM_POLICY_DEFAULT_IP6_AC "default-ip6-ac" +#define NM_POLICY_ACTIVATING_IP4_AC "activating-ip4-ac" +#define NM_POLICY_ACTIVATING_IP6_AC "activating-ip6-ac" typedef struct _NMPolicyClass NMPolicyClass; @@ -42,10 +42,10 @@ GType nm_policy_get_type (void); NMPolicy *nm_policy_new (NMManager *manager, NMSettings *settings); -NMDevice *nm_policy_get_default_ip4_device (NMPolicy *policy); -NMDevice *nm_policy_get_default_ip6_device (NMPolicy *policy); -NMDevice *nm_policy_get_activating_ip4_device (NMPolicy *policy); -NMDevice *nm_policy_get_activating_ip6_device (NMPolicy *policy); +NMActiveConnection *nm_policy_get_default_ip4_ac (NMPolicy *policy); +NMActiveConnection *nm_policy_get_default_ip6_ac (NMPolicy *policy); +NMActiveConnection *nm_policy_get_activating_ip4_ac (NMPolicy *policy); +NMActiveConnection *nm_policy_get_activating_ip6_ac (NMPolicy *policy); /** * NMPolicyHostnameMode diff --git a/src/nm-rfkill-manager.c b/src/nm-rfkill-manager.c index b2909e9d..a7bc694a 100644 --- a/src/nm-rfkill-manager.c +++ b/src/nm-rfkill-manager.c @@ -65,7 +65,7 @@ typedef struct { char *path; char *driver; RfKillType rtype; - gint state; + int state; gboolean platform; } Killswitch; @@ -158,7 +158,7 @@ killswitch_destroy (Killswitch *ks) } static RfKillState -sysfs_state_to_nm_state (gint sysfs_state) +sysfs_state_to_nm_state (int sysfs_state) { switch (sysfs_state) { case 0: diff --git a/src/nm-session-monitor.c b/src/nm-session-monitor.c index 23d41d7e..b67c537c 100644 --- a/src/nm-session-monitor.c +++ b/src/nm-session-monitor.c @@ -28,24 +28,26 @@ #include <string.h> #include <sys/stat.h> -#if defined (SESSION_TRACKING_SYSTEMD) && defined (SESSION_TRACKING_ELOGIND) +#if SESSION_TRACKING_SYSTEMD && SESSION_TRACKING_ELOGIND #error Cannot build both systemd-logind and elogind support #endif -#ifdef SESSION_TRACKING_SYSTEMD +#if SESSION_TRACKING_SYSTEMD #include <systemd/sd-login.h> #define LOGIND_NAME "systemd-logind" #endif -#ifdef SESSION_TRACKING_ELOGIND +#if SESSION_TRACKING_ELOGIND #include <elogind/sd-login.h> #define LOGIND_NAME "elogind" -/* Re-Use SESSION_TRACKING_SYSTEMD as elogind substitutes systemd-login */ -#define SESSION_TRACKING_SYSTEMD 1 #endif #include "NetworkManagerUtils.h" +#define SESSION_TRACKING_XLOGIND (SESSION_TRACKING_SYSTEMD || SESSION_TRACKING_ELOGIND) + +#define CKDB_PATH "/var/run/ConsoleKit/database" + /*****************************************************************************/ enum { @@ -58,14 +60,14 @@ static guint signals[LAST_SIGNAL] = { 0 }; struct _NMSessionMonitor { GObject parent; -#ifdef SESSION_TRACKING_SYSTEMD +#if SESSION_TRACKING_XLOGIND struct { sd_login_monitor *monitor; guint watch; } sd; #endif -#ifdef SESSION_TRACKING_CONSOLEKIT +#if SESSION_TRACKING_CONSOLEKIT struct { GFileMonitor *monitor; GHashTable *cache; @@ -85,7 +87,7 @@ G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT); /*****************************************************************************/ -#ifdef SESSION_TRACKING_SYSTEMD +#if SESSION_TRACKING_XLOGIND static gboolean st_sd_session_exists (NMSessionMonitor *monitor, uid_t uid, gboolean active) { @@ -143,11 +145,11 @@ st_sd_finalize (NMSessionMonitor *monitor) } nm_clear_g_source (&monitor->sd.watch); } -#endif /* SESSION_TRACKING_SYSTEMD */ +#endif /* SESSION_TRACKING_XLOGIND */ /*****************************************************************************/ -#ifdef SESSION_TRACKING_CONSOLEKIT +#if SESSION_TRACKING_CONSOLEKIT typedef struct { gboolean active; } CkSession; @@ -186,7 +188,7 @@ ck_load_cache (GHashTable *cache) if (error) goto out; - g_hash_table_insert (cache, GUINT_TO_POINTER (uid), g_memdup (&session, sizeof session)); + g_hash_table_insert (cache, GUINT_TO_POINTER (uid), nm_memdup (&session, sizeof session)); } finished = TRUE; @@ -352,12 +354,12 @@ nm_session_monitor_session_exists (NMSessionMonitor *self, { g_return_val_if_fail (NM_IS_SESSION_MONITOR (self), FALSE); -#ifdef SESSION_TRACKING_SYSTEMD +#if SESSION_TRACKING_XLOGIND if (st_sd_session_exists (self, uid, active)) return TRUE; #endif -#ifdef SESSION_TRACKING_CONSOLEKIT +#if SESSION_TRACKING_CONSOLEKIT if (ck_session_exists (self, uid, active)) return TRUE; #endif @@ -370,12 +372,12 @@ nm_session_monitor_session_exists (NMSessionMonitor *self, static void nm_session_monitor_init (NMSessionMonitor *monitor) { -#ifdef SESSION_TRACKING_SYSTEMD +#if SESSION_TRACKING_XLOGIND st_sd_init (monitor); _LOGD ("using "LOGIND_NAME" session tracking"); #endif -#ifdef SESSION_TRACKING_CONSOLEKIT +#if SESSION_TRACKING_CONSOLEKIT ck_init (monitor); _LOGD ("using ConsoleKit session tracking"); #endif @@ -384,11 +386,11 @@ nm_session_monitor_init (NMSessionMonitor *monitor) static void finalize (GObject *object) { -#ifdef SESSION_TRACKING_SYSTEMD +#if SESSION_TRACKING_XLOGIND st_sd_finalize (NM_SESSION_MONITOR (object)); #endif -#ifdef SESSION_TRACKING_CONSOLEKIT +#if SESSION_TRACKING_CONSOLEKIT ck_finalize (NM_SESSION_MONITOR (object)); #endif diff --git a/src/nm-sleep-monitor.c b/src/nm-sleep-monitor.c index a7e3a7c3..54d75773 100644 --- a/src/nm-sleep-monitor.c +++ b/src/nm-sleep-monitor.c @@ -84,7 +84,7 @@ struct _NMSleepMonitor { /* used both during construction of proxy and during Inhibit call. */ GCancellable *cancellable; - gint inhibit_fd; + int inhibit_fd; GSList *handles_active; GSList *handles_stale; diff --git a/src/nm-test-utils-core.h b/src/nm-test-utils-core.h index c76f510f..5e89cb39 100644 --- a/src/nm-test-utils-core.h +++ b/src/nm-test-utils-core.h @@ -216,8 +216,8 @@ nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP g_assert (b); if (ignore_order) { - a = c_a = g_memdup (a, sizeof (NMPlatformIP4Route) * len); - b = c_b = g_memdup (b, sizeof (NMPlatformIP4Route) * len); + a = c_a = nm_memdup (a, sizeof (NMPlatformIP4Route) * len); + b = c_b = nm_memdup (b, sizeof (NMPlatformIP4Route) * len); g_qsort_with_data (c_a, len, sizeof (NMPlatformIP4Route), _nmtst_platform_ip4_routes_equal_sort, NULL); g_qsort_with_data (c_b, len, sizeof (NMPlatformIP4Route), _nmtst_platform_ip4_routes_equal_sort, NULL); } @@ -269,8 +269,8 @@ nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP g_assert (b); if (ignore_order) { - a = c_a = g_memdup (a, sizeof (NMPlatformIP6Route) * len); - b = c_b = g_memdup (b, sizeof (NMPlatformIP6Route) * len); + a = c_a = nm_memdup (a, sizeof (NMPlatformIP6Route) * len); + b = c_b = nm_memdup (b, sizeof (NMPlatformIP6Route) * len); g_qsort_with_data (c_a, len, sizeof (NMPlatformIP6Route), _nmtst_platform_ip6_routes_equal_sort, NULL); g_qsort_with_data (c_b, len, sizeof (NMPlatformIP6Route), _nmtst_platform_ip6_routes_equal_sort, NULL); } diff --git a/src/nm-types.h b/src/nm-types.h index 1477d226..a0a7f620 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -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) 2012 - 2017 Red Hat, Inc. + * Copyright (C) 2012 - 2018 Red Hat, Inc. */ #ifndef __NETWORKMANAGER_TYPES_H__ @@ -150,6 +150,8 @@ typedef enum { NM_LINK_TYPE_WIFI, NM_LINK_TYPE_WWAN_NET, /* WWAN kernel netdevice */ NM_LINK_TYPE_WIMAX, + NM_LINK_TYPE_WPAN, + NM_LINK_TYPE_6LOWPAN, /* Software types */ NM_LINK_TYPE_BNEP = 0x10000, /* Bluetooth Ethernet emulation */ @@ -158,6 +160,8 @@ typedef enum { NM_LINK_TYPE_GRETAP, NM_LINK_TYPE_IFB, NM_LINK_TYPE_IP6TNL, + NM_LINK_TYPE_IP6GRE, + NM_LINK_TYPE_IP6GRETAP, NM_LINK_TYPE_IPIP, NM_LINK_TYPE_LOOPBACK, NM_LINK_TYPE_MACSEC, @@ -170,6 +174,7 @@ typedef enum { NM_LINK_TYPE_VETH, NM_LINK_TYPE_VLAN, NM_LINK_TYPE_VXLAN, + NM_LINK_TYPE_WIREGUARD, /* Software types with slaves */ NM_LINK_TYPE_BRIDGE = 0x10000 | 0x20000, @@ -192,8 +197,11 @@ typedef enum { NMP_OBJECT_TYPE_TFILTER, NMP_OBJECT_TYPE_LNK_GRE, + NMP_OBJECT_TYPE_LNK_GRETAP, NMP_OBJECT_TYPE_LNK_INFINIBAND, NMP_OBJECT_TYPE_LNK_IP6TNL, + NMP_OBJECT_TYPE_LNK_IP6GRE, + NMP_OBJECT_TYPE_LNK_IP6GRETAP, NMP_OBJECT_TYPE_LNK_IPIP, NMP_OBJECT_TYPE_LNK_MACSEC, NMP_OBJECT_TYPE_LNK_MACVLAN, @@ -202,6 +210,7 @@ typedef enum { NMP_OBJECT_TYPE_LNK_TUN, NMP_OBJECT_TYPE_LNK_VLAN, NMP_OBJECT_TYPE_LNK_VXLAN, + NMP_OBJECT_TYPE_LNK_WIREGUARD, __NMP_OBJECT_TYPE_LAST, NMP_OBJECT_TYPE_MAX = __NMP_OBJECT_TYPE_LAST - 1, diff --git a/src/platform/linux/nl802154.h b/src/platform/linux/nl802154.h new file mode 100644 index 00000000..ddcee128 --- /dev/null +++ b/src/platform/linux/nl802154.h @@ -0,0 +1,452 @@ +#ifndef __NL802154_H +#define __NL802154_H +/* + * 802.15.4 netlink interface public header + * + * Copyright 2014 Alexander Aring <aar@pengutronix.de> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#define NL802154_GENL_NAME "nl802154" + +enum nl802154_commands { +/* don't change the order or add anything between, this is ABI! */ +/* currently we don't shipping this file via uapi, ignore the above one */ + NL802154_CMD_UNSPEC, + + NL802154_CMD_GET_WPAN_PHY, /* can dump */ + NL802154_CMD_SET_WPAN_PHY, + NL802154_CMD_NEW_WPAN_PHY, + NL802154_CMD_DEL_WPAN_PHY, + + NL802154_CMD_GET_INTERFACE, /* can dump */ + NL802154_CMD_SET_INTERFACE, + NL802154_CMD_NEW_INTERFACE, + NL802154_CMD_DEL_INTERFACE, + + NL802154_CMD_SET_CHANNEL, + + NL802154_CMD_SET_PAN_ID, + NL802154_CMD_SET_SHORT_ADDR, + + NL802154_CMD_SET_TX_POWER, + NL802154_CMD_SET_CCA_MODE, + NL802154_CMD_SET_CCA_ED_LEVEL, + + NL802154_CMD_SET_MAX_FRAME_RETRIES, + + NL802154_CMD_SET_BACKOFF_EXPONENT, + NL802154_CMD_SET_MAX_CSMA_BACKOFFS, + + NL802154_CMD_SET_LBT_MODE, + + NL802154_CMD_SET_ACKREQ_DEFAULT, + + NL802154_CMD_SET_WPAN_PHY_NETNS, + + /* add new commands above here */ + +#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL + NL802154_CMD_SET_SEC_PARAMS, + NL802154_CMD_GET_SEC_KEY, /* can dump */ + NL802154_CMD_NEW_SEC_KEY, + NL802154_CMD_DEL_SEC_KEY, + NL802154_CMD_GET_SEC_DEV, /* can dump */ + NL802154_CMD_NEW_SEC_DEV, + NL802154_CMD_DEL_SEC_DEV, + NL802154_CMD_GET_SEC_DEVKEY, /* can dump */ + NL802154_CMD_NEW_SEC_DEVKEY, + NL802154_CMD_DEL_SEC_DEVKEY, + NL802154_CMD_GET_SEC_LEVEL, /* can dump */ + NL802154_CMD_NEW_SEC_LEVEL, + NL802154_CMD_DEL_SEC_LEVEL, +#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ + + /* used to define NL802154_CMD_MAX below */ + __NL802154_CMD_AFTER_LAST, + NL802154_CMD_MAX = __NL802154_CMD_AFTER_LAST - 1 +}; + +enum nl802154_attrs { +/* don't change the order or add anything between, this is ABI! */ +/* currently we don't shipping this file via uapi, ignore the above one */ + NL802154_ATTR_UNSPEC, + + NL802154_ATTR_WPAN_PHY, + NL802154_ATTR_WPAN_PHY_NAME, + + NL802154_ATTR_IFINDEX, + NL802154_ATTR_IFNAME, + NL802154_ATTR_IFTYPE, + + NL802154_ATTR_WPAN_DEV, + + NL802154_ATTR_PAGE, + NL802154_ATTR_CHANNEL, + + NL802154_ATTR_PAN_ID, + NL802154_ATTR_SHORT_ADDR, + + NL802154_ATTR_TX_POWER, + + NL802154_ATTR_CCA_MODE, + NL802154_ATTR_CCA_OPT, + NL802154_ATTR_CCA_ED_LEVEL, + + NL802154_ATTR_MAX_FRAME_RETRIES, + + NL802154_ATTR_MAX_BE, + NL802154_ATTR_MIN_BE, + NL802154_ATTR_MAX_CSMA_BACKOFFS, + + NL802154_ATTR_LBT_MODE, + + NL802154_ATTR_GENERATION, + + NL802154_ATTR_CHANNELS_SUPPORTED, + NL802154_ATTR_SUPPORTED_CHANNEL, + + NL802154_ATTR_EXTENDED_ADDR, + + NL802154_ATTR_WPAN_PHY_CAPS, + + NL802154_ATTR_SUPPORTED_COMMANDS, + + NL802154_ATTR_ACKREQ_DEFAULT, + + NL802154_ATTR_PAD, + + NL802154_ATTR_PID, + NL802154_ATTR_NETNS_FD, + + /* add attributes here, update the policy in nl802154.c */ + +#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL + NL802154_ATTR_SEC_ENABLED, + NL802154_ATTR_SEC_OUT_LEVEL, + NL802154_ATTR_SEC_OUT_KEY_ID, + NL802154_ATTR_SEC_FRAME_COUNTER, + + NL802154_ATTR_SEC_LEVEL, + NL802154_ATTR_SEC_DEVICE, + NL802154_ATTR_SEC_DEVKEY, + NL802154_ATTR_SEC_KEY, +#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ + + __NL802154_ATTR_AFTER_LAST, + NL802154_ATTR_MAX = __NL802154_ATTR_AFTER_LAST - 1 +}; + +enum nl802154_iftype { + /* for backwards compatibility TODO */ + NL802154_IFTYPE_UNSPEC = -1, + + NL802154_IFTYPE_NODE, + NL802154_IFTYPE_MONITOR, + NL802154_IFTYPE_COORD, + + /* keep last */ + NUM_NL802154_IFTYPES, + NL802154_IFTYPE_MAX = NUM_NL802154_IFTYPES - 1 +}; + +/** + * enum nl802154_wpan_phy_capability_attr - wpan phy capability attributes + * + * @__NL802154_CAP_ATTR_INVALID: attribute number 0 is reserved + * @NL802154_CAP_ATTR_CHANNELS: a nested attribute for nl802154_channel_attr + * @NL802154_CAP_ATTR_TX_POWERS: a nested attribute for + * nl802154_wpan_phy_tx_power + * @NL802154_CAP_ATTR_MIN_CCA_ED_LEVEL: minimum value for cca_ed_level + * @NL802154_CAP_ATTR_MAX_CCA_ED_LEVEL: maxmimum value for cca_ed_level + * @NL802154_CAP_ATTR_CCA_MODES: nl802154_cca_modes flags + * @NL802154_CAP_ATTR_CCA_OPTS: nl802154_cca_opts flags + * @NL802154_CAP_ATTR_MIN_MINBE: minimum of minbe value + * @NL802154_CAP_ATTR_MAX_MINBE: maximum of minbe value + * @NL802154_CAP_ATTR_MIN_MAXBE: minimum of maxbe value + * @NL802154_CAP_ATTR_MAX_MINBE: maximum of maxbe value + * @NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS: minimum of csma backoff value + * @NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS: maximum of csma backoffs value + * @NL802154_CAP_ATTR_MIN_FRAME_RETRIES: minimum of frame retries value + * @NL802154_CAP_ATTR_MAX_FRAME_RETRIES: maximum of frame retries value + * @NL802154_CAP_ATTR_IFTYPES: nl802154_iftype flags + * @NL802154_CAP_ATTR_LBT: nl802154_supported_bool_states flags + * @NL802154_CAP_ATTR_MAX: highest cap attribute currently defined + * @__NL802154_CAP_ATTR_AFTER_LAST: internal use + */ +enum nl802154_wpan_phy_capability_attr { + __NL802154_CAP_ATTR_INVALID, + + NL802154_CAP_ATTR_IFTYPES, + + NL802154_CAP_ATTR_CHANNELS, + NL802154_CAP_ATTR_TX_POWERS, + + NL802154_CAP_ATTR_CCA_ED_LEVELS, + NL802154_CAP_ATTR_CCA_MODES, + NL802154_CAP_ATTR_CCA_OPTS, + + NL802154_CAP_ATTR_MIN_MINBE, + NL802154_CAP_ATTR_MAX_MINBE, + + NL802154_CAP_ATTR_MIN_MAXBE, + NL802154_CAP_ATTR_MAX_MAXBE, + + NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS, + NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS, + + NL802154_CAP_ATTR_MIN_FRAME_RETRIES, + NL802154_CAP_ATTR_MAX_FRAME_RETRIES, + + NL802154_CAP_ATTR_LBT, + + /* keep last */ + __NL802154_CAP_ATTR_AFTER_LAST, + NL802154_CAP_ATTR_MAX = __NL802154_CAP_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl802154_cca_modes - cca modes + * + * @__NL802154_CCA_INVALID: cca mode number 0 is reserved + * @NL802154_CCA_ENERGY: Energy above threshold + * @NL802154_CCA_CARRIER: Carrier sense only + * @NL802154_CCA_ENERGY_CARRIER: Carrier sense with energy above threshold + * @NL802154_CCA_ALOHA: CCA shall always report an idle medium + * @NL802154_CCA_UWB_SHR: UWB preamble sense based on the SHR of a frame + * @NL802154_CCA_UWB_MULTIPLEXED: UWB preamble sense based on the packet with + * the multiplexed preamble + * @__NL802154_CCA_ATTR_AFTER_LAST: Internal + * @NL802154_CCA_ATTR_MAX: Maximum CCA attribute number + */ +enum nl802154_cca_modes { + __NL802154_CCA_INVALID, + NL802154_CCA_ENERGY, + NL802154_CCA_CARRIER, + NL802154_CCA_ENERGY_CARRIER, + NL802154_CCA_ALOHA, + NL802154_CCA_UWB_SHR, + NL802154_CCA_UWB_MULTIPLEXED, + + /* keep last */ + __NL802154_CCA_ATTR_AFTER_LAST, + NL802154_CCA_ATTR_MAX = __NL802154_CCA_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl802154_cca_opts - additional options for cca modes + * + * @NL802154_CCA_OPT_ENERGY_CARRIER_OR: NL802154_CCA_ENERGY_CARRIER with OR + * @NL802154_CCA_OPT_ENERGY_CARRIER_AND: NL802154_CCA_ENERGY_CARRIER with AND + */ +enum nl802154_cca_opts { + NL802154_CCA_OPT_ENERGY_CARRIER_AND, + NL802154_CCA_OPT_ENERGY_CARRIER_OR, + + /* keep last */ + __NL802154_CCA_OPT_ATTR_AFTER_LAST, + NL802154_CCA_OPT_ATTR_MAX = __NL802154_CCA_OPT_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl802154_supported_bool_states - bool states for bool capability entry + * + * @NL802154_SUPPORTED_BOOL_FALSE: indicates to set false + * @NL802154_SUPPORTED_BOOL_TRUE: indicates to set true + * @__NL802154_SUPPORTED_BOOL_INVALD: reserved + * @NL802154_SUPPORTED_BOOL_BOTH: indicates to set true and false + * @__NL802154_SUPPORTED_BOOL_AFTER_LAST: Internal + * @NL802154_SUPPORTED_BOOL_MAX: highest value for bool states + */ +enum nl802154_supported_bool_states { + NL802154_SUPPORTED_BOOL_FALSE, + NL802154_SUPPORTED_BOOL_TRUE, + /* to handle them in a mask */ + __NL802154_SUPPORTED_BOOL_INVALD, + NL802154_SUPPORTED_BOOL_BOTH, + + /* keep last */ + __NL802154_SUPPORTED_BOOL_AFTER_LAST, + NL802154_SUPPORTED_BOOL_MAX = __NL802154_SUPPORTED_BOOL_AFTER_LAST - 1 +}; + +#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL + +enum nl802154_dev_addr_modes { + NL802154_DEV_ADDR_NONE, + __NL802154_DEV_ADDR_INVALID, + NL802154_DEV_ADDR_SHORT, + NL802154_DEV_ADDR_EXTENDED, + + /* keep last */ + __NL802154_DEV_ADDR_AFTER_LAST, + NL802154_DEV_ADDR_MAX = __NL802154_DEV_ADDR_AFTER_LAST - 1 +}; + +enum nl802154_dev_addr_attrs { + NL802154_DEV_ADDR_ATTR_UNSPEC, + + NL802154_DEV_ADDR_ATTR_PAN_ID, + NL802154_DEV_ADDR_ATTR_MODE, + NL802154_DEV_ADDR_ATTR_SHORT, + NL802154_DEV_ADDR_ATTR_EXTENDED, + NL802154_DEV_ADDR_ATTR_PAD, + + /* keep last */ + __NL802154_DEV_ADDR_ATTR_AFTER_LAST, + NL802154_DEV_ADDR_ATTR_MAX = __NL802154_DEV_ADDR_ATTR_AFTER_LAST - 1 +}; + +enum nl802154_key_id_modes { + NL802154_KEY_ID_MODE_IMPLICIT, + NL802154_KEY_ID_MODE_INDEX, + NL802154_KEY_ID_MODE_INDEX_SHORT, + NL802154_KEY_ID_MODE_INDEX_EXTENDED, + + /* keep last */ + __NL802154_KEY_ID_MODE_AFTER_LAST, + NL802154_KEY_ID_MODE_MAX = __NL802154_KEY_ID_MODE_AFTER_LAST - 1 +}; + +enum nl802154_key_id_attrs { + NL802154_KEY_ID_ATTR_UNSPEC, + + NL802154_KEY_ID_ATTR_MODE, + NL802154_KEY_ID_ATTR_INDEX, + NL802154_KEY_ID_ATTR_IMPLICIT, + NL802154_KEY_ID_ATTR_SOURCE_SHORT, + NL802154_KEY_ID_ATTR_SOURCE_EXTENDED, + NL802154_KEY_ID_ATTR_PAD, + + /* keep last */ + __NL802154_KEY_ID_ATTR_AFTER_LAST, + NL802154_KEY_ID_ATTR_MAX = __NL802154_KEY_ID_ATTR_AFTER_LAST - 1 +}; + +enum nl802154_seclevels { + NL802154_SECLEVEL_NONE, + NL802154_SECLEVEL_MIC32, + NL802154_SECLEVEL_MIC64, + NL802154_SECLEVEL_MIC128, + NL802154_SECLEVEL_ENC, + NL802154_SECLEVEL_ENC_MIC32, + NL802154_SECLEVEL_ENC_MIC64, + NL802154_SECLEVEL_ENC_MIC128, + + /* keep last */ + __NL802154_SECLEVEL_AFTER_LAST, + NL802154_SECLEVEL_MAX = __NL802154_SECLEVEL_AFTER_LAST - 1 +}; + +enum nl802154_frames { + NL802154_FRAME_BEACON, + NL802154_FRAME_DATA, + NL802154_FRAME_ACK, + NL802154_FRAME_CMD, + + /* keep last */ + __NL802154_FRAME_AFTER_LAST, + NL802154_FRAME_MAX = __NL802154_FRAME_AFTER_LAST - 1 +}; + +enum nl802154_cmd_frames { + __NL802154_CMD_FRAME_INVALID, + NL802154_CMD_FRAME_ASSOC_REQUEST, + NL802154_CMD_FRAME_ASSOC_RESPONSE, + NL802154_CMD_FRAME_DISASSOC_NOTIFY, + NL802154_CMD_FRAME_DATA_REQUEST, + NL802154_CMD_FRAME_PAN_ID_CONFLICT_NOTIFY, + NL802154_CMD_FRAME_ORPHAN_NOTIFY, + NL802154_CMD_FRAME_BEACON_REQUEST, + NL802154_CMD_FRAME_COORD_REALIGNMENT, + NL802154_CMD_FRAME_GTS_REQUEST, + + /* keep last */ + __NL802154_CMD_FRAME_AFTER_LAST, + NL802154_CMD_FRAME_MAX = __NL802154_CMD_FRAME_AFTER_LAST - 1 +}; + +enum nl802154_seclevel_attrs { + NL802154_SECLEVEL_ATTR_UNSPEC, + + NL802154_SECLEVEL_ATTR_LEVELS, + NL802154_SECLEVEL_ATTR_FRAME, + NL802154_SECLEVEL_ATTR_CMD_FRAME, + NL802154_SECLEVEL_ATTR_DEV_OVERRIDE, + + /* keep last */ + __NL802154_SECLEVEL_ATTR_AFTER_LAST, + NL802154_SECLEVEL_ATTR_MAX = __NL802154_SECLEVEL_ATTR_AFTER_LAST - 1 +}; + +/* TODO what is this? couldn't find in mib */ +enum { + NL802154_DEVKEY_IGNORE, + NL802154_DEVKEY_RESTRICT, + NL802154_DEVKEY_RECORD, + + /* keep last */ + __NL802154_DEVKEY_AFTER_LAST, + NL802154_DEVKEY_MAX = __NL802154_DEVKEY_AFTER_LAST - 1 +}; + +enum nl802154_dev { + NL802154_DEV_ATTR_UNSPEC, + + NL802154_DEV_ATTR_FRAME_COUNTER, + NL802154_DEV_ATTR_PAN_ID, + NL802154_DEV_ATTR_SHORT_ADDR, + NL802154_DEV_ATTR_EXTENDED_ADDR, + NL802154_DEV_ATTR_SECLEVEL_EXEMPT, + NL802154_DEV_ATTR_KEY_MODE, + NL802154_DEV_ATTR_PAD, + + /* keep last */ + __NL802154_DEV_ATTR_AFTER_LAST, + NL802154_DEV_ATTR_MAX = __NL802154_DEV_ATTR_AFTER_LAST - 1 +}; + +enum nl802154_devkey { + NL802154_DEVKEY_ATTR_UNSPEC, + + NL802154_DEVKEY_ATTR_FRAME_COUNTER, + NL802154_DEVKEY_ATTR_EXTENDED_ADDR, + NL802154_DEVKEY_ATTR_ID, + NL802154_DEVKEY_ATTR_PAD, + + /* keep last */ + __NL802154_DEVKEY_ATTR_AFTER_LAST, + NL802154_DEVKEY_ATTR_MAX = __NL802154_DEVKEY_ATTR_AFTER_LAST - 1 +}; + +enum nl802154_key { + NL802154_KEY_ATTR_UNSPEC, + + NL802154_KEY_ATTR_ID, + NL802154_KEY_ATTR_USAGE_FRAMES, + NL802154_KEY_ATTR_USAGE_CMDS, + NL802154_KEY_ATTR_BYTES, + + /* keep last */ + __NL802154_KEY_ATTR_AFTER_LAST, + NL802154_KEY_ATTR_MAX = __NL802154_KEY_ATTR_AFTER_LAST - 1 +}; + +#define NL802154_KEY_SIZE 16 +#define NL802154_CMD_FRAME_NR_IDS 256 + +#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ + +#endif /* __NL802154_H */ diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index f8f4627e..82f9e2fb 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -602,12 +602,6 @@ link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu) return NM_PLATFORM_ERROR_SUCCESS; } -static gboolean -link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs) -{ - return TRUE; -} - static const char * link_get_udi (NMPlatform *platform, int ifindex) { @@ -893,12 +887,6 @@ wifi_get_bssid (NMPlatform *platform, int ifindex, guint8 *bssid) return FALSE; } -static GByteArray * -wifi_get_ssid (NMPlatform *platform, int ifindex) -{ - return NULL; -} - static guint32 wifi_get_frequency (NMPlatform *platform, int ifindex) { @@ -1422,7 +1410,6 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->link_set_address = link_set_address; platform_class->link_set_mtu = link_set_mtu; - platform_class->link_set_sriov_num_vfs = link_set_sriov_num_vfs; platform_class->link_get_driver_info = link_get_driver_info; @@ -1442,7 +1429,6 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->wifi_get_capabilities = wifi_get_capabilities; platform_class->wifi_get_bssid = wifi_get_bssid; - platform_class->wifi_get_ssid = wifi_get_ssid; platform_class->wifi_get_frequency = wifi_get_frequency; platform_class->wifi_get_quality = wifi_get_quality; platform_class->wifi_get_rate = wifi_get_rate; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 9bd662a1..e73d5d8c 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.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) 2012 - 2017 Red Hat, Inc. + * Copyright (C) 2012 - 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -44,15 +44,18 @@ #include "nm-core-internal.h" #include "nm-setting-vlan.h" +#include "nm-utils/nm-secret-utils.h" #include "nm-netlink.h" #include "nm-core-utils.h" #include "nmp-object.h" #include "nmp-netns.h" #include "nm-platform-utils.h" #include "nm-platform-private.h" -#include "wifi/wifi-utils.h" -#include "wifi/wifi-utils-wext.h" +#include "wifi/nm-wifi-utils.h" +#include "wifi/nm-wifi-utils-wext.h" +#include "wpan/nm-wpan-utils.h" #include "nm-utils/unaligned.h" +#include "nm-utils/nm-io-utils.h" #include "nm-utils/nm-udev-utils.h" /*****************************************************************************/ @@ -154,6 +157,13 @@ G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1)); /*****************************************************************************/ +/* Appeared in in kernel prior to 3.13 dated 19 January, 2014 */ +#ifndef ARPHRD_6LOWPAN +#define ARPHRD_6LOWPAN 825 +#endif + +/*****************************************************************************/ + #define IFLA_MACSEC_UNSPEC 0 #define IFLA_MACSEC_SCI 1 #define IFLA_MACSEC_PORT 2 @@ -173,63 +183,79 @@ G_STATIC_ASSERT (RTA_MAX == (__RTA_MAX - 1)); /*****************************************************************************/ -#define _NMLOG_PREFIX_NAME "platform-linux" -#define _NMLOG_DOMAIN LOGD_PLATFORM -#define _NMLOG2_DOMAIN LOGD_PLATFORM -#define _NMLOG(level, ...) _LOG ( level, _NMLOG_DOMAIN, platform, __VA_ARGS__) -#define _NMLOG_err(errsv, level, ...) _LOG_err (errsv, level, _NMLOG_DOMAIN, platform, __VA_ARGS__) -#define _NMLOG2(level, ...) _LOG ( level, _NMLOG2_DOMAIN, NULL, __VA_ARGS__) -#define _NMLOG2_err(errsv, level, ...) _LOG_err (errsv, level, _NMLOG2_DOMAIN, NULL, __VA_ARGS__) +#define WG_CMD_GET_DEVICE 0 +#define WG_CMD_SET_DEVICE 1 + +#define WGDEVICE_A_UNSPEC 0 +#define WGDEVICE_A_IFINDEX 1 +#define WGDEVICE_A_IFNAME 2 +#define WGDEVICE_A_PRIVATE_KEY 3 +#define WGDEVICE_A_PUBLIC_KEY 4 +#define WGDEVICE_A_FLAGS 5 +#define WGDEVICE_A_LISTEN_PORT 6 +#define WGDEVICE_A_FWMARK 7 +#define WGDEVICE_A_PEERS 8 +#define WGDEVICE_A_MAX 8 + +#define WGPEER_A_UNSPEC 0 +#define WGPEER_A_PUBLIC_KEY 1 +#define WGPEER_A_PRESHARED_KEY 2 +#define WGPEER_A_FLAGS 3 +#define WGPEER_A_ENDPOINT 4 +#define WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL 5 +#define WGPEER_A_LAST_HANDSHAKE_TIME 6 +#define WGPEER_A_RX_BYTES 7 +#define WGPEER_A_TX_BYTES 8 +#define WGPEER_A_ALLOWEDIPS 9 +#define WGPEER_A_MAX 9 + +#define WGALLOWEDIP_A_UNSPEC 0 +#define WGALLOWEDIP_A_FAMILY 1 +#define WGALLOWEDIP_A_IPADDR 2 +#define WGALLOWEDIP_A_CIDR_MASK 3 +#define WGALLOWEDIP_A_MAX 3 -#define _LOG_print(__level, __domain, __errsv, self, ...) \ - G_STMT_START { \ - char __prefix[32]; \ - const char *__p_prefix = _NMLOG_PREFIX_NAME; \ - NMPlatform *const __self = (self); \ - \ - if (__self && nm_platform_get_log_with_ptr (__self)) { \ - g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ - __p_prefix = __prefix; \ - } \ - _nm_log (__level, __domain, __errsv, NULL, NULL, \ - "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ - __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ - } G_STMT_END +/*****************************************************************************/ -#define _LOG(level, domain, self, ...) \ - G_STMT_START { \ - const NMLogLevel __level = (level); \ - const NMLogDomain __domain = (domain); \ - \ - if (nm_logging_enabled (__level, __domain)) { \ - _LOG_print (__level, __domain, 0, self, __VA_ARGS__); \ - } \ - } G_STMT_END +/* Redefine VF enums and structures that are not available on older kernels. */ + +#define IFLA_VF_UNSPEC 0 +#define IFLA_VF_MAC 1 +#define IFLA_VF_VLAN 2 +#define IFLA_VF_TX_RATE 3 +#define IFLA_VF_SPOOFCHK 4 +#define IFLA_VF_LINK_STATE 5 +#define IFLA_VF_RATE 6 +#define IFLA_VF_RSS_QUERY_EN 7 +#define IFLA_VF_STATS 8 +#define IFLA_VF_TRUST 9 +#define IFLA_VF_IB_NODE_GUID 10 +#define IFLA_VF_IB_PORT_GUID 11 +#define IFLA_VF_VLAN_LIST 12 + +#define IFLA_VF_VLAN_INFO_UNSPEC 0 +#define IFLA_VF_VLAN_INFO 1 + +/* valid for TRUST, SPOOFCHK, LINK_STATE, RSS_QUERY_EN */ +struct _ifla_vf_setting { + guint32 vf; + guint32 setting; +}; -#define _LOG_err(errsv, level, domain, self, ...) \ - G_STMT_START { \ - const NMLogLevel __level = (level); \ - const NMLogDomain __domain = (domain); \ - \ - if (nm_logging_enabled (__level, __domain)) { \ - int __errsv = (errsv); \ - \ - /* The %m format specifier (GNU extension) would alread allow you to specify the error - * message conveniently (and nm_log would get that right too). But we don't want to depend - * on that, so instead append the message at the end. - * Currently users are expected not to use %m in the format string. */ \ - _LOG_print (__level, __domain, __errsv, self, \ - _NM_UTILS_MACRO_FIRST (__VA_ARGS__) ": %s (%d)" \ - _NM_UTILS_MACRO_REST (__VA_ARGS__), \ - g_strerror (__errsv), __errsv); \ - } \ - } G_STMT_END +struct _ifla_vf_rate { + guint32 vf; + guint32 min_tx_rate; + guint32 max_tx_rate; +}; -#define LOG_FMT_IP_TUNNEL "adding %s '%s' parent %u local %s remote %s" +struct _ifla_vf_vlan_info { + guint32 vf; + guint32 vlan; /* 0 - 4095, 0 disables VLAN filter */ + guint32 qos; + guint16 vlan_proto; /* VLAN protocol, either 802.1Q or 802.1ad */ +}; -/****************************************************************** - * Forward declarations and enums - ******************************************************************/ +/*****************************************************************************/ typedef enum { INFINIBAND_ACTION_CREATE_CHILD, @@ -307,6 +333,133 @@ typedef enum { WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS, } WaitForNlResponseResult; +typedef enum { + DELAYED_ACTION_RESPONSE_TYPE_VOID = 0, + DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS = 1, + DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET = 2, +} DelayedActionWaitForNlResponseType; + +typedef struct { + guint32 seq_number; + WaitForNlResponseResult seq_result; + DelayedActionWaitForNlResponseType response_type; + gint64 timeout_abs_ns; + WaitForNlResponseResult *out_seq_result; + char **out_errmsg; + union { + int *out_refresh_all_in_progress; + NMPObject **out_route_get; + gpointer out_data; + } response; +} DelayedActionWaitForNlResponseData; + +/*****************************************************************************/ + +typedef struct { + struct nl_sock *genl; + + struct nl_sock *nlh; + guint32 nlh_seq_next; +#if NM_MORE_LOGGING + guint32 nlh_seq_last_handled; +#endif + guint32 nlh_seq_last_seen; + GIOChannel *event_channel; + guint event_id; + + bool pruning[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM]; + + bool sysctl_get_warned; + GHashTable *sysctl_get_prev_values; + + NMUdevClient *udev_client; + + struct { + /* which delayed actions are scheduled, as marked in @flags. + * Some types have additional arguments in the fields below. */ + DelayedActionType flags; + + /* counter that a refresh all action is in progress, separated + * by type. */ + int refresh_all_in_progress[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM]; + + GPtrArray *list_master_connected; + GPtrArray *list_refresh_link; + GArray *list_wait_for_nl_response; + + int is_handling; + } delayed_action; +} NMLinuxPlatformPrivate; + +struct _NMLinuxPlatform { + NMPlatform parent; + NMLinuxPlatformPrivate _priv; +}; + +struct _NMLinuxPlatformClass { + NMPlatformClass parent; +}; + +G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM) + +#define NM_LINUX_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMLinuxPlatform, NM_IS_LINUX_PLATFORM, NMPlatform) + +/*****************************************************************************/ + +#define _NMLOG_PREFIX_NAME "platform-linux" +#define _NMLOG_DOMAIN LOGD_PLATFORM +#define _NMLOG2_DOMAIN LOGD_PLATFORM +#define _NMLOG(level, ...) _LOG ( level, _NMLOG_DOMAIN, platform, __VA_ARGS__) +#define _NMLOG_err(errsv, level, ...) _LOG_err (errsv, level, _NMLOG_DOMAIN, platform, __VA_ARGS__) +#define _NMLOG2(level, ...) _LOG ( level, _NMLOG2_DOMAIN, NULL, __VA_ARGS__) +#define _NMLOG2_err(errsv, level, ...) _LOG_err (errsv, level, _NMLOG2_DOMAIN, NULL, __VA_ARGS__) + +#define _LOG_print(__level, __domain, __errsv, self, ...) \ + G_STMT_START { \ + char __prefix[32]; \ + const char *__p_prefix = _NMLOG_PREFIX_NAME; \ + NMPlatform *const __self = (self); \ + \ + if (__self && nm_platform_get_log_with_ptr (__self)) { \ + g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ + __p_prefix = __prefix; \ + } \ + _nm_log (__level, __domain, __errsv, NULL, NULL, \ + "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } G_STMT_END + +#define _LOG(level, domain, self, ...) \ + G_STMT_START { \ + const NMLogLevel __level = (level); \ + const NMLogDomain __domain = (domain); \ + \ + if (nm_logging_enabled (__level, __domain)) { \ + _LOG_print (__level, __domain, 0, self, __VA_ARGS__); \ + } \ + } G_STMT_END + +#define _LOG_err(errsv, level, domain, self, ...) \ + G_STMT_START { \ + const NMLogLevel __level = (level); \ + const NMLogDomain __domain = (domain); \ + \ + if (nm_logging_enabled (__level, __domain)) { \ + int __errsv = (errsv); \ + \ + /* The %m format specifier (GNU extension) would alread allow you to specify the error + * message conveniently (and nm_log would get that right too). But we don't want to depend + * on that, so instead append the message at the end. + * Currently users are expected not to use %m in the format string. */ \ + _LOG_print (__level, __domain, __errsv, self, \ + _NM_UTILS_MACRO_FIRST (__VA_ARGS__) ": %s (%d)" \ + _NM_UTILS_MACRO_REST (__VA_ARGS__), \ + g_strerror (__errsv), __errsv); \ + } \ + } G_STMT_END + +/*****************************************************************************/ + static void delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gpointer user_data); static gboolean delayed_action_handle_all (NMPlatform *platform, gboolean read_netlink); static void do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const char *name); @@ -317,6 +470,7 @@ static void cache_on_change (NMPlatform *platform, const NMPObject *obj_new); static void cache_prune_all (NMPlatform *platform); static gboolean event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks); +static struct nl_sock *_genl_sock (NMLinuxPlatform *platform); /*****************************************************************************/ @@ -533,6 +687,8 @@ static const LinkDesc linktypes[] = { { NM_LINK_TYPE_WIFI, "wifi", NULL, "wlan" }, { NM_LINK_TYPE_WWAN_NET, "wwan", NULL, "wwan" }, { NM_LINK_TYPE_WIMAX, "wimax", "wimax", "wimax" }, + { NM_LINK_TYPE_WPAN, "wpan", NULL, NULL }, + { NM_LINK_TYPE_6LOWPAN, "6lowpan", NULL, NULL }, { NM_LINK_TYPE_BNEP, "bluetooth", NULL, "bluetooth" }, { NM_LINK_TYPE_DUMMY, "dummy", "dummy", NULL }, @@ -540,6 +696,8 @@ static const LinkDesc linktypes[] = { { NM_LINK_TYPE_GRETAP, "gretap", "gretap", NULL }, { NM_LINK_TYPE_IFB, "ifb", "ifb", NULL }, { NM_LINK_TYPE_IP6TNL, "ip6tnl", "ip6tnl", NULL }, + { NM_LINK_TYPE_IP6GRE, "ip6gre", "ip6gre", NULL }, + { NM_LINK_TYPE_IP6GRETAP, "ip6gretap", "ip6gretap", NULL }, { NM_LINK_TYPE_IPIP, "ipip", "ipip", NULL }, { NM_LINK_TYPE_LOOPBACK, "loopback", NULL, NULL }, { NM_LINK_TYPE_MACSEC, "macsec", "macsec", NULL }, @@ -552,6 +710,7 @@ static const LinkDesc linktypes[] = { { NM_LINK_TYPE_VETH, "veth", "veth", NULL }, { NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" }, { NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" }, + { NM_LINK_TYPE_WIREGUARD, "wireguard", "wireguard", "wireguard" }, { NM_LINK_TYPE_BRIDGE, "bridge", "bridge", "bridge" }, { NM_LINK_TYPE_BOND, "bond", "bond", "bond" }, @@ -725,19 +884,21 @@ _addrtime_get_lifetimes (guint32 timestamp, /*****************************************************************************/ static const NMPObject * -_lookup_cached_link (const NMPCache *cache, int ifindex, gboolean *completed_from_cache, const NMPObject **link_cached) +_lookup_cached_link (const NMPCache *cache, + int ifindex, + gboolean *completed_from_cache, + const NMPObject **link_cached) { const NMPObject *obj; nm_assert (completed_from_cache && link_cached); if (!*completed_from_cache) { - obj = ifindex > 0 && cache ? nmp_cache_lookup_link (cache, ifindex) : NULL; + obj = ifindex > 0 && cache + ? nmp_cache_lookup_link (cache, ifindex) + : NULL; - if (obj && obj->_link.netlink.is_in_netlink) - *link_cached = obj; - else - *link_cached = NULL; + *link_cached = obj; *completed_from_cache = TRUE; } return *link_cached; @@ -755,7 +916,9 @@ _linktype_read_devtype (int dirfd) nm_assert (dirfd >= 0); - if (nm_utils_file_get_contents (dirfd, "uevent", 1*1024*1024, &contents, NULL, NULL) < 0) + if (nm_utils_file_get_contents (dirfd, "uevent", 1*1024*1024, + NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, + &contents, NULL, NULL) < 0) return NULL; for (cont = contents; cont; cont = end) { end = strpbrk (cont, "\r\n"); @@ -806,6 +969,7 @@ _linktype_get_type (NMPlatform *platform, * when moving interfce to other netns). Thus here there is a tiny potential * of messing stuff up. */ if ( obj + && obj->_link.netlink.is_in_netlink && !NM_IN_SET (obj->link.type, NM_LINK_TYPE_UNKNOWN, NM_LINK_TYPE_NONE) && nm_streq (ifname, obj->link.name) && ( !kind @@ -841,6 +1005,10 @@ _linktype_get_type (NMPlatform *platform, return NM_LINK_TYPE_IP6TNL; else if (arptype == ARPHRD_PPP) return NM_LINK_TYPE_PPP; + else if (arptype == ARPHRD_IEEE802154) + return NM_LINK_TYPE_WPAN; + else if (arptype == ARPHRD_6LOWPAN) + return NM_LINK_TYPE_6LOWPAN; { NMPUtilsEthtoolDriverInfo driver_info; @@ -885,7 +1053,7 @@ _linktype_get_type (NMPlatform *platform, } /* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */ - if (wifi_utils_is_wifi (dirfd, ifname_verified)) + if (nm_wifi_utils_is_wifi (dirfd, ifname_verified)) return NM_LINK_TYPE_WIFI; } @@ -953,18 +1121,21 @@ _nl_addattr_l (struct nlmsghdr *n, * NMPObject/netlink functions ******************************************************************/ -#define _check_addr_or_errout(tb, attr, addr_len) \ +#define _check_addr_or_return_val(tb, attr, addr_len, ret_val) \ ({ \ const struct nlattr *__t = (tb)[(attr)]; \ \ if (__t) { \ if (nla_len (__t) != (addr_len)) { \ - goto errout; \ + return ret_val; \ } \ } \ !!__t; \ }) +#define _check_addr_or_return_null(tb, attr, addr_len) \ + _check_addr_or_return_val (tb, attr, addr_len, NULL) + /*****************************************************************************/ /* Copied and heavily modified from libnl3's inet6_parse_protinfo(). */ @@ -991,20 +1162,19 @@ _parse_af_inet6 (NMPlatform *platform, gboolean token_valid = FALSE; gboolean addr_gen_mode_valid = FALSE; guint8 i6_addr_gen_mode_inv = 0; - gboolean success = FALSE; err = nla_parse_nested (tb, IFLA_INET6_MAX, attr, policy); if (err < 0) - goto errout; + return FALSE; if (tb[IFLA_INET6_CONF] && nla_len(tb[IFLA_INET6_CONF]) % 4) - goto errout; + return FALSE; if (tb[IFLA_INET6_STATS] && nla_len(tb[IFLA_INET6_STATS]) % 8) - goto errout; + return FALSE; if (tb[IFLA_INET6_ICMP6STATS] && nla_len(tb[IFLA_INET6_ICMP6STATS]) % 8) - goto errout; + return FALSE; - if (_check_addr_or_errout (tb, IFLA_INET6_TOKEN, sizeof (struct in6_addr))) { + if (_check_addr_or_return_val (tb, IFLA_INET6_TOKEN, sizeof (struct in6_addr), FALSE)) { nla_memcpy (&i6_token, tb[IFLA_INET6_TOKEN], sizeof (struct in6_addr)); token_valid = TRUE; } @@ -1020,12 +1190,11 @@ _parse_af_inet6 (NMPlatform *platform, if (i6_addr_gen_mode_inv == 0) { /* an inverse addrgenmode of zero is unexpected. We need to reserve zero * to signal "unset". */ - goto errout; + return FALSE; } addr_gen_mode_valid = TRUE; } - success = TRUE; if (token_valid) { *out_token_valid = token_valid; nm_utils_ipv6_interface_identifier_get_from_addr (out_token, &i6_token); @@ -1034,8 +1203,7 @@ _parse_af_inet6 (NMPlatform *platform, *out_addr_gen_mode_valid = addr_gen_mode_valid; *out_addr_gen_mode_inv = i6_addr_gen_mode_inv; } -errout: - return success; + return TRUE; } /*****************************************************************************/ @@ -1059,15 +1227,23 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data) int err; NMPObject *obj; NMPlatformLnkGre *props; + gboolean is_tap; + + if (!info_data || !kind) + return NULL; - if (!info_data || g_strcmp0 (kind, "gre")) + if (nm_streq (kind, "gretap")) + is_tap = TRUE; + else if (nm_streq (kind, "gre")) + is_tap = FALSE; + else return NULL; err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy); if (err < 0) return NULL; - obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_GRE, NULL); + obj = nmp_object_new (is_tap ? NMP_OBJECT_TYPE_LNK_GRETAP : NMP_OBJECT_TYPE_LNK_GRE, NULL); props = &obj->lnk_gre; props->parent_ifindex = tb[IFLA_GRE_LINK] ? nla_get_u32 (tb[IFLA_GRE_LINK]) : 0; @@ -1080,6 +1256,7 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data) props->tos = tb[IFLA_GRE_TOS] ? nla_get_u8 (tb[IFLA_GRE_TOS]) : 0; props->ttl = tb[IFLA_GRE_TTL] ? nla_get_u8 (tb[IFLA_GRE_TTL]) : 0; props->path_mtu_discovery = !tb[IFLA_GRE_PMTUDISC] || !!nla_get_u8 (tb[IFLA_GRE_PMTUDISC]); + props->is_tap = is_tap; return obj; } @@ -1200,6 +1377,79 @@ _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) return obj; } +static NMPObject * +_parse_lnk_ip6gre (const char *kind, struct nlattr *info_data) +{ + static const struct nla_policy policy[IFLA_GRE_MAX + 1] = { + [IFLA_GRE_LINK] = { .type = NLA_U32 }, + [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, + [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, + [IFLA_GRE_IKEY] = { .type = NLA_U32 }, + [IFLA_GRE_OKEY] = { .type = NLA_U32 }, + [IFLA_GRE_LOCAL] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct in6_addr)}, + [IFLA_GRE_REMOTE] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct in6_addr)}, + [IFLA_GRE_TTL] = { .type = NLA_U8 }, + [IFLA_GRE_ENCAP_LIMIT] = { .type = NLA_U8 }, + [IFLA_GRE_FLOWINFO] = { .type = NLA_U32 }, + [IFLA_GRE_FLAGS] = { .type = NLA_U32 }, + }; + struct nlattr *tb[IFLA_GRE_MAX + 1]; + int err; + NMPObject *obj; + NMPlatformLnkIp6Tnl *props; + guint32 flowinfo; + gboolean is_tap; + + if (!info_data || !kind) + return NULL; + + if (nm_streq (kind, "ip6gre")) + is_tap = FALSE; + else if (nm_streq (kind, "ip6gretap")) + is_tap = TRUE; + else + return NULL; + + err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy); + if (err < 0) + return NULL; + + obj = nmp_object_new (is_tap ? NMP_OBJECT_TYPE_LNK_IP6GRETAP : NMP_OBJECT_TYPE_LNK_IP6GRE, NULL); + props = &obj->lnk_ip6tnl; + props->is_gre = TRUE; + props->is_tap = is_tap; + + if (tb[IFLA_GRE_LINK]) + props->parent_ifindex = nla_get_u32 (tb[IFLA_GRE_LINK]); + if (tb[IFLA_GRE_IFLAGS]) + props->input_flags = ntohs (nla_get_u16 (tb[IFLA_GRE_IFLAGS])); + if (tb[IFLA_GRE_OFLAGS]) + props->output_flags = ntohs (nla_get_u16 (tb[IFLA_GRE_OFLAGS])); + if (tb[IFLA_GRE_IKEY]) + props->input_key = ntohl (nla_get_u32 (tb[IFLA_GRE_IKEY])); + if (tb[IFLA_GRE_OKEY]) + props->output_key = ntohl (nla_get_u32 (tb[IFLA_GRE_OKEY])); + if (tb[IFLA_GRE_LOCAL]) + memcpy (&props->local, nla_data (tb[IFLA_GRE_LOCAL]), sizeof (props->local)); + if (tb[IFLA_GRE_REMOTE]) + memcpy (&props->remote, nla_data (tb[IFLA_GRE_REMOTE]), sizeof (props->remote)); + if (tb[IFLA_GRE_TTL]) + props->ttl = nla_get_u8 (tb[IFLA_GRE_TTL]); + if (tb[IFLA_GRE_ENCAP_LIMIT]) + props->encap_limit = nla_get_u8 (tb[IFLA_GRE_ENCAP_LIMIT]); + if (tb[IFLA_GRE_FLOWINFO]) { + flowinfo = ntohl (nla_get_u32 (tb[IFLA_GRE_FLOWINFO])); + props->flow_label = flowinfo & IP6_FLOWINFO_FLOWLABEL_MASK; + props->tclass = (flowinfo & IP6_FLOWINFO_TCLASS_MASK) >> IP6_FLOWINFO_TCLASS_SHIFT; + } + if (tb[IFLA_GRE_FLAGS]) + props->flags = nla_get_u32 (tb[IFLA_GRE_FLAGS]); + + return obj; +} + /*****************************************************************************/ static NMPObject * @@ -1663,6 +1913,378 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) /*****************************************************************************/ +static gboolean +_wireguard_update_from_allowed_ips_nla (NMPWireGuardAllowedIP *allowed_ip, + struct nlattr *nlattr) +{ + static const struct nla_policy policy[WGALLOWEDIP_A_MAX + 1] = { + [WGALLOWEDIP_A_FAMILY] = { .type = NLA_U16 }, + [WGALLOWEDIP_A_IPADDR] = { .minlen = sizeof (struct in_addr) }, + [WGALLOWEDIP_A_CIDR_MASK] = { .type = NLA_U8 }, + }; + struct nlattr *tb[WGALLOWEDIP_A_MAX + 1]; + int family; + int addr_len; + + if (nla_parse_nested (tb, WGALLOWEDIP_A_MAX, nlattr, policy) < 0) + return FALSE; + + if (!tb[WGALLOWEDIP_A_FAMILY]) + return FALSE; + + family = nla_get_u16 (tb[WGALLOWEDIP_A_FAMILY]); + if (family == AF_INET) + addr_len = sizeof (in_addr_t); + else if (family == AF_INET6) + addr_len = sizeof (struct in6_addr); + else + return FALSE; + + _check_addr_or_return_val (tb, WGALLOWEDIP_A_IPADDR, addr_len, FALSE); + + memset (allowed_ip, 0, sizeof (NMPWireGuardAllowedIP)); + + allowed_ip->family = family; + nm_assert ((int) allowed_ip->family == family); + + if (tb[WGALLOWEDIP_A_IPADDR]) + nla_memcpy (&allowed_ip->addr, tb[WGALLOWEDIP_A_IPADDR], addr_len); + if (tb[WGALLOWEDIP_A_CIDR_MASK]) + allowed_ip->mask = nla_get_u8 (tb[WGALLOWEDIP_A_CIDR_MASK]); + + return TRUE; +} + +typedef struct { + CList lst; + NMPWireGuardPeer data; +} WireGuardPeerConstruct; + +static gboolean +_wireguard_update_from_peers_nla (CList *peers, + GArray **p_allowed_ips, + struct nlattr *peer_attr) +{ + static const struct nla_policy policy[WGPEER_A_MAX + 1] = { + [WGPEER_A_PUBLIC_KEY] = { .minlen = NMP_WIREGUARD_PUBLIC_KEY_LEN }, + [WGPEER_A_PRESHARED_KEY] = { }, + [WGPEER_A_FLAGS] = { .type = NLA_U32 }, + [WGPEER_A_ENDPOINT] = { }, + [WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = { .type = NLA_U16 }, + [WGPEER_A_LAST_HANDSHAKE_TIME] = { }, + [WGPEER_A_RX_BYTES] = { .type = NLA_U64 }, + [WGPEER_A_TX_BYTES] = { .type = NLA_U64 }, + [WGPEER_A_ALLOWEDIPS] = { .type = NLA_NESTED }, + }; + WireGuardPeerConstruct *peer_c; + struct nlattr *tb[WGPEER_A_MAX + 1]; + + if (nla_parse_nested (tb, WGPEER_A_MAX, peer_attr, policy) < 0) + return FALSE; + + if (!tb[WGPEER_A_PUBLIC_KEY]) + return FALSE; + + /* a peer with the same public key as last peer is just a continuation for extra AllowedIPs */ + peer_c = c_list_last_entry (peers, WireGuardPeerConstruct, lst); + if ( peer_c + && !memcmp (nla_data (tb[WGPEER_A_PUBLIC_KEY]), peer_c->data.public_key, NMP_WIREGUARD_PUBLIC_KEY_LEN)) { + G_STATIC_ASSERT_EXPR (NMP_WIREGUARD_PUBLIC_KEY_LEN == sizeof (peer_c->data.public_key)); + /* this message is a continuation of the previous peer. + * Only parse WGPEER_A_ALLOWEDIPS below. */ + } + else { + /* otherwise, start a new peer */ + peer_c = g_slice_new0 (WireGuardPeerConstruct); + c_list_link_tail (peers, &peer_c->lst); + + nla_memcpy (&peer_c->data.public_key, tb[WGPEER_A_PUBLIC_KEY], sizeof (peer_c->data.public_key)); + + if (tb[WGPEER_A_PRESHARED_KEY]) { + nla_memcpy (&peer_c->data.preshared_key, tb[WGPEER_A_PRESHARED_KEY], sizeof (peer_c->data.preshared_key)); + /* FIXME(netlink-bzero-secret) */ + nm_explicit_bzero (nla_data (tb[WGPEER_A_PRESHARED_KEY]), + nla_len (tb[WGPEER_A_PRESHARED_KEY])); + } + if (tb[WGPEER_A_ENDPOINT]) { + const struct sockaddr *addr = nla_data (tb[WGPEER_A_ENDPOINT]); + unsigned short family; + + G_STATIC_ASSERT (sizeof (addr->sa_family) == sizeof (family)); + memcpy (&family, &addr->sa_family, sizeof (addr->sa_family)); + + if ( family == AF_INET + && nla_len (tb[WGPEER_A_ENDPOINT]) == sizeof (struct sockaddr_in)) { + const struct sockaddr_in *addr4 = (const struct sockaddr_in *) addr; + + peer_c->data.endpoint_family = AF_INET; + peer_c->data.endpoint_port = unaligned_read_be16 (&addr4->sin_port); + peer_c->data.endpoint_addr.addr4 = unaligned_read_ne32 (&addr4->sin_addr.s_addr); + memcpy (&peer_c->data.endpoint_addr.addr4, &addr4->sin_addr.s_addr, 4); + } else if ( family == AF_INET6 + && nla_len (tb[WGPEER_A_ENDPOINT]) == sizeof (struct sockaddr_in6)) { + const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *) addr; + + peer_c->data.endpoint_family = AF_INET6; + peer_c->data.endpoint_port = unaligned_read_be16 (&addr6->sin6_port); + memcpy (&peer_c->data.endpoint_addr.addr6, &addr6->sin6_addr, 16); + } + } + if (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]) + peer_c->data.persistent_keepalive_interval = nla_get_u64 (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]); + if (tb[WGPEER_A_LAST_HANDSHAKE_TIME]) + nla_memcpy (&peer_c->data.last_handshake_time, tb[WGPEER_A_LAST_HANDSHAKE_TIME], sizeof (peer_c->data.last_handshake_time)); + if (tb[WGPEER_A_RX_BYTES]) + peer_c->data.rx_bytes = nla_get_u64 (tb[WGPEER_A_RX_BYTES]); + if (tb[WGPEER_A_TX_BYTES]) + peer_c->data.tx_bytes = nla_get_u64 (tb[WGPEER_A_TX_BYTES]); + } + + if (tb[WGPEER_A_ALLOWEDIPS]) { + struct nlattr *attr; + int rem; + GArray *allowed_ips = *p_allowed_ips; + + nla_for_each_nested (attr, tb[WGPEER_A_ALLOWEDIPS], rem) { + if (!allowed_ips) { + allowed_ips = g_array_new (FALSE, FALSE, sizeof (NMPWireGuardAllowedIP)); + *p_allowed_ips = allowed_ips; + g_array_set_size (allowed_ips, 1); + } else + g_array_set_size (allowed_ips, allowed_ips->len + 1); + + if (!_wireguard_update_from_allowed_ips_nla (&g_array_index (allowed_ips, + NMPWireGuardAllowedIP, + allowed_ips->len - 1), + attr)) { + /* we ignore the error of parsing one allowed-ip. */ + g_array_set_size (allowed_ips, allowed_ips->len - 1); + continue; + } + + if (!peer_c->data._construct_idx_end) + peer_c->data._construct_idx_start = allowed_ips->len - 1; + peer_c->data._construct_idx_end = allowed_ips->len; + } + } + + return TRUE; +} + +typedef struct { + const int ifindex; + NMPObject *obj; + CList peers; + GArray *allowed_ips; +} WireGuardParseData; + +static int +_wireguard_get_device_cb (struct nl_msg *msg, void *arg) +{ + static const struct nla_policy policy[WGDEVICE_A_MAX + 1] = { + [WGDEVICE_A_IFINDEX] = { .type = NLA_U32 }, + [WGDEVICE_A_IFNAME] = { .type = NLA_NUL_STRING, .maxlen = IFNAMSIZ }, + [WGDEVICE_A_PRIVATE_KEY] = { }, + [WGDEVICE_A_PUBLIC_KEY] = { }, + [WGDEVICE_A_FLAGS] = { .type = NLA_U32 }, + [WGDEVICE_A_LISTEN_PORT] = { .type = NLA_U16 }, + [WGDEVICE_A_FWMARK] = { .type = NLA_U32 }, + [WGDEVICE_A_PEERS] = { .type = NLA_NESTED }, + }; + WireGuardParseData *parse_data = arg; + struct nlattr *tb[WGDEVICE_A_MAX + 1]; + int nlerr; + + nlerr = genlmsg_parse (nlmsg_hdr (msg), 0, tb, WGDEVICE_A_MAX, policy); + if (nlerr < 0) + return NL_SKIP; + + if (tb[WGDEVICE_A_IFINDEX]) { + int ifindex; + + ifindex = (int) nla_get_u32 (tb[WGDEVICE_A_IFINDEX]); + if ( ifindex <= 0 + || parse_data->ifindex != ifindex) + return NL_SKIP; + } else { + if (!parse_data->obj) + return NL_SKIP; + } + + if (parse_data->obj) { + /* we already have an object instance. This means the netlink message + * is a continuation, only providing more WGDEVICE_A_PEERS data below. */ + } else { + NMPObject *obj; + NMPlatformLnkWireGuard *props; + + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_WIREGUARD, NULL); + props = &obj->lnk_wireguard; + + if (tb[WGDEVICE_A_PRIVATE_KEY]) { + nla_memcpy (props->private_key, tb[WGDEVICE_A_PRIVATE_KEY], sizeof (props->private_key)); + /* FIXME(netlink-bzero-secret): extend netlink library to wipe memory. For now, + * just hack it here (yes, this does not cover all places where the + * private key was copied). */ + nm_explicit_bzero (nla_data (tb[WGDEVICE_A_PRIVATE_KEY]), + nla_len (tb[WGDEVICE_A_PRIVATE_KEY])); + } + if (tb[WGDEVICE_A_PUBLIC_KEY]) + nla_memcpy (props->public_key, tb[WGDEVICE_A_PUBLIC_KEY], sizeof (props->public_key)); + if (tb[WGDEVICE_A_LISTEN_PORT]) + props->listen_port = nla_get_u16 (tb[WGDEVICE_A_LISTEN_PORT]); + if (tb[WGDEVICE_A_FWMARK]) + props->fwmark = nla_get_u32 (tb[WGDEVICE_A_FWMARK]); + + parse_data->obj = obj; + } + + if (tb[WGDEVICE_A_PEERS]) { + struct nlattr *attr; + int rem; + + nla_for_each_nested (attr, tb[WGDEVICE_A_PEERS], rem) { + if (!_wireguard_update_from_peers_nla (&parse_data->peers, &parse_data->allowed_ips, attr)) { + /* we ignore the error of parsing one peer. + * _wireguard_update_from_peers_nla() leaves the @peers array in the + * desired state. */ + } + } + } + + return NL_OK; +} + +static const NMPObject * +_wireguard_read_info (NMPlatform *platform /* used only as logging context */, + struct nl_sock *genl, + int wireguard_family_id, + int ifindex) +{ + nm_auto_nlmsg struct nl_msg *msg = NULL; + NMPObject *obj = NULL; + WireGuardPeerConstruct *peer_c; + WireGuardPeerConstruct *peer_c_safe; + gs_unref_array GArray *allowed_ips = NULL; + WireGuardParseData parse_data = { + .ifindex = ifindex, + }; + guint i; + + nm_assert (genl); + nm_assert (wireguard_family_id >= 0); + nm_assert (ifindex > 0); + + msg = nlmsg_alloc (); + + if (!genlmsg_put (msg, + NL_AUTO_PORT, + NL_AUTO_SEQ, + wireguard_family_id, + 0, + NLM_F_DUMP, + WG_CMD_GET_DEVICE, + 1)) + return NULL; + + NLA_PUT_U32 (msg, WGDEVICE_A_IFINDEX, (guint32) ifindex); + + if (nl_send_auto (genl, msg) < 0) + return NULL; + + c_list_init (&parse_data.peers); + + /* we ignore errors, and return whatever we could successfully + * parse. */ + nl_recvmsgs (genl, + &((const struct nl_cb) { + .valid_cb = _wireguard_get_device_cb, + .valid_arg = (gpointer) &parse_data, + })); + + /* unpack: transfer ownership */ + obj = parse_data.obj; + allowed_ips = parse_data.allowed_ips; + + if (!obj) { + while ((peer_c = c_list_first_entry (&parse_data.peers, WireGuardPeerConstruct, lst))) { + c_list_unlink_stale (&peer_c->lst); + nm_explicit_bzero (&peer_c->data.preshared_key, sizeof (peer_c->data.preshared_key)); + g_slice_free (WireGuardPeerConstruct, peer_c); + } + return NULL; + } + + /* we receive peers/allowed-ips possibly in separate netlink messages. Hence, while + * parsing the dump, we don't know upfront how many peers/allowed-ips we will receive. + * + * We solve that, by collecting all peers with a CList. It's done this way, + * because a GArray would require growing the array, but we want to bzero() + * the preshared-key of each peer while reallocating. The CList apprach avoids + * that. + * + * For allowed-ips, we instead track one GArray, which are all appended + * there. The realloc/resize of the GArray is fine there. However, + * while we build the GArray, we don't yet have the final pointers. + * Hence, while constructing, we track the indexes with peer->_construct_idx_* + * fields. These indexes must be convered to actual pointers blow. + * + * This is all done during parsing. In the final NMPObjectLnkWireGuard we + * don't want the CList anymore and repackage the NMPObject tightly. The + * reason is, that NMPObject instances are immutable and long-living. Spend + * a bit effort below during construction to obtain a most suitable representation + * in this regard. */ + obj->_lnk_wireguard.peers_len = c_list_length (&parse_data.peers); + obj->_lnk_wireguard.peers = obj->_lnk_wireguard.peers_len > 0 + ? g_new (NMPWireGuardPeer, obj->_lnk_wireguard.peers_len) + : NULL; + + /* duplicate allowed_ips instead of using the pointer. The GArray possibly has more + * space allocated then we need, and we want to get rid of this excess buffer. + * Note that NMPObject instance is possibly put into the cache and long-living. */ + obj->_lnk_wireguard._allowed_ips_buf_len = allowed_ips ? allowed_ips->len : 0u; + obj->_lnk_wireguard._allowed_ips_buf = obj->_lnk_wireguard._allowed_ips_buf_len > 0 + ? (NMPWireGuardAllowedIP *) nm_memdup (allowed_ips->data, + sizeof (NMPWireGuardAllowedIP) * allowed_ips->len) + : NULL; + + i = 0; + c_list_for_each_entry_safe (peer_c, peer_c_safe, &parse_data.peers, lst) { + NMPWireGuardPeer *peer = (NMPWireGuardPeer *) &obj->_lnk_wireguard.peers[i++]; + + *peer = peer_c->data; + + c_list_unlink_stale (&peer_c->lst); + nm_explicit_bzero (&peer_c->data.preshared_key, sizeof (peer_c->data.preshared_key)); + g_slice_free (WireGuardPeerConstruct, peer_c); + + if (peer->_construct_idx_end != 0) { + guint len; + + nm_assert (obj->_lnk_wireguard._allowed_ips_buf); + nm_assert (peer->_construct_idx_end > peer->_construct_idx_start); + nm_assert (peer->_construct_idx_start < obj->_lnk_wireguard._allowed_ips_buf_len); + nm_assert (peer->_construct_idx_end <= obj->_lnk_wireguard._allowed_ips_buf_len); + + len = peer->_construct_idx_end - peer->_construct_idx_start; + peer->allowed_ips = &obj->_lnk_wireguard._allowed_ips_buf[peer->_construct_idx_start]; + peer->allowed_ips_len = len; + } else { + nm_assert (!peer->_construct_idx_start); + nm_assert (!peer->_construct_idx_end); + peer->allowed_ips = NULL; + peer->allowed_ips_len = 0; + } + } + + return obj; + +nla_put_failure: + g_return_val_if_reached (NULL); +} + +/*****************************************************************************/ + /* Copied and heavily modified from libnl3's link_msg_parser(). */ static NMPObject * _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr *nlh, gboolean id_only) @@ -1707,37 +2329,39 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr const char *nl_info_kind = NULL; int err; nm_auto_nmpobj NMPObject *obj = NULL; - NMPObject *obj_result = NULL; gboolean completed_from_cache_val = FALSE; gboolean *completed_from_cache = cache ? &completed_from_cache_val : NULL; const NMPObject *link_cached = NULL; - NMPObject *lnk_data = NULL; + const NMPObject *lnk_data = NULL; gboolean address_complete_from_cache = TRUE; gboolean lnk_data_complete_from_cache = TRUE; + gboolean need_ext_data = FALSE; gboolean af_inet6_token_valid = FALSE; gboolean af_inet6_addr_gen_mode_valid = FALSE; if (!nlmsg_valid_hdr (nlh, sizeof (*ifi))) return NULL; - ifi = nlmsg_data(nlh); + ifi = nlmsg_data (nlh); if (ifi->ifi_family != AF_UNSPEC) return NULL; + if (ifi->ifi_index <= 0) + return NULL; obj = nmp_object_new_link (ifi->ifi_index); if (id_only) - goto id_only_handled; + return g_steal_pointer (&obj); err = nlmsg_parse (nlh, sizeof (*ifi), tb, IFLA_MAX, policy); if (err < 0) - goto errout; + return NULL; if (!tb[IFLA_IFNAME]) - goto errout; + return NULL; nla_strlcpy(obj->link.name, tb[IFLA_IFNAME], IFNAMSIZ); if (!obj->link.name[0]) - goto errout; + return NULL; if (!tb[IFLA_MTU]) { /* Kernel has two places that send RTM_GETLINK messages: @@ -1752,14 +2376,14 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr * To some extent this is a hack and correct approach is to * merge objects per-field. */ - goto errout; + return NULL; } obj->link.mtu = nla_get_u32 (tb[IFLA_MTU]); if (tb[IFLA_LINKINFO]) { err = nla_parse_nested (li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], policy_link_info); if (err < 0) - goto errout; + return NULL; if (li[IFLA_INFO_KIND]) nl_info_kind = nla_get_string (li[IFLA_INFO_KIND]); @@ -1838,6 +2462,7 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr switch (obj->link.type) { case NM_LINK_TYPE_GRE: + case NM_LINK_TYPE_GRETAP: lnk_data = _parse_lnk_gre (nl_info_kind, nl_info_data); break; case NM_LINK_TYPE_INFINIBAND: @@ -1846,6 +2471,10 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr case NM_LINK_TYPE_IP6TNL: lnk_data = _parse_lnk_ip6tnl (nl_info_kind, nl_info_data); break; + case NM_LINK_TYPE_IP6GRE: + case NM_LINK_TYPE_IP6GRETAP: + lnk_data = _parse_lnk_ip6gre (nl_info_kind, nl_info_data); + break; case NM_LINK_TYPE_IPIP: lnk_data = _parse_lnk_ipip (nl_info_kind, nl_info_data); break; @@ -1868,6 +2497,15 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr case NM_LINK_TYPE_VXLAN: lnk_data = _parse_lnk_vxlan (nl_info_kind, nl_info_data); break; + case NM_LINK_TYPE_WIFI: + case NM_LINK_TYPE_OLPC_MESH: + case NM_LINK_TYPE_WPAN: + need_ext_data = TRUE; + lnk_data_complete_from_cache = FALSE; + break; + case NM_LINK_TYPE_WIREGUARD: + lnk_data_complete_from_cache = TRUE; + break; default: lnk_data_complete_from_cache = FALSE; break; @@ -1875,12 +2513,14 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr if ( completed_from_cache && ( lnk_data_complete_from_cache + || need_ext_data || address_complete_from_cache || !af_inet6_token_valid || !af_inet6_addr_gen_mode_valid || !tb[IFLA_STATS64])) { _lookup_cached_link (cache, obj->link.ifindex, completed_from_cache, &link_cached); - if (link_cached) { + if ( link_cached + && link_cached->_link.netlink.is_in_netlink) { if ( lnk_data_complete_from_cache && link_cached->link.type == obj->link.type && link_cached->_link.netlink.lnk @@ -1893,8 +2533,16 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr * Also, sometimes the info-data is missing for updates. In this case * we want to keep the previously received lnk_data. */ nmp_object_unref (lnk_data); - lnk_data = (NMPObject *) nmp_object_ref (link_cached->_link.netlink.lnk); + lnk_data = nmp_object_ref (link_cached->_link.netlink.lnk); } + + if ( need_ext_data + && link_cached->link.type == obj->link.type + && link_cached->_link.ext_data) { + /* Prefer reuse of existing ext_data object */ + obj->_link.ext_data = g_object_ref (link_cached->_link.ext_data); + } + if (address_complete_from_cache) obj->link.addr = link_cached->link.addr; if (!af_inet6_token_valid) @@ -1912,12 +2560,71 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr obj->_link.netlink.lnk = lnk_data; + if ( need_ext_data + && obj->_link.ext_data == NULL) { + switch (obj->link.type) { + case NM_LINK_TYPE_WIFI: + obj->_link.ext_data = (GObject *) nm_wifi_utils_new (ifi->ifi_index, + _genl_sock (NM_LINUX_PLATFORM (platform)), + TRUE); + break; + case NM_LINK_TYPE_OLPC_MESH: +#if HAVE_WEXT + /* The kernel driver now uses nl80211, but we force use of WEXT because + * the cfg80211 interactions are not quite ready to support access to + * mesh control through nl80211 just yet. + */ + obj->_link.ext_data = (GObject *) nm_wifi_utils_wext_new (ifi->ifi_index, FALSE); +#endif + break; + case NM_LINK_TYPE_WPAN: + obj->_link.ext_data = (GObject *) nm_wpan_utils_new (ifi->ifi_index, + _genl_sock (NM_LINUX_PLATFORM (platform)), + TRUE); + break; + default: + g_assert_not_reached (); + } + } + + if (obj->link.type == NM_LINK_TYPE_WIREGUARD) { + const NMPObject *lnk_data_new = NULL; + struct nl_sock *genl = NM_LINUX_PLATFORM_GET_PRIVATE (platform)->genl; + + /* The WireGuard kernel module does not yet send link update + * notifications, so we don't actually update the cache. For + * now, always refetch link data here. */ + + _lookup_cached_link (cache, obj->link.ifindex, completed_from_cache, &link_cached); + if ( link_cached + && link_cached->_link.netlink.is_in_netlink + && link_cached->link.type == NM_LINK_TYPE_WIREGUARD) + obj->_link.wireguard_family_id = link_cached->_link.wireguard_family_id; + else + obj->_link.wireguard_family_id = -1; + + if (obj->_link.wireguard_family_id < 0) + obj->_link.wireguard_family_id = genl_ctrl_resolve (genl, "wireguard"); + + if (obj->_link.wireguard_family_id >= 0) { + lnk_data_new = _wireguard_read_info (platform, + genl, + obj->_link.wireguard_family_id, + obj->link.ifindex); + } + + if ( lnk_data_new + && obj->_link.netlink.lnk + && nmp_object_equal (obj->_link.netlink.lnk, lnk_data_new)) + nmp_object_unref (lnk_data_new); + else { + nmp_object_unref (obj->_link.netlink.lnk); + obj->_link.netlink.lnk = lnk_data_new; + } + } + obj->_link.netlink.is_in_netlink = TRUE; -id_only_handled: - obj_result = obj; - obj = NULL; -errout: - return obj_result; + return g_steal_pointer (&obj); } /* Copied and heavily modified from libnl3's addr_msg_parser(). */ @@ -1934,7 +2641,6 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) int err; gboolean is_v4; nm_auto_nmpobj NMPObject *obj = NULL; - NMPObject *obj_result = NULL; int addr_len; guint32 lifetime, preferred, timestamp; @@ -1943,19 +2649,19 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) ifa = nlmsg_data(nlh); if (!NM_IN_SET (ifa->ifa_family, AF_INET, AF_INET6)) - goto errout; + return NULL; is_v4 = ifa->ifa_family == AF_INET; err = nlmsg_parse (nlh, sizeof(*ifa), tb, IFA_MAX, policy); if (err < 0) - goto errout; + return NULL; addr_len = is_v4 ? sizeof (in_addr_t) : sizeof (struct in6_addr); if (ifa->ifa_prefixlen > (is_v4 ? 32 : 128)) - goto errout; + return NULL; /*****************************************************************/ @@ -1964,8 +2670,8 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) obj->ip_address.ifindex = ifa->ifa_index; obj->ip_address.plen = ifa->ifa_prefixlen; - _check_addr_or_errout (tb, IFA_ADDRESS, addr_len); - _check_addr_or_errout (tb, IFA_LOCAL, addr_len); + _check_addr_or_return_null (tb, IFA_ADDRESS, addr_len); + _check_addr_or_return_null (tb, IFA_LOCAL, addr_len); if (is_v4) { /* For IPv4, kernel omits IFA_LOCAL/IFA_ADDRESS if (and only if) they * are effectively 0.0.0.0 (all-zero). */ @@ -2029,10 +2735,7 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) &obj->ip_address.lifetime, &obj->ip_address.preferred); - obj_result = obj; - obj = NULL; -errout: - return obj_result; + return g_steal_pointer (&obj); } /* Copied and heavily modified from libnl3's rtnl_route_parse() and parse_multipath(). */ @@ -2055,7 +2758,6 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) int err; gboolean is_v4; nm_auto_nmpobj NMPObject *obj = NULL; - NMPObject *obj_result = NULL; int addr_len; struct { gboolean is_present; @@ -2074,14 +2776,14 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) *****************************************************************/ if (!NM_IN_SET (rtm->rtm_family, AF_INET, AF_INET6)) - goto errout; + return NULL; if (rtm->rtm_type != RTN_UNICAST) - goto errout; + return NULL; err = nlmsg_parse (nlh, sizeof (struct rtmsg), tb, RTA_MAX, policy); if (err < 0) - goto errout; + return NULL; /*****************************************************************/ @@ -2091,7 +2793,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) : sizeof (struct in6_addr); if (rtm->rtm_dst_len > (is_v4 ? 32 : 128)) - goto errout; + return NULL; /***************************************************************** * parse nexthops. Only handle routes with one nh. @@ -2107,7 +2809,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) if (nh.is_present) { /* we don't support multipath routes. */ - goto errout; + return NULL; } nh.is_present = TRUE; @@ -2121,9 +2823,9 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) rtnh->rtnh_len - sizeof (*rtnh), policy); if (err < 0) - goto errout; + return NULL; - if (_check_addr_or_errout (ntb, RTA_GATEWAY, addr_len)) + if (_check_addr_or_return_null (ntb, RTA_GATEWAY, addr_len)) memcpy (&nh.gateway, nla_data (ntb[RTA_GATEWAY]), addr_len); } @@ -2140,7 +2842,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) if (tb[RTA_OIF]) ifindex = nla_get_u32 (tb[RTA_OIF]); - if (_check_addr_or_errout (tb, RTA_GATEWAY, addr_len)) + if (_check_addr_or_return_null (tb, RTA_GATEWAY, addr_len)) memcpy (&gateway, nla_data (tb[RTA_GATEWAY]), addr_len); if (!nh.is_present) { @@ -2154,10 +2856,10 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) * verify that it is a duplicate and ignore old-style nexthop. */ if ( nh.ifindex != ifindex || memcmp (&nh.gateway, &gateway, addr_len) != 0) - goto errout; + return NULL; } } else if (!nh.is_present) - goto errout; + return NULL; /*****************************************************************/ @@ -2176,7 +2878,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) err = nla_parse_nested (mtb, RTAX_MAX, tb[RTA_METRICS], rtax_policy); if (err < 0) - goto errout; + return NULL; if (mtb[RTAX_LOCK]) lock = nla_get_u32 (mtb[RTAX_LOCK]); @@ -2204,7 +2906,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) obj->ip_route.ifindex = nh.ifindex; - if (_check_addr_or_errout (tb, RTA_DST, addr_len)) + if (_check_addr_or_return_null (tb, RTA_DST, addr_len)) memcpy (obj->ip_route.network_ptr, nla_data (tb[RTA_DST]), addr_len); obj->ip_route.plen = rtm->rtm_dst_len; @@ -2220,7 +2922,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) if (is_v4) obj->ip4_route.scope_inv = nm_platform_route_scope_inv (rtm->rtm_scope); - if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len)) { + if (_check_addr_or_return_null (tb, RTA_PREFSRC, addr_len)) { if (is_v4) memcpy (&obj->ip4_route.pref_src, nla_data (tb[RTA_PREFSRC]), addr_len); else @@ -2231,7 +2933,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) obj->ip4_route.tos = rtm->rtm_tos; else { if (tb[RTA_SRC]) { - _check_addr_or_errout (tb, RTA_SRC, addr_len); + _check_addr_or_return_null (tb, RTA_SRC, addr_len); memcpy (&obj->ip6_route.src, nla_data (tb[RTA_SRC]), addr_len); } obj->ip6_route.src_plen = rtm->rtm_src_len; @@ -2261,10 +2963,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) obj->ip_route.r_rtm_flags = rtm->rtm_flags; obj->ip_route.rt_source = nmp_utils_ip_config_source_from_rtprot (rtm->rtm_protocol); - obj_result = obj; - obj = NULL; -errout: - return obj_result; + return g_steal_pointer (&obj); } static NMPObject * @@ -2941,103 +3640,16 @@ nla_put_failure: g_return_val_if_reached (NULL); } -/****************************************************************** - * NMPlatform types and functions - ******************************************************************/ - -typedef enum { - DELAYED_ACTION_RESPONSE_TYPE_VOID = 0, - DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS = 1, - DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET = 2, -} DelayedActionWaitForNlResponseType; - -typedef struct { - guint32 seq_number; - WaitForNlResponseResult seq_result; - DelayedActionWaitForNlResponseType response_type; - gint64 timeout_abs_ns; - WaitForNlResponseResult *out_seq_result; - char **out_errmsg; - union { - gint *out_refresh_all_in_progess; - NMPObject **out_route_get; - gpointer out_data; - } response; -} DelayedActionWaitForNlResponseData; - -typedef struct { - struct nl_sock *nlh; - guint32 nlh_seq_next; -#ifdef NM_MORE_LOGGING - guint32 nlh_seq_last_handled; -#endif - guint32 nlh_seq_last_seen; - GIOChannel *event_channel; - guint event_id; - - bool pruning[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM]; - - bool sysctl_get_warned; - GHashTable *sysctl_get_prev_values; - - NMUdevClient *udev_client; - - struct { - /* which delayed actions are scheduled, as marked in @flags. - * Some types have additional arguments in the fields below. */ - DelayedActionType flags; - - /* counter that a refresh all action is in progress, separated - * by type. */ - gint refresh_all_in_progess[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM]; - - GPtrArray *list_master_connected; - GPtrArray *list_refresh_link; - GArray *list_wait_for_nl_response; - - gint is_handling; - } delayed_action; - - GHashTable *wifi_data; -} NMLinuxPlatformPrivate; - -struct _NMLinuxPlatform { - NMPlatform parent; - NMLinuxPlatformPrivate _priv; -}; - -struct _NMLinuxPlatformClass { - NMPlatformClass parent; -}; - -G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM) - -#define NM_LINUX_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMLinuxPlatform, NM_IS_LINUX_PLATFORM, NMPlatform) +/*****************************************************************************/ -NMPlatform * -nm_linux_platform_new (gboolean log_with_ptr, gboolean netns_support) +static struct nl_sock * +_genl_sock (NMLinuxPlatform *platform) { - gboolean use_udev = FALSE; - - if ( nmp_netns_is_initial () - && access ("/sys", W_OK) == 0) - use_udev = TRUE; - - return g_object_new (NM_TYPE_LINUX_PLATFORM, - NM_PLATFORM_LOG_WITH_PTR, log_with_ptr, - NM_PLATFORM_USE_UDEV, use_udev, - NM_PLATFORM_NETNS_SUPPORT, netns_support, - NULL); -} + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); -void -nm_linux_platform_setup (void) -{ - nm_platform_setup (nm_linux_platform_new (FALSE, FALSE)); + return priv->genl; } -/*****************************************************************************/ - #define ASSERT_SYSCTL_ARGS(pathid, dirfd, path) \ G_STMT_START { \ const char *const _pathid = (pathid); \ @@ -3064,7 +3676,9 @@ _log_dbg_sysctl_set_impl (NMPlatform *platform, const char *pathid, int dirfd, c char *contents; gs_free char *value_escaped = g_strescape (value, NULL); - if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, &contents, NULL, &error) < 0) { + if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, + NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, + &contents, NULL, &error) < 0) { _LOGD ("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", pathid, value_escaped, error->message); g_clear_error (&error); return; @@ -3281,7 +3895,9 @@ sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *pat pathid = path; } - if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, &contents, NULL, &error) < 0) { + if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, + NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, + &contents, NULL, &error) < 0) { /* We assume FAILED means EOPNOTSUP */ if ( g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT) || g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NODEV) @@ -3452,7 +4068,7 @@ delayed_action_refresh_all_in_progress (NMPlatform *platform, DelayedActionType if (NM_FLAGS_ANY (priv->delayed_action.flags, action_type)) return TRUE; - if (priv->delayed_action.refresh_all_in_progess[delayed_action_refresh_all_to_idx (action_type)] > 0) + if (priv->delayed_action.refresh_all_in_progress[delayed_action_refresh_all_to_idx (action_type)] > 0) return TRUE; return FALSE; @@ -3482,10 +4098,10 @@ delayed_action_wait_for_nl_response_complete (NMPlatform *platform, case DELAYED_ACTION_RESPONSE_TYPE_VOID: break; case DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS: - if (data->response.out_refresh_all_in_progess) { - nm_assert (*data->response.out_refresh_all_in_progess > 0); - *data->response.out_refresh_all_in_progess -= 1; - data->response.out_refresh_all_in_progess = NULL; + if (data->response.out_refresh_all_in_progress) { + nm_assert (*data->response.out_refresh_all_in_progress > 0); + *data->response.out_refresh_all_in_progress -= 1; + data->response.out_refresh_all_in_progress = NULL; } break; case DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET: @@ -3510,7 +4126,7 @@ delayed_action_wait_for_nl_response_complete_check (NMPlatform *platform, guint i; guint32 next_seq_number = 0; gint64 next_timeout_abs_ns = 0; - gint now_ns = 0; + int now_ns = 0; for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; ) { const DelayedActionWaitForNlResponseData *data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i); @@ -3932,7 +4548,10 @@ cache_on_change (NMPlatform *platform, if ( !obj_new->_link.netlink.lnk && NM_IN_SET (obj_new->link.type, NM_LINK_TYPE_GRE, + NM_LINK_TYPE_GRETAP, NM_LINK_TYPE_IP6TNL, + NM_LINK_TYPE_IP6GRE, + NM_LINK_TYPE_IP6GRETAP, NM_LINK_TYPE_INFINIBAND, NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVLAN, @@ -4205,11 +4824,11 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio const NMPClass *klass = nmp_class_from_type (obj_type); nm_auto_nlmsg struct nl_msg *nlmsg = NULL; int nle; - gint *out_refresh_all_in_progess; + int *out_refresh_all_in_progress; - out_refresh_all_in_progess = &priv->delayed_action.refresh_all_in_progess[delayed_action_refresh_all_to_idx (iflags)]; - nm_assert (*out_refresh_all_in_progess >= 0); - *out_refresh_all_in_progess += 1; + out_refresh_all_in_progress = &priv->delayed_action.refresh_all_in_progress[delayed_action_refresh_all_to_idx (iflags)]; + nm_assert (*out_refresh_all_in_progress >= 0); + *out_refresh_all_in_progress += 1; /* clear any delayed action that request a refresh of this object type. */ priv->delayed_action.flags &= ~iflags; @@ -4243,9 +4862,9 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio if (nle < 0) continue; - if (_nl_send_nlmsg (platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, out_refresh_all_in_progess) < 0) { - nm_assert (*out_refresh_all_in_progess > 0); - *out_refresh_all_in_progess -= 1; + if (_nl_send_nlmsg (platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, out_refresh_all_in_progress) < 0) { + nm_assert (*out_refresh_all_in_progress > 0); + *out_refresh_all_in_progress -= 1; } } } @@ -4274,10 +4893,10 @@ event_seq_check_refresh_all (NMPlatform *platform, guint32 seq_number) data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i); if ( data->response_type == DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS - && data->response.out_refresh_all_in_progess + && data->response.out_refresh_all_in_progress && data->seq_number == priv->nlh_seq_last_seen) { - *data->response.out_refresh_all_in_progess -= 1; - data->response.out_refresh_all_in_progess = NULL; + *data->response.out_refresh_all_in_progress -= 1; + data->response.out_refresh_all_in_progress = NULL; break; } } @@ -4318,7 +4937,7 @@ event_seq_check (NMPlatform *platform, guint32 seq_number, WaitForNlResponseResu } } -#ifdef NM_MORE_LOGGING +#if NM_MORE_LOGGING if (seq_number != priv->nlh_seq_last_handled) _LOGt ("netlink: recvmsg: unwaited sequence number %u", seq_number); priv->nlh_seq_last_handled = seq_number; @@ -4741,6 +5360,9 @@ retry: } else if (NM_IN_SET (-((int) seq_result), ENODEV)) { log_level = LOGL_DEBUG; result = NM_PLATFORM_ERROR_NOT_FOUND; + } else if (-((int) seq_result) == EAFNOSUPPORT) { + log_level = LOGL_DEBUG; + result = NM_PLATFORM_ERROR_OPNOTSUPP; } else { log_level = LOGL_WARN; result = NM_PLATFORM_ERROR_UNSPECIFIED; @@ -4841,8 +5463,6 @@ link_set_netns (NMPlatform *platform, { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - _LOGD ("link: move link %d to network namespace with fd %d", ifindex, netns_fd); - nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, @@ -5031,7 +5651,6 @@ static NMPlatformError link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size_t length) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - gs_free char *mac = NULL; const ChangeLinkData d = { .set_address = { .address = address, @@ -5042,10 +5661,6 @@ link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size if (!address || !length) g_return_val_if_reached (NM_PLATFORM_ERROR_BUG); - _LOGD ("link: change %d: address: %s (%lu bytes)", ifindex, - (mac = nm_utils_hwaddr_ntoa (address, length)), - (unsigned long) length); - nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, @@ -5067,8 +5682,6 @@ link_set_name (NMPlatform *platform, int ifindex, const char *name) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - _LOGD ("link: change %d: name: %s", ifindex, name); - nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, @@ -5104,8 +5717,6 @@ link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - _LOGD ("link: change %d: mtu: %u", ifindex, (unsigned) mtu); - nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, @@ -5123,16 +5734,18 @@ nla_put_failure: } static gboolean -link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs) +link_set_sriov_params (NMPlatform *platform, + int ifindex, + guint num_vfs, + int autoprobe) { nm_auto_pop_netns NMPNetns *netns = NULL; nm_auto_close int dirfd = -1; - int total, current; + gboolean current_autoprobe; + guint total, current_num; char ifname[IFNAMSIZ]; char buf[64]; - _LOGD ("link: change %d: num VFs: %u", ifindex, num_vfs); - if (!nm_platform_netns_push (platform, &netns)) return FALSE; @@ -5140,46 +5753,69 @@ link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs) if (!dirfd) return FALSE; - total = nm_platform_sysctl_get_int32 (platform, - NMP_SYSCTL_PATHID_NETDIR (dirfd, - ifname, - "device/sriov_totalvfs"), - -1); - if (total < 1) + total = nm_platform_sysctl_get_int_checked (platform, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_totalvfs"), + 10, 0, G_MAXUINT, 0); + if (errno) return FALSE; if (num_vfs > total) { _LOGW ("link: %d only supports %u VFs (requested %u)", ifindex, total, num_vfs); num_vfs = total; } - current = nm_platform_sysctl_get_int32 (platform, - NMP_SYSCTL_PATHID_NETDIR (dirfd, - ifname, - "device/sriov_numvfs"), - -1); - if (current == num_vfs) + /* + * Take special care when setting new values: + * - don't touch anything if the right values are already set + * - to change the number of VFs or autoprobe we need to destroy existing VFs + * - the autoprobe setting is irrelevant when numvfs is zero + */ + current_num = nm_platform_sysctl_get_int_checked (platform, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_numvfs"), + 10, 0, G_MAXUINT, 0); + current_autoprobe = nm_platform_sysctl_get_int_checked (platform, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_drivers_autoprobe"), + 10, 0, G_MAXUINT, 0); + if ( current_num == num_vfs + && (autoprobe == -1 || current_autoprobe == autoprobe)) return TRUE; - if (current != 0) { - /* We need to destroy all other VFs before changing the value */ + if (current_num != 0) { + /* We need to destroy all other VFs before changing any value */ if (!nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "device/sriov_numvfs"), "0")) { - _LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", 0, strerror (errno)); + _LOGW ("link: couldn't reset SR-IOV num_vfs: %s", strerror (errno)); return FALSE; } - if (num_vfs == 0) - return TRUE; } - /* Finally, set the desired value */ + if (num_vfs == 0) + return TRUE; + + if ( autoprobe >= 0 + && current_autoprobe != autoprobe + && !nm_platform_sysctl_set (NM_PLATFORM_GET, + NMP_SYSCTL_PATHID_NETDIR (dirfd, + ifname, + "device/sriov_drivers_autoprobe"), + nm_sprintf_buf (buf, "%d", autoprobe))) { + _LOGW ("link: couldn't set SR-IOV drivers-autoprobe to %d: %s", autoprobe, strerror (errno)); + return FALSE; + } + if (!nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "device/sriov_numvfs"), - nm_sprintf_buf (buf, "%d", num_vfs))) { + nm_sprintf_buf (buf, "%u", num_vfs))) { _LOGW ("link: couldn't set SR-IOV num_vfs to %d: %s", num_vfs, strerror (errno)); return FALSE; } @@ -5187,6 +5823,101 @@ link_set_sriov_num_vfs (NMPlatform *platform, int ifindex, guint num_vfs) return TRUE; } +static gboolean +link_set_sriov_vfs (NMPlatform *platform, int ifindex, const NMPlatformVF *const *vfs) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *list, *info, *vlan_list; + guint i; + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + 0, + ifindex, + NULL, + 0, + 0); + if (!nlmsg) + g_return_val_if_reached (NM_PLATFORM_ERROR_UNSPECIFIED); + + if (!(list = nla_nest_start (nlmsg, IFLA_VFINFO_LIST))) + goto nla_put_failure; + + for (i = 0; vfs[i]; i++) { + const NMPlatformVF *vf = vfs[i]; + + if (!(info = nla_nest_start (nlmsg, IFLA_VF_INFO))) + goto nla_put_failure; + + if (vf->spoofchk >= 0) { + struct _ifla_vf_setting ivs = { 0 }; + + ivs.vf = vf->index; + ivs.setting = vf->spoofchk; + NLA_PUT (nlmsg, IFLA_VF_SPOOFCHK, sizeof (ivs), &ivs); + } + + if (vf->trust >= 0) { + struct _ifla_vf_setting ivs = { 0 }; + + ivs.vf = vf->index; + ivs.setting = vf->trust; + NLA_PUT (nlmsg, IFLA_VF_TRUST, sizeof (ivs), &ivs); + } + + if (vf->mac.len) { + struct ifla_vf_mac ivm = { 0 }; + + ivm.vf = vf->index; + memcpy (ivm.mac, vf->mac.data, vf->mac.len); + NLA_PUT (nlmsg, IFLA_VF_MAC, sizeof (ivm), &ivm); + } + + if (vf->min_tx_rate || vf->max_tx_rate) { + struct _ifla_vf_rate ivr = { 0 }; + + ivr.vf = vf->index; + ivr.min_tx_rate = vf->min_tx_rate; + ivr.max_tx_rate = vf->max_tx_rate; + NLA_PUT (nlmsg, IFLA_VF_RATE, sizeof (ivr), &ivr); + } + + /* Kernel only supports one VLAN per VF now. If this + * changes in the future, we need to figure out how to + * clear existing VLANs and set new ones in one message + * with the new API.*/ + if (vf->num_vlans > 1) { + _LOGW ("multiple VLANs per VF are not supported at the moment"); + return FALSE; + } else { + struct _ifla_vf_vlan_info ivvi = { 0 }; + + if (!(vlan_list = nla_nest_start (nlmsg, IFLA_VF_VLAN_LIST))) + goto nla_put_failure; + + ivvi.vf = vf->index; + if (vf->num_vlans == 1) { + ivvi.vlan = vf->vlans[0].id; + ivvi.qos = vf->vlans[0].qos; + ivvi.vlan_proto = htons (vf->vlans[0].proto_ad ? ETH_P_8021AD : ETH_P_8021Q); + } else { + /* Clear existing VLAN */ + ivvi.vlan = 0; + ivvi.qos = 0; + ivvi.vlan_proto = htons (ETH_P_8021Q); + } + + NLA_PUT (nlmsg, IFLA_VF_VLAN_INFO, sizeof (ivvi), &ivvi); + nla_nest_end (nlmsg, vlan_list); + } + nla_nest_end (nlmsg, info); + } + nla_nest_end (nlmsg, list); + + return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS; +nla_put_failure: + g_return_val_if_reached (FALSE); +} + static char * link_get_physical_port_id (NMPlatform *platform, int ifindex) { @@ -5213,7 +5944,7 @@ link_get_dev_id (NMPlatform *platform, int ifindex) 16, 0, G_MAXUINT16, 0); } -static int +static gboolean vlan_add (NMPlatform *platform, const char *name, int parent, @@ -5229,10 +5960,6 @@ vlan_add (NMPlatform *platform, G_STATIC_ASSERT (NM_VLAN_FLAG_MVRP == (guint32) VLAN_FLAG_MVRP); vlan_flags &= (guint32) NM_VLAN_FLAGS_ALL; - - _LOGD ("link: add vlan '%s', parent %d, vlan id %d, flags %X", - name, parent, vlan_id, (unsigned) vlan_flags); - nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, @@ -5259,7 +5986,7 @@ nla_put_failure: g_return_val_if_reached (FALSE); } -static int +static gboolean link_gre_add (NMPlatform *platform, const char *name, const NMPlatformLnkGre *props, @@ -5268,14 +5995,6 @@ link_gre_add (NMPlatform *platform, nm_auto_nlmsg struct nl_msg *nlmsg = NULL; struct nlattr *info; struct nlattr *data; - char buffer[INET_ADDRSTRLEN]; - - _LOGD (LOG_FMT_IP_TUNNEL, - "gre", - name, - props->parent_ifindex, - nm_utils_inet4_ntop (props->local, NULL), - nm_utils_inet4_ntop (props->remote, buffer)); nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, @@ -5289,7 +6008,7 @@ link_gre_add (NMPlatform *platform, if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) goto nla_put_failure; - NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "gre"); + NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, props->is_tap ? "gretap" : "gre"); if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) goto nla_put_failure; @@ -5303,18 +6022,20 @@ link_gre_add (NMPlatform *platform, NLA_PUT_U8 (nlmsg, IFLA_GRE_PMTUDISC, !!props->path_mtu_discovery); NLA_PUT_U32 (nlmsg, IFLA_GRE_IKEY, htonl (props->input_key)); NLA_PUT_U32 (nlmsg, IFLA_GRE_OKEY, htonl (props->output_key)); - NLA_PUT_U32 (nlmsg, IFLA_GRE_IFLAGS, htons (props->input_flags)); - NLA_PUT_U32 (nlmsg, IFLA_GRE_OFLAGS, htons (props->output_flags)); + NLA_PUT_U16 (nlmsg, IFLA_GRE_IFLAGS, htons (props->input_flags)); + NLA_PUT_U16 (nlmsg, IFLA_GRE_OFLAGS, htons (props->output_flags)); nla_nest_end (nlmsg, data); nla_nest_end (nlmsg, info); - return do_add_link_with_lookup (platform, NM_LINK_TYPE_GRE, name, nlmsg, out_link); + return do_add_link_with_lookup (platform, + props->is_tap ? NM_LINK_TYPE_GRETAP : NM_LINK_TYPE_GRE, + name, nlmsg, out_link); nla_put_failure: g_return_val_if_reached (FALSE); } -static int +static gboolean link_ip6tnl_add (NMPlatform *platform, const char *name, const NMPlatformLnkIp6Tnl *props, @@ -5323,15 +6044,9 @@ link_ip6tnl_add (NMPlatform *platform, nm_auto_nlmsg struct nl_msg *nlmsg = NULL; struct nlattr *info; struct nlattr *data; - char buffer[INET_ADDRSTRLEN]; guint32 flowinfo; - _LOGD (LOG_FMT_IP_TUNNEL, - "ip6tnl", - name, - props->parent_ifindex, - nm_utils_inet6_ntop (&props->local, NULL), - nm_utils_inet6_ntop (&props->remote, buffer)); + g_return_val_if_fail (!props->is_gre, FALSE); nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, @@ -5376,7 +6091,69 @@ nla_put_failure: g_return_val_if_reached (FALSE); } -static int +static gboolean +link_ip6gre_add (NMPlatform *platform, + const char *name, + const NMPlatformLnkIp6Tnl *props, + const NMPlatformLink **out_link) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + struct nlattr *data; + guint32 flowinfo; + + g_return_val_if_fail (props->is_gre, FALSE); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE | NLM_F_EXCL, + 0, + name, + 0, + 0); + if (!nlmsg) + return FALSE; + + if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) + goto nla_put_failure; + + NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, props->is_tap ? "ip6gretap" : "ip6gre"); + + if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->parent_ifindex) + NLA_PUT_U32 (nlmsg, IFLA_GRE_LINK, props->parent_ifindex); + + NLA_PUT_U32 (nlmsg, IFLA_GRE_IKEY, htonl (props->input_key)); + NLA_PUT_U32 (nlmsg, IFLA_GRE_OKEY, htonl (props->output_key)); + NLA_PUT_U16 (nlmsg, IFLA_GRE_IFLAGS, htons (props->input_flags)); + NLA_PUT_U16 (nlmsg, IFLA_GRE_OFLAGS, htons (props->output_flags)); + + if (memcmp (&props->local, &in6addr_any, sizeof (in6addr_any))) + NLA_PUT (nlmsg, IFLA_GRE_LOCAL, sizeof (props->local), &props->local); + if (memcmp (&props->remote, &in6addr_any, sizeof (in6addr_any))) + NLA_PUT (nlmsg, IFLA_GRE_REMOTE, sizeof (props->remote), &props->remote); + + NLA_PUT_U8 (nlmsg, IFLA_GRE_TTL, props->ttl); + NLA_PUT_U8 (nlmsg, IFLA_GRE_ENCAP_LIMIT, props->encap_limit); + + flowinfo = props->flow_label & IP6_FLOWINFO_FLOWLABEL_MASK; + flowinfo |= (props->tclass << IP6_FLOWINFO_TCLASS_SHIFT) + & IP6_FLOWINFO_TCLASS_MASK; + NLA_PUT_U32 (nlmsg, IFLA_GRE_FLOWINFO, htonl (flowinfo)); + NLA_PUT_U32 (nlmsg, IFLA_GRE_FLAGS, props->flags); + + nla_nest_end (nlmsg, data); + nla_nest_end (nlmsg, info); + + return do_add_link_with_lookup (platform, + props->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE, + name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); +} + +static gboolean link_ipip_add (NMPlatform *platform, const char *name, const NMPlatformLnkIpIp *props, @@ -5385,14 +6162,6 @@ link_ipip_add (NMPlatform *platform, nm_auto_nlmsg struct nl_msg *nlmsg = NULL; struct nlattr *info; struct nlattr *data; - char buffer[INET_ADDRSTRLEN]; - - _LOGD (LOG_FMT_IP_TUNNEL, - "ipip", - name, - props->parent_ifindex, - nm_utils_inet4_ntop (props->local, NULL), - nm_utils_inet4_ntop (props->remote, buffer)); nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, @@ -5427,7 +6196,7 @@ nla_put_failure: g_return_val_if_reached (FALSE); } -static int +static gboolean link_macsec_add (NMPlatform *platform, const char *name, int parent, @@ -5438,11 +6207,6 @@ link_macsec_add (NMPlatform *platform, struct nlattr *info; struct nlattr *data; - _LOGD ("adding macsec '%s' parent %u sci %llx", - name, - parent, - (unsigned long long) props->sci); - nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, @@ -5489,7 +6253,7 @@ nla_put_failure: g_return_val_if_reached (FALSE); } -static int +static gboolean link_macvlan_add (NMPlatform *platform, const char *name, int parent, @@ -5500,12 +6264,6 @@ link_macvlan_add (NMPlatform *platform, struct nlattr *info; struct nlattr *data; - _LOGD ("adding %s '%s' parent %u mode %u", - props->tap ? "macvtap" : "macvlan", - name, - parent, - props->mode); - nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, @@ -5538,7 +6296,7 @@ nla_put_failure: g_return_val_if_reached (FALSE); } -static int +static gboolean link_sit_add (NMPlatform *platform, const char *name, const NMPlatformLnkSit *props, @@ -5547,14 +6305,6 @@ link_sit_add (NMPlatform *platform, nm_auto_nlmsg struct nl_msg *nlmsg = NULL; struct nlattr *info; struct nlattr *data; - char buffer[INET_ADDRSTRLEN]; - - _LOGD (LOG_FMT_IP_TUNNEL, - "sit", - name, - props->parent_ifindex, - nm_utils_inet4_ntop (props->local, NULL), - nm_utils_inet4_ntop (props->remote, buffer)); nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, @@ -5658,9 +6408,6 @@ link_vxlan_add (NMPlatform *platform, g_return_val_if_fail (props, FALSE); - _LOGD ("link: add vxlan '%s', parent %d, vxlan id %d", - name, props->parent_ifindex, props->id); - nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, @@ -5718,6 +6465,41 @@ nla_put_failure: g_return_val_if_reached (FALSE); } +static gboolean +link_6lowpan_add (NMPlatform *platform, + const char *name, + int parent, + const NMPlatformLink **out_link) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE | NLM_F_EXCL, + 0, + name, + 0, + 0); + if (!nlmsg) + return FALSE; + + NLA_PUT_U32 (nlmsg, IFLA_LINK, parent); + + if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) + goto nla_put_failure; + + NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "lowpan"); + + nla_nest_end (nlmsg, info); + + return do_add_link_with_lookup (platform, + NM_LINK_TYPE_6LOWPAN, + name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); +} + + static void _vlan_change_vlan_qos_mapping_create (gboolean is_ingress_map, gboolean reset_all, @@ -5812,9 +6594,6 @@ link_vlan_change (NMPlatform *platform, guint new_n_egress_map = 0; gs_free NMVlanQosMapping *new_ingress_map = NULL; gs_free NMVlanQosMapping *new_egress_map = NULL; - char s_flags[64]; - char s_ingress[256]; - char s_egress[256]; obj_cache = nmp_cache_lookup_link (nm_platform_get_cache (platform), ifindex); if ( !obj_cache @@ -5845,26 +6624,6 @@ link_vlan_change (NMPlatform *platform, &new_egress_map, &new_n_egress_map); - _LOGD ("link: change %d: vlan:%s%s%s", - ifindex, - flags_mask - ? nm_sprintf_buf (s_flags, " flags 0x%x/0x%x", (unsigned) flags_set, (unsigned) flags_mask) - : "", - new_n_ingress_map - ? nm_platform_vlan_qos_mapping_to_string (" ingress-qos-map", - new_ingress_map, - new_n_ingress_map, - s_ingress, - sizeof (s_ingress)) - : "", - new_n_egress_map - ? nm_platform_vlan_qos_mapping_to_string (" egress-qos-map", - new_egress_map, - new_n_egress_map, - s_egress, - sizeof (s_egress)) - : ""); - nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, @@ -5891,8 +6650,6 @@ link_enslave (NMPlatform *platform, int master, int slave) nm_auto_nlmsg struct nl_msg *nlmsg = NULL; int ifindex = slave; - _LOGD ("link: change %d: enslave: master %d", slave, master); - nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, @@ -5980,43 +6737,26 @@ infiniband_partition_delete (NMPlatform *platform, int parent, int p_key) /*****************************************************************************/ -static WifiData * -wifi_get_wifi_data (NMPlatform *platform, int ifindex) +static GObject * +get_ext_data (NMPlatform *platform, int ifindex) { - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - const NMPlatformLink *pllink; - WifiData *wifi_data; - - wifi_data = g_hash_table_lookup (priv->wifi_data, GINT_TO_POINTER (ifindex)); - pllink = nm_platform_link_get (platform, ifindex); - - if (!wifi_data) { - if (pllink) { - if (pllink->type == NM_LINK_TYPE_WIFI) - wifi_data = wifi_utils_init (ifindex, TRUE); - else if (pllink->type == NM_LINK_TYPE_OLPC_MESH) { - /* The kernel driver now uses nl80211, but we force use of WEXT because - * the cfg80211 interactions are not quite ready to support access to - * mesh control through nl80211 just yet. - */ -#if HAVE_WEXT - wifi_data = wifi_wext_init (ifindex, FALSE); -#endif - } + const NMPObject *obj; - if (wifi_data) - g_hash_table_insert (priv->wifi_data, GINT_TO_POINTER (ifindex), wifi_data); - } - } + obj = nmp_cache_lookup_link (nm_platform_get_cache (platform), ifindex); + if (!obj) + return NULL; - return wifi_data; + return obj->_link.ext_data; } + +/*****************************************************************************/ + #define WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, retval) \ nm_auto_pop_netns NMPNetns *netns = NULL; \ - WifiData *wifi_data; \ + NMWifiUtils *wifi_data; \ if (!nm_platform_netns_push (platform, &netns)) \ return retval; \ - wifi_data = wifi_get_wifi_data (platform, ifindex); \ + wifi_data = NM_WIFI_UTILS (get_ext_data (platform, ifindex)); \ if (!wifi_data) \ return retval; @@ -6025,7 +6765,7 @@ wifi_get_capabilities (NMPlatform *platform, int ifindex, NMDeviceWifiCapabiliti { WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE); if (caps) - *caps = wifi_utils_get_caps (wifi_data); + *caps = nm_wifi_utils_get_caps (wifi_data); return TRUE; } @@ -6033,63 +6773,70 @@ static gboolean wifi_get_bssid (NMPlatform *platform, int ifindex, guint8 *bssid) { WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE); - return wifi_utils_get_bssid (wifi_data, bssid); + return nm_wifi_utils_get_bssid (wifi_data, bssid); } static guint32 wifi_get_frequency (NMPlatform *platform, int ifindex) { WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0); - return wifi_utils_get_freq (wifi_data); + return nm_wifi_utils_get_freq (wifi_data); } static gboolean wifi_get_quality (NMPlatform *platform, int ifindex) { WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE); - return wifi_utils_get_qual (wifi_data); + return nm_wifi_utils_get_qual (wifi_data); } static guint32 wifi_get_rate (NMPlatform *platform, int ifindex) { WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE); - return wifi_utils_get_rate (wifi_data); + return nm_wifi_utils_get_rate (wifi_data); } static NM80211Mode wifi_get_mode (NMPlatform *platform, int ifindex) { WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, NM_802_11_MODE_UNKNOWN); - return wifi_utils_get_mode (wifi_data); + return nm_wifi_utils_get_mode (wifi_data); } static void wifi_set_mode (NMPlatform *platform, int ifindex, NM80211Mode mode) { WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, ); - wifi_utils_set_mode (wifi_data, mode); + nm_wifi_utils_set_mode (wifi_data, mode); } static void wifi_set_powersave (NMPlatform *platform, int ifindex, guint32 powersave) { WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, ); - wifi_utils_set_powersave (wifi_data, powersave); + nm_wifi_utils_set_powersave (wifi_data, powersave); } static guint32 wifi_find_frequency (NMPlatform *platform, int ifindex, const guint32 *freqs) { WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0); - return wifi_utils_find_freq (wifi_data, freqs); + return nm_wifi_utils_find_freq (wifi_data, freqs); } static void wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean running) { WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, ); - wifi_utils_indicate_addressing_running (wifi_data, running); + nm_wifi_utils_indicate_addressing_running (wifi_data, running); +} + +static NMSettingWirelessWakeOnWLan +wifi_get_wake_on_wlan (NMPlatform *platform, int ifindex) +{ + WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE); + return nm_wifi_utils_get_wake_on_wlan (wifi_data); } static gboolean @@ -6097,7 +6844,7 @@ wifi_set_wake_on_wlan (NMPlatform *platform, int ifindex, NMSettingWirelessWakeOnWLan wowl) { WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE); - return wifi_utils_set_wake_on_wlan (wifi_data, wowl); + return nm_wifi_utils_set_wake_on_wlan (wifi_data, wowl); } /*****************************************************************************/ @@ -6148,21 +6895,56 @@ static guint32 mesh_get_channel (NMPlatform *platform, int ifindex) { WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, 0); - return wifi_utils_get_mesh_channel (wifi_data); + return nm_wifi_utils_get_mesh_channel (wifi_data); } static gboolean mesh_set_channel (NMPlatform *platform, int ifindex, guint32 channel) { WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE); - return wifi_utils_set_mesh_channel (wifi_data, channel); + return nm_wifi_utils_set_mesh_channel (wifi_data, channel); } static gboolean mesh_set_ssid (NMPlatform *platform, int ifindex, const guint8 *ssid, gsize len) { WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE); - return wifi_utils_set_mesh_ssid (wifi_data, ssid, len); + return nm_wifi_utils_set_mesh_ssid (wifi_data, ssid, len); +} + +/*****************************************************************************/ + +#define WPAN_GET_WPAN_DATA(wpan_data, platform, ifindex, retval) \ + NMWpanUtils *wpan_data = NM_WPAN_UTILS (get_ext_data (platform, ifindex)); \ + if (!wpan_data) \ + return retval; + +static guint16 +wpan_get_pan_id (NMPlatform *platform, int ifindex) +{ + WPAN_GET_WPAN_DATA (wpan_data, platform, ifindex, G_MAXINT16); + return nm_wpan_utils_get_pan_id (wpan_data); +} + +static gboolean +wpan_set_pan_id (NMPlatform *platform, int ifindex, guint16 pan_id) +{ + WPAN_GET_WPAN_DATA (wpan_data, platform, ifindex, FALSE); + return nm_wpan_utils_set_pan_id (wpan_data, pan_id); +} + +static guint16 +wpan_get_short_addr (NMPlatform *platform, int ifindex) +{ + WPAN_GET_WPAN_DATA (wpan_data, platform, ifindex, G_MAXINT16); + return nm_wpan_utils_get_short_addr (wpan_data); +} + +static gboolean +wpan_set_short_addr (NMPlatform *platform, int ifindex, guint16 short_addr) +{ + WPAN_GET_WPAN_DATA (wpan_data, platform, ifindex, FALSE); + return nm_wpan_utils_set_short_addr (wpan_data, short_addr); } /*****************************************************************************/ @@ -6179,12 +6961,12 @@ link_get_wake_on_lan (NMPlatform *platform, int ifindex) if (type == NM_LINK_TYPE_ETHERNET) return nmp_utils_ethtool_get_wake_on_lan (ifindex); else if (type == NM_LINK_TYPE_WIFI) { - WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + NMWifiUtils *wifi_data = NM_WIFI_UTILS (get_ext_data (platform, ifindex)); if (!wifi_data) return FALSE; - return wifi_utils_get_wowlan (wifi_data); + return nm_wifi_utils_get_wake_on_wlan (wifi_data) != NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE; } else return FALSE; } @@ -6998,6 +7780,14 @@ handle_udev_event (NMUdevClient *udev_client, /*****************************************************************************/ +void +nm_linux_platform_setup (void) +{ + nm_platform_setup (nm_linux_platform_new (FALSE, FALSE)); +} + +/*****************************************************************************/ + static void nm_linux_platform_init (NMLinuxPlatform *self) { @@ -7006,7 +7796,6 @@ nm_linux_platform_init (NMLinuxPlatform *self) priv->delayed_action.list_master_connected = g_ptr_array_new (); priv->delayed_action.list_refresh_link = g_ptr_array_new (); priv->delayed_action.list_wait_for_nl_response = g_array_new (FALSE, TRUE, sizeof (DelayedActionWaitForNlResponseData)); - priv->wifi_data = g_hash_table_new_full (nm_direct_hash, NULL, NULL, (GDestroyNotify) wifi_utils_unref); } static void @@ -7036,6 +7825,18 @@ constructed (GObject *_object) nmp_netns_get_current () == nmp_netns_get_initial () ? "/main" : "")), nm_platform_get_use_udev (platform) ? "use" : "no"); + + priv->genl = nl_socket_alloc (); + g_assert (priv->genl); + + nle = nl_connect (priv->genl, NETLINK_GENERIC); + if (nle) { + _LOGE ("unable to connect the generic netlink socket \"%s\" (%d)", + nl_geterror (nle), -nle); + nl_socket_free (priv->genl); + priv->genl = NULL; + } + priv->nlh = nl_socket_alloc (); g_assert (priv->nlh); @@ -7127,6 +7928,22 @@ constructed (GObject *_object) } } +NMPlatform * +nm_linux_platform_new (gboolean log_with_ptr, gboolean netns_support) +{ + gboolean use_udev = FALSE; + + if ( nmp_netns_is_initial () + && access ("/sys", W_OK) == 0) + use_udev = TRUE; + + return g_object_new (NM_TYPE_LINUX_PLATFORM, + NM_PLATFORM_LOG_WITH_PTR, log_with_ptr, + NM_PLATFORM_USE_UDEV, use_udev, + NM_PLATFORM_NETNS_SUPPORT, netns_support, + NULL); +} + static void dispose (GObject *object) { @@ -7154,12 +7971,12 @@ finalize (GObject *object) g_ptr_array_unref (priv->delayed_action.list_refresh_link); g_array_unref (priv->delayed_action.list_wait_for_nl_response); + nl_socket_free (priv->genl); + g_source_remove (priv->event_id); g_io_channel_unref (priv->event_channel); nl_socket_free (priv->nlh); - g_hash_table_unref (priv->wifi_data); - if (priv->sysctl_get_prev_values) { sysctl_clear_cache_list = g_slist_remove (sysctl_clear_cache_list, object); g_hash_table_destroy (priv->sysctl_get_prev_values); @@ -7205,7 +8022,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_get_permanent_address = link_get_permanent_address; platform_class->link_set_mtu = link_set_mtu; platform_class->link_set_name = link_set_name; - platform_class->link_set_sriov_num_vfs = link_set_sriov_num_vfs; + platform_class->link_set_sriov_params = link_set_sriov_params; + platform_class->link_set_sriov_vfs = link_set_sriov_vfs; platform_class->link_get_physical_port_id = link_get_physical_port_id; platform_class->link_get_dev_id = link_get_dev_id; @@ -7238,19 +8056,27 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->wifi_set_powersave = wifi_set_powersave; platform_class->wifi_find_frequency = wifi_find_frequency; platform_class->wifi_indicate_addressing_running = wifi_indicate_addressing_running; + platform_class->wifi_get_wake_on_wlan = wifi_get_wake_on_wlan; platform_class->wifi_set_wake_on_wlan = wifi_set_wake_on_wlan; platform_class->mesh_get_channel = mesh_get_channel; platform_class->mesh_set_channel = mesh_set_channel; platform_class->mesh_set_ssid = mesh_set_ssid; + platform_class->wpan_get_pan_id = wpan_get_pan_id; + platform_class->wpan_set_pan_id = wpan_set_pan_id; + platform_class->wpan_get_short_addr = wpan_get_short_addr; + platform_class->wpan_set_short_addr = wpan_set_short_addr; + platform_class->link_gre_add = link_gre_add; platform_class->link_ip6tnl_add = link_ip6tnl_add; + platform_class->link_ip6gre_add = link_ip6gre_add; platform_class->link_macsec_add = link_macsec_add; platform_class->link_macvlan_add = link_macvlan_add; platform_class->link_ipip_add = link_ipip_add; platform_class->link_sit_add = link_sit_add; platform_class->link_tun_add = link_tun_add; + platform_class->link_6lowpan_add = link_6lowpan_add; platform_class->object_delete = object_delete; platform_class->ip4_address_add = ip4_address_add; diff --git a/src/platform/nm-netlink.c b/src/platform/nm-netlink.c index 4cb19780..3e2ad911 100644 --- a/src/platform/nm-netlink.c +++ b/src/platform/nm-netlink.c @@ -52,7 +52,6 @@ struct nl_msg { struct ucred nm_creds; struct nlmsghdr * nm_nlh; size_t nm_size; - int nm_refcnt; }; struct nl_sock { @@ -84,18 +83,18 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_geterror, int, ) const char * -nl_geterror (int err) +nl_geterror (int nlerr) { const char *s; - err = nl_errno (err); + nlerr = nl_errno (nlerr); - if (err >= _NLE_BASE) { - s = _geterror (err); + if (nlerr >= _NLE_BASE) { + s = _geterror (nlerr); if (s) return s; } - return g_strerror (err); + return g_strerror (nlerr); } /*****************************************************************************/ @@ -252,27 +251,13 @@ nlmsg_reserve (struct nl_msg *n, size_t len, int pad) n->nm_nlh->nlmsg_len += tlen; if (tlen > len) - memset(buf + len, 0, tlen - len); + memset (buf + len, 0, tlen - len); return buf; } /*****************************************************************************/ -static int - get_default_page_size (void) -{ - static int val = 0; - int v; - - if (G_UNLIKELY (val == 0)) { - v = getpagesize (); - g_assert (v > 0); - val = v; - } - return val; -} - struct nlattr * nla_reserve (struct nl_msg *msg, int attrtype, int attrlen) { @@ -282,22 +267,38 @@ nla_reserve (struct nl_msg *msg, int attrtype, int attrlen) if (attrlen < 0) return NULL; - tlen = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) + nla_total_size(attrlen); + tlen = NLMSG_ALIGN (msg->nm_nlh->nlmsg_len) + nla_total_size (attrlen); if (tlen > msg->nm_size) return NULL; - nla = (struct nlattr *) nlmsg_tail(msg->nm_nlh); + nla = (struct nlattr *) nlmsg_tail (msg->nm_nlh); nla->nla_type = attrtype; - nla->nla_len = nla_attr_size(attrlen); + nla->nla_len = nla_attr_size (attrlen); if (attrlen) - memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen)); + memset ((unsigned char *) nla + nla->nla_len, 0, nla_padlen (attrlen)); msg->nm_nlh->nlmsg_len = tlen; return nla; } +/*****************************************************************************/ + +static int +get_default_page_size (void) +{ + static int val = 0; + int v; + + if (G_UNLIKELY (val == 0)) { + v = getpagesize (); + g_assert (v > 0); + val = v; + } + return val; +} + struct nl_msg * nlmsg_alloc_size (size_t len) { @@ -308,7 +309,6 @@ nlmsg_alloc_size (size_t len) nm = g_slice_new0 (struct nl_msg); - nm->nm_refcnt = 1; nm->nm_protocol = -1; nm->nm_size = len; nm->nm_nlh = g_malloc0 (len); @@ -331,48 +331,40 @@ nlmsg_alloc (void) return nlmsg_alloc_size (get_default_page_size ()); } -/** - * Allocate a new netlink message with maximum payload size specified. - */ struct nl_msg * -nlmsg_alloc_inherit (struct nlmsghdr *hdr) +nlmsg_alloc_convert (struct nlmsghdr *hdr) { struct nl_msg *nm; - nm = nlmsg_alloc (); - if (hdr) { - struct nlmsghdr *new = nm->nm_nlh; - - new->nlmsg_type = hdr->nlmsg_type; - new->nlmsg_flags = hdr->nlmsg_flags; - new->nlmsg_seq = hdr->nlmsg_seq; - new->nlmsg_pid = hdr->nlmsg_pid; - } - + nm = nlmsg_alloc_size (NLMSG_ALIGN (hdr->nlmsg_len)); + memcpy (nm->nm_nlh, hdr, hdr->nlmsg_len); return nm; } struct nl_msg * -nlmsg_alloc_convert (struct nlmsghdr *hdr) +nlmsg_alloc_simple (int nlmsgtype, int flags) { struct nl_msg *nm; + struct nlmsghdr *new; - nm = nlmsg_alloc_size (NLMSG_ALIGN (hdr->nlmsg_len)); - memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len); + nm = nlmsg_alloc (); + new = nm->nm_nlh; + new->nlmsg_type = nlmsgtype; + new->nlmsg_flags = flags; return nm; } -struct nl_msg * -nlmsg_alloc_simple (int nlmsgtype, int flags) +void nlmsg_free (struct nl_msg *msg) { - struct nlmsghdr nlh = { - .nlmsg_type = nlmsgtype, - .nlmsg_flags = flags, - }; + if (!msg) + return; - return nlmsg_alloc_inherit (&nlh); + g_free (msg->nm_nlh); + g_slice_free (struct nl_msg, msg); } +/*****************************************************************************/ + int nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad) { @@ -382,19 +374,21 @@ nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad) if (tmp == NULL) return -ENOMEM; - memcpy(tmp, data, len); + memcpy (tmp, data, len); return 0; } +/*****************************************************************************/ + int nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy) { - if (!nlmsg_valid_hdr(nlh, hdrlen)) + if (!nlmsg_valid_hdr (nlh, hdrlen)) return -NLE_MSG_TOOSHORT; - return nla_parse (tb, maxtype, nlmsg_attrdata(nlh, hdrlen), - nlmsg_attrlen(nlh, hdrlen), policy); + return nla_parse (tb, maxtype, nlmsg_attrdata (nlh, hdrlen), + nlmsg_attrlen (nlh, hdrlen), policy); } struct nlmsghdr * @@ -412,8 +406,8 @@ nlmsg_put (struct nl_msg *n, uint32_t pid, uint32_t seq, nlh->nlmsg_pid = pid; nlh->nlmsg_seq = seq; - if (payload > 0 && - nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL) + if ( payload > 0 + && nlmsg_reserve (n, payload, NLMSG_ALIGNTO) == NULL) return NULL; return nlh; @@ -424,8 +418,8 @@ nla_get_u64 (const struct nlattr *nla) { uint64_t tmp = 0; - if (nla && nla_len(nla) >= sizeof (tmp)) - memcpy(&tmp, nla_data(nla), sizeof (tmp)); + if (nla && nla_len (nla) >= sizeof (tmp)) + memcpy (&tmp, nla_data (nla), sizeof (tmp)); return tmp; } @@ -433,8 +427,8 @@ nla_get_u64 (const struct nlattr *nla) size_t nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize) { - size_t srclen = nla_len(nla); - const char *src = nla_data(nla); + size_t srclen = nla_len (nla); + const char *src = nla_data (nla); if (srclen > 0 && src[srclen - 1] == '\0') srclen--; @@ -442,8 +436,8 @@ nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize) if (dstsize > 0) { size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen; - memset(dst, 0, dstsize); - memcpy(dst, src, len); + memset (dst, 0, dstsize); + memcpy (dst, src, len); } return srclen; @@ -458,7 +452,7 @@ nla_memcpy (void *dest, const struct nlattr *src, int count) return 0; minlen = NM_MIN (count, (int) nla_len (src)); - memcpy(dest, nla_data(src), minlen); + memcpy (dest, nla_data (src), minlen); return minlen; } @@ -468,7 +462,7 @@ nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data) { struct nlattr *nla; - nla = nla_reserve(msg, attrtype, datalen); + nla = nla_reserve (msg, attrtype, datalen); if (!nla) { if (datalen < 0) g_return_val_if_reached (-NLE_BUG); @@ -477,7 +471,7 @@ nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data) } if (datalen > 0) - memcpy (nla_data(nla), data, datalen); + memcpy (nla_data (nla), data, datalen); return 0; } @@ -501,21 +495,21 @@ nla_nest_cancel (struct nl_msg *msg, const struct nlattr *attr) { ssize_t len; - len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) attr; + len = (char *) nlmsg_tail (msg->nm_nlh) - (char *) attr; if (len < 0) g_return_if_reached (); else if (len > 0) { msg->nm_nlh->nlmsg_len -= len; - memset(nlmsg_tail(msg->nm_nlh), 0, len); + memset (nlmsg_tail (msg->nm_nlh), 0, len); } } struct nlattr * nla_nest_start (struct nl_msg *msg, int attrtype) { - struct nlattr *start = (struct nlattr *) nlmsg_tail(msg->nm_nlh); + struct nlattr *start = (struct nlattr *) nlmsg_tail (msg->nm_nlh); - if (nla_put(msg, attrtype, 0, NULL) < 0) + if (nla_put (msg, attrtype, 0, NULL) < 0) return NULL; return start; @@ -526,7 +520,7 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty) { size_t pad, len; - len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) start; + len = (char *) nlmsg_tail (msg->nm_nlh) - (char *) start; if ( len > USHRT_MAX || (!keep_empty && len == NLA_HDRLEN)) { @@ -534,7 +528,7 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty) * Max nlattr size exceeded or empty nested attribute, trim the * attribute header again */ - nla_nest_cancel(msg, start); + nla_nest_cancel (msg, start); /* Return error only if nlattr size was exceeded */ return (len == NLA_HDRLEN) ? 0 : -NLE_ATTRSIZE; @@ -542,7 +536,7 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty) start->nla_len = len; - pad = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len; + pad = NLMSG_ALIGN (msg->nm_nlh->nlmsg_len) - msg->nm_nlh->nlmsg_len; if (pad > 0) { /* * Data inside attribute does not end at a alignment boundry. @@ -550,7 +544,7 @@ _nest_end (struct nl_msg *msg, struct nlattr *start, int keep_empty) * the message. nlmsg_reserve() may never fail in this situation, * the allocate message buffer must be a multiple of NLMSG_ALIGNTO. */ - if (!nlmsg_reserve(msg, pad, 0)) + if (!nlmsg_reserve (msg, pad, 0)) g_return_val_if_reached (-NLE_BUG); } @@ -578,7 +572,7 @@ validate_nla (const struct nlattr *nla, int maxtype, { const struct nla_policy *pt; unsigned int minlen = 0; - int type = nla_type(nla); + int type = nla_type (nla); if (type < 0 || type > maxtype) return 0; @@ -593,15 +587,15 @@ validate_nla (const struct nlattr *nla, int maxtype, else if (pt->type != NLA_UNSPEC) minlen = nla_attr_minlen[pt->type]; - if (nla_len(nla) < minlen) + if (nla_len (nla) < minlen) return -NLE_UNSPEC; - if (pt->maxlen && nla_len(nla) > pt->maxlen) + if (pt->maxlen && nla_len (nla) > pt->maxlen) return -NLE_UNSPEC; if (pt->type == NLA_STRING) { - const char *data = nla_data(nla); - if (data[nla_len(nla) - 1] != '\0') + const char *data = nla_data (nla); + if (data[nla_len (nla) - 1] != '\0') return -NLE_UNSPEC; } @@ -613,48 +607,32 @@ nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, const struct nla_policy *policy) { struct nlattr *nla; - int rem, err; + int rem, nlerr; - memset(tb, 0, sizeof (struct nlattr *) * (maxtype + 1)); + memset (tb, 0, sizeof (struct nlattr *) * (maxtype + 1)); - nla_for_each_attr(nla, head, len, rem) { - int type = nla_type(nla); + nla_for_each_attr (nla, head, len, rem) { + int type = nla_type (nla); if (type > maxtype) continue; if (policy) { - err = validate_nla(nla, maxtype, policy); - if (err < 0) + nlerr = validate_nla (nla, maxtype, policy); + if (nlerr < 0) goto errout; } tb[type] = nla; } - err = 0; + nlerr = 0; errout: - return err; + return nlerr; } /*****************************************************************************/ -void nlmsg_free (struct nl_msg *msg) -{ - if (!msg) - return; - - if (msg->nm_refcnt < 1) - g_return_if_reached (); - - msg->nm_refcnt--; - - if (msg->nm_refcnt <= 0) { - g_free (msg->nm_nlh); - g_slice_free (struct nl_msg, msg); - } -} - int nlmsg_get_proto (struct nl_msg *msg) { @@ -813,7 +791,7 @@ int genl_ctrl_resolve (struct nl_sock *sk, const char *name) { nm_auto_nlmsg struct nl_msg *msg = NULL; - int result = -ENOMEM; + int nlerr; gint32 response_data = -1; const struct nl_cb cb = { .valid_cb = _genl_parse_getfamily, @@ -824,31 +802,29 @@ genl_ctrl_resolve (struct nl_sock *sk, const char *name) if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL, 0, 0, CTRL_CMD_GETFAMILY, 1)) - goto out; + return -ENOMEM; - if (nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name) < 0) - goto out; + nlerr = nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name); + if (nlerr < 0) + return nlerr; - result = nl_send_auto (sk, msg); - if (result < 0) - goto out; + nlerr = nl_send_auto (sk, msg); + if (nlerr < 0) + return nlerr; - result = nl_recvmsgs (sk, &cb); - if (result < 0) - goto out; + nlerr = nl_recvmsgs (sk, &cb); + if (nlerr < 0) + return nlerr; /* If search was successful, request may be ACKed after data */ - result = nl_wait_for_ack (sk, NULL); - if (result < 0) - goto out; + nlerr = nl_wait_for_ack (sk, NULL); + if (nlerr < 0) + return nlerr; - if (response_data > 0) - result = response_data; - else - result = -ENOENT; + if (response_data < 0) + return -NLE_UNSPEC; -out: - return result; + return response_data; } /*****************************************************************************/ @@ -863,7 +839,7 @@ nl_socket_alloc (void) sk->s_fd = -1; sk->s_local.nl_family = AF_NETLINK; sk->s_peer.nl_family = AF_NETLINK; - sk->s_seq_expect = sk->s_seq_next = time(NULL); + sk->s_seq_expect = sk->s_seq_next = time (NULL); return sk; } @@ -938,7 +914,7 @@ nl_socket_set_nonblocking (const struct nl_sock *sk) if (sk->s_fd == -1) return -NLE_BAD_SOCK; - if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0) + if (fcntl (sk->s_fd, F_SETFL, O_NONBLOCK) < 0) return -nl_syserr2nlerr (errno); return 0; @@ -982,25 +958,27 @@ nl_socket_add_memberships (struct nl_sock *sk, int group, ...) if (sk->s_fd == -1) return -NLE_BAD_SOCK; - va_start(ap, group); + va_start (ap, group); while (group != 0) { if (group < 0) { - va_end(ap); + va_end (ap); g_return_val_if_reached (-NLE_BUG); } err = setsockopt (sk->s_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof (group)); if (err < 0) { - va_end(ap); - return -nl_syserr2nlerr (errno); + int errsv = errno; + + va_end (ap); + return -nl_syserr2nlerr (errsv); } - group = va_arg(ap, int); + group = va_arg (ap, int); } - va_end(ap); + va_end (ap); return 0; } @@ -1030,7 +1008,7 @@ void nl_socket_disable_msg_peek (struct nl_sock *sk) int nl_connect (struct nl_sock *sk, int protocol) { - int err; + int err, nlerr; socklen_t addrlen; struct sockaddr_nl local = { 0 }; @@ -1039,12 +1017,12 @@ nl_connect (struct nl_sock *sk, int protocol) sk->s_fd = socket (AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); if (sk->s_fd < 0) { - err = -nl_syserr2nlerr (errno); + nlerr = -nl_syserr2nlerr (errno); goto errout; } - err = nl_socket_set_buffer_size(sk, 0, 0); - if (err < 0) + nlerr = nl_socket_set_buffer_size (sk, 0, 0); + if (nlerr < 0) goto errout; nm_assert (sk->s_local.nl_pid == 0); @@ -1052,7 +1030,7 @@ nl_connect (struct nl_sock *sk, int protocol) err = bind (sk->s_fd, (struct sockaddr*) &sk->s_local, sizeof (sk->s_local)); if (err != 0) { - err = -nl_syserr2nlerr (errno); + nlerr = -nl_syserr2nlerr (errno); goto errout; } @@ -1060,17 +1038,17 @@ nl_connect (struct nl_sock *sk, int protocol) err = getsockname (sk->s_fd, (struct sockaddr *) &local, &addrlen); if (err < 0) { - err = -nl_syserr2nlerr (errno); + nlerr = -nl_syserr2nlerr (errno); goto errout; } if (addrlen != sizeof (local)) { - err = -NLE_UNSPEC; + nlerr = -NLE_UNSPEC; goto errout; } if (local.nl_family != AF_NETLINK) { - err = -NLE_UNSPEC; + nlerr = -NLE_UNSPEC; goto errout; } @@ -1081,10 +1059,10 @@ nl_connect (struct nl_sock *sk, int protocol) errout: if (sk->s_fd != -1) { - close(sk->s_fd); + close (sk->s_fd); sk->s_fd = -1; } - return err; + return nlerr; } /*****************************************************************************/ @@ -1100,7 +1078,7 @@ _cb_init (struct nl_cb *dst, const struct nl_cb *src) memset (dst, 0, sizeof (*dst)); } -static int ack_wait_handler(struct nl_msg *msg, void *arg) +static int ack_wait_handler (struct nl_msg *msg, void *arg) { return NL_STOP; } @@ -1121,16 +1099,22 @@ do { \ const struct nl_cb *_cb = (cb); \ \ if (_cb->type##_cb) { \ - err = _cb->type##_cb ((msg), _cb->type##_arg); \ - switch (err) { \ + /* the returned value here must be either a negative + * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */ \ + nlerr = _cb->type##_cb ((msg), _cb->type##_arg); \ + switch (nlerr) { \ case NL_OK: \ - err = 0; \ + nlerr = 0; \ break; \ case NL_SKIP: \ goto skip; \ case NL_STOP: \ goto stop; \ default: \ + if (nlerr >= 0) { \ + nm_assert_not_reached (); \ + nlerr = -NLE_BUG; \ + } \ goto out; \ } \ } \ @@ -1139,7 +1123,7 @@ do { \ int nl_recvmsgs (struct nl_sock *sk, const struct nl_cb *cb) { - int n, err = 0, multipart = 0, interrupted = 0, nrecv = 0; + int n, nlerr = 0, multipart = 0, interrupted = 0, nrecv = 0; gs_free unsigned char *buf = NULL; struct nlmsghdr *hdr; struct sockaddr_nl nla = { 0 }; @@ -1164,9 +1148,9 @@ continue_reading: nrecv++; /* Only do sequence checking if auto-ack mode is enabled */ - if (!(sk->s_flags & NL_NO_AUTO_ACK)) { + if (! (sk->s_flags & NL_NO_AUTO_ACK)) { if (hdr->nlmsg_seq != sk->s_seq_expect) { - err = -NLE_SEQ_MISMATCH; + nlerr = -NLE_SEQ_MISMATCH; goto out; } } @@ -1198,7 +1182,7 @@ continue_reading: * this action by skipping this packet. */ if (hdr->nlmsg_type == NLMSG_DONE) { multipart = 0; - NL_CB_CALL(cb, finish, msg); + NL_CB_CALL (cb, finish, msg); } /* Message to be ignored, the default action is to @@ -1212,50 +1196,53 @@ continue_reading: * quit parsing. The user may overrule this action by retuning * NL_SKIP or NL_PROCEED (dangerous) */ else if (hdr->nlmsg_type == NLMSG_OVERRUN) { - err = -NLE_MSG_OVERFLOW; + nlerr = -NLE_MSG_OVERFLOW; goto out; } /* Message carries a nlmsgerr */ else if (hdr->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *e = nlmsg_data(hdr); + struct nlmsgerr *e = nlmsg_data (hdr); - if (hdr->nlmsg_len < nlmsg_size(sizeof (*e))) { + if (hdr->nlmsg_len < nlmsg_size (sizeof (*e))) { /* Truncated error message, the default action * is to stop parsing. The user may overrule * this action by returning NL_SKIP or * NL_PROCEED (dangerous) */ - err = -NLE_MSG_TRUNC; + nlerr = -NLE_MSG_TRUNC; goto out; } if (e->error) { /* Error message reported back from kernel. */ if (cb->err_cb) { - err = cb->err_cb (&nla, e, - cb->err_arg); - if (err < 0) + /* the returned value here must be either a negative + * netlink error number, or one of NL_SKIP, NL_STOP, NL_OK. */ + nlerr = cb->err_cb (&nla, e, + cb->err_arg); + if (nlerr < 0) goto out; - else if (err == NL_SKIP) + else if (nlerr == NL_SKIP) goto skip; - else if (err == NL_STOP) { - err = -e->error; + else if (nlerr == NL_STOP) { + nlerr = -nl_syserr2nlerr (e->error); goto out; } + nm_assert (nlerr == NL_OK); } else { - err = -e->error; + nlerr = -nl_syserr2nlerr (e->error); goto out; } } else - NL_CB_CALL(cb, ack, msg); + NL_CB_CALL (cb, ack, msg); } else { /* Valid message (not checking for MULTIPART bit to * get along with broken kernels. NL_SKIP has no * effect on this. */ - NL_CB_CALL(cb, valid, msg); + NL_CB_CALL (cb, valid, msg); } skip: - err = 0; - hdr = nlmsg_next(hdr, &n); + nlerr = 0; + hdr = nlmsg_next (hdr, &n); } if (multipart) { @@ -1267,13 +1254,14 @@ skip: } stop: - err = 0; + nlerr = 0; out: if (interrupted) - err = -NLE_DUMP_INTR; + nlerr = -NLE_DUMP_INTR; - return err ?: nrecv; + nm_assert (nlerr <= 0); + return nlerr ?: nrecv; } int @@ -1286,7 +1274,7 @@ nl_sendmsg (struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr) nlmsg_set_src (msg, &sk->s_local); - ret = sendmsg(sk->s_fd, hdr, 0); + ret = sendmsg (sk->s_fd, hdr, 0); if (ret < 0) return -nl_syserr2nlerr (errno); @@ -1304,31 +1292,31 @@ nl_send_iovec (struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsign .msg_iov = iov, .msg_iovlen = iovlen, }; - char buf[CMSG_SPACE(sizeof (struct ucred))]; + char buf[CMSG_SPACE (sizeof (struct ucred))]; /* Overwrite destination if specified in the message itself, defaults * to the peer address of the socket. */ - dst = nlmsg_get_dst(msg); + dst = nlmsg_get_dst (msg); if (dst->nl_family == AF_NETLINK) hdr.msg_name = dst; /* Add credentials if present. */ - creds = nlmsg_get_creds(msg); + creds = nlmsg_get_creds (msg); if (creds != NULL) { struct cmsghdr *cmsg; hdr.msg_control = buf; hdr.msg_controllen = sizeof (buf); - cmsg = CMSG_FIRSTHDR(&hdr); + cmsg = CMSG_FIRSTHDR (&hdr); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_CREDENTIALS; - cmsg->cmsg_len = CMSG_LEN(sizeof (struct ucred)); - memcpy(CMSG_DATA(cmsg), creds, sizeof (struct ucred)); + cmsg->cmsg_len = CMSG_LEN (sizeof (struct ucred)); + memcpy (CMSG_DATA (cmsg), creds, sizeof (struct ucred)); } - return nl_sendmsg(sk, msg, &hdr); + return nl_sendmsg (sk, msg, &hdr); } void @@ -1336,9 +1324,9 @@ nl_complete_msg (struct nl_sock *sk, struct nl_msg *msg) { struct nlmsghdr *nlh; - nlh = nlmsg_hdr(msg); + nlh = nlmsg_hdr (msg); if (nlh->nlmsg_pid == NL_AUTO_PORT) - nlh->nlmsg_pid = nl_socket_get_local_port(sk); + nlh->nlmsg_pid = nl_socket_get_local_port (sk); if (nlh->nlmsg_seq == NL_AUTO_SEQ) nlh->nlmsg_seq = sk->s_seq_next++; @@ -1356,18 +1344,18 @@ int nl_send (struct nl_sock *sk, struct nl_msg *msg) { struct iovec iov = { - .iov_base = (void *) nlmsg_hdr(msg), - .iov_len = nlmsg_hdr(msg)->nlmsg_len, + .iov_base = (void *) nlmsg_hdr (msg), + .iov_len = nlmsg_hdr (msg)->nlmsg_len, }; - return nl_send_iovec(sk, msg, &iov, 1); + return nl_send_iovec (sk, msg, &iov, 1); } -int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg) +int nl_send_auto (struct nl_sock *sk, struct nl_msg *msg) { - nl_complete_msg(sk, msg); + nl_complete_msg (sk, msg); - return nl_send(sk, msg); + return nl_send (sk, msg); } int @@ -1397,9 +1385,9 @@ nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, flags |= MSG_PEEK | MSG_TRUNC; if (page_size == 0) - page_size = getpagesize() * 4; + page_size = getpagesize () * 4; - iov.iov_len = sk->s_bufsize ? : page_size; + iov.iov_len = sk->s_bufsize ?: page_size; iov.iov_base = g_malloc (iov.iov_len); if ( creds @@ -1409,7 +1397,7 @@ nl_recv (struct nl_sock *sk, struct sockaddr_nl *nla, } retry: - n = recvmsg(sk->s_fd, &msg, flags); + n = recvmsg (sk->s_fd, &msg, flags); if (!n) { retval = 0; goto abort; @@ -1465,12 +1453,12 @@ retry: if (creds && (sk->s_flags & NL_SOCK_PASSCRED)) { struct cmsghdr *cmsg; - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) { if (cmsg->cmsg_level != SOL_SOCKET) continue; if (cmsg->cmsg_type != SCM_CREDENTIALS) continue; - tmpcreds = g_memdup (CMSG_DATA(cmsg), sizeof (*tmpcreds)); + tmpcreds = nm_memdup (CMSG_DATA (cmsg), sizeof (*tmpcreds)); break; } } diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h index 185269ba..d5df7ab9 100644 --- a/src/platform/nm-netlink.h +++ b/src/platform/nm-netlink.h @@ -52,32 +52,48 @@ #endif static inline int -nl_errno (int err) +nl_errno (int nlerr) { - /* the error codes from our netlink implementation are plain errno - * extended with our own error in a particular range starting from - * _NLE_BASE. + /* Normalizes an netlink error to be positive. Various API returns negative + * error codes, and this function converts the negative value to its + * positive. * - * However, often we encode errors as negative values. This function - * normalizes the error and returns its positive value. */ - return err >= 0 - ? err - : ((err == G_MININT) ? NLE_BUG : -errno); + * It's very similar to nm_errno(), but not exactly. The difference is that + * nm_errno() is for plain errno, while nl_errno() is for netlink error numbers. + * Yes, netlink error number are ~almost~ the same as errno, except that a particular + * range (_NLE_BASE, _NLE_BASE_END) is reserved. The difference between the two + * functions is only how G_MININT is mapped. + * + * See also nl_syserr2nlerr() below. */ + return nlerr >= 0 + ? nlerr + : ((nlerr == G_MININT) ? NLE_BUG : -nlerr); } static inline int -nl_syserr2nlerr (int err) +nl_syserr2nlerr (int errsv) { - if (err == G_MININT) + /* this maps a native errno to a (always non-negative) netlink error number. + * + * Note that netlink error numbers are embedded into the range of regular + * errno. The only difference is, that netlink error numbers reserve a + * range (_NLE_BASE, _NLE_BASE_END) for their own purpose. + * + * That means, converting an errno to netlink error number means in + * most cases just returning itself (negative values are normalized + * to be positive). Only values G_MININT and [_NLE_BASE, _NLE_BASE_END] + * are coerced to the special value NLE_NATIVE_ERRNO, as they cannot + * otherwise be represented in netlink error number domain. */ + if (errsv == G_MININT) return NLE_NATIVE_ERRNO; - if (err < 0) - err = -err; - return (err >= _NLE_BASE && err < _NLE_BASE_END) + if (errsv < 0) + errsv = -errsv; + return (errsv >= _NLE_BASE && errsv < _NLE_BASE_END) ? NLE_NATIVE_ERRNO - : err; + : errsv; } -const char *nl_geterror (int err); +const char *nl_geterror (int nlerr); /*****************************************************************************/ @@ -177,6 +193,12 @@ nla_get_u8 (const struct nlattr *nla) } static inline uint8_t +nla_get_s8 (const struct nlattr *nla) +{ + return *(const int8_t *) nla_data (nla); +} + +static inline uint8_t nla_get_u8_cond (/*const*/ struct nlattr *const*tb, int attr, uint8_t default_val) { nm_assert (tb); @@ -197,6 +219,12 @@ nla_get_u32(const struct nlattr *nla) return *(const uint32_t *) nla_data (nla); } +static inline int32_t +nla_get_s32(const struct nlattr *nla) +{ + return *(const int32_t *) nla_data (nla); +} + uint64_t nla_get_u64 (const struct nlattr *nla); static inline char * @@ -232,12 +260,18 @@ nla_put_string (struct nl_msg *msg, int attrtype, const char *str) #define NLA_PUT_U8(msg, attrtype, value) \ NLA_PUT_TYPE(msg, uint8_t, attrtype, value) +#define NLA_PUT_S8(msg, attrtype, value) \ + NLA_PUT_TYPE(msg, int8_t, attrtype, value) + #define NLA_PUT_U16(msg, attrtype, value) \ NLA_PUT_TYPE(msg, uint16_t, attrtype, value) #define NLA_PUT_U32(msg, attrtype, value) \ NLA_PUT_TYPE(msg, uint32_t, attrtype, value) +#define NLA_PUT_S32(msg, attrtype, value) \ + NLA_PUT_TYPE(msg, int32_t, attrtype, value) + #define NLA_PUT_U64(msg, attrtype, value) \ NLA_PUT_TYPE(msg, uint64_t, attrtype, value) @@ -252,7 +286,7 @@ struct nlattr *nla_find (const struct nlattr *head, int len, int attrtype); static inline int nla_ok (const struct nlattr *nla, int remaining) { - return remaining >= sizeof(*nla) && + return remaining >= (int) sizeof(*nla) && nla->nla_len >= sizeof(*nla) && nla->nla_len <= remaining; } @@ -296,8 +330,6 @@ struct nl_msg *nlmsg_alloc (void); struct nl_msg *nlmsg_alloc_size (size_t max); -struct nl_msg *nlmsg_alloc_inherit (struct nlmsghdr *hdr); - struct nl_msg *nlmsg_alloc_convert (struct nlmsghdr *hdr); struct nl_msg *nlmsg_alloc_simple (int nlmsgtype, int flags); diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index 0d224443..216b1547 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -36,12 +36,15 @@ #include "nm-utils.h" #include "nm-setting-wired.h" +#include "nm-ethtool-utils.h" #include "nm-core-utils.h" -/****************************************************************** +#define ONOFF(bool_val) ((bool_val) ? "on" : "off") + +/****************************************************************************** * utils - ******************************************************************/ + *****************************************************************************/ extern char *if_indextoname (unsigned __ifindex, char *__ifname); unsigned if_nametoindex (const char *__ifname); @@ -63,9 +66,45 @@ nmp_utils_if_nametoindex (const char *ifname) return if_nametoindex (ifname); } -/****************************************************************** +/*****************************************************************************/ + +typedef struct { + int fd; + int ifindex; + char ifname[IFNAMSIZ]; +} SocketHandle; + +static int +socket_handle_init (SocketHandle *shandle, int ifindex) +{ + if (!nmp_utils_if_indextoname (ifindex, shandle->ifname)) { + shandle->ifindex = 0; + return -ENODEV; + } + + shandle->fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (shandle->fd < 0) { + shandle->ifindex = 0; + return -errno; + } + + shandle->ifindex = ifindex; + return 0; +} + +static void +socket_handle_destroy (SocketHandle *shandle) +{ + if (shandle->ifindex) { + shandle->ifindex = 0; + nm_close (shandle->fd); + } +} +#define nm_auto_socket_handle nm_auto(socket_handle_destroy) + +/****************************************************************************** * ethtool - ******************************************************************/ + *****************************************************************************/ NM_UTILS_ENUM2STR_DEFINE_STATIC (_ethtool_cmd_to_string, guint32, NM_UTILS_ENUM2STR (ETHTOOL_GDRVINFO, "ETHTOOL_GDRVINFO"), @@ -77,6 +116,7 @@ NM_UTILS_ENUM2STR_DEFINE_STATIC (_ethtool_cmd_to_string, guint32, NM_UTILS_ENUM2STR (ETHTOOL_GSTATS, "ETHTOOL_GSTATS"), NM_UTILS_ENUM2STR (ETHTOOL_GSTRINGS, "ETHTOOL_GSTRINGS"), NM_UTILS_ENUM2STR (ETHTOOL_GWOL, "ETHTOOL_GWOL"), + NM_UTILS_ENUM2STR (ETHTOOL_SFEATURES, "ETHTOOL_SFEATURES"), NM_UTILS_ENUM2STR (ETHTOOL_SSET, "ETHTOOL_SSET"), NM_UTILS_ENUM2STR (ETHTOOL_SWOL, "ETHTOOL_SWOL"), ); @@ -87,6 +127,8 @@ _ethtool_data_to_string (gconstpointer edata, char *buf, gsize len) return _ethtool_cmd_to_string (*((guint32 *) edata), buf, len); } +/*****************************************************************************/ + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) #define ethtool_cmd_speed(pedata) ((pedata)->speed) @@ -94,117 +136,553 @@ _ethtool_data_to_string (gconstpointer edata, char *buf, gsize len) G_STMT_START { (pedata)->speed = (guint16) (speed); } G_STMT_END #endif -static gboolean -ethtool_get (int ifindex, gpointer edata) +static int +ethtool_call_handle (SocketHandle *shandle, gpointer edata) { - char ifname[IFNAMSIZ]; + struct ifreq ifr = { + .ifr_data = edata, + }; char sbuf[50]; + int errsv; + + nm_assert (shandle); + nm_assert (shandle->ifindex); + nm_assert (shandle->ifname[0]); + nm_assert (strlen (shandle->ifname) < IFNAMSIZ); + nm_assert (edata); + + memcpy (ifr.ifr_name, shandle->ifname, IFNAMSIZ); + if (ioctl (shandle->fd, SIOCETHTOOL, &ifr) < 0) { + errsv = errno; + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: failed: %s", + shandle->ifindex, + _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)), + shandle->ifname, + strerror (errsv)); + return -errsv; + } - nm_assert (ifindex > 0); + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: success", + shandle->ifindex, + _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)), + shandle->ifname); + return 0; +} - /* ethtool ioctl API uses the ifname to refer to an interface. That is racy - * as interfaces can be renamed *sigh*. - * - * Note that we anyway have to verify whether the interface exists, before - * calling ioctl for a non-existing ifname. This is to prevent autoloading - * of kernel modules *sigh*. - * Thus, as we anyway verify the existence of ifname before doing the call, - * go one step further and lookup the ifname everytime anew. - * - * This does not solve the renaming race, but it minimizes the time for - * the race to happen as much as possible. */ +static int +ethtool_call_ifindex (int ifindex, gpointer edata) +{ + nm_auto_socket_handle SocketHandle shandle = { }; + int r; + char sbuf[50]; - if (!nmp_utils_if_indextoname (ifindex, ifname)) { - nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: request fails resolving ifindex: %s", + nm_assert (edata); + + if ((r = socket_handle_init (&shandle, ifindex)) < 0) { + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", ifindex, _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)), - g_strerror (errno)); + g_strerror (-r)); + return r; + } + + return ethtool_call_handle (&shandle, edata); +} + +/*****************************************************************************/ + +static struct ethtool_gstrings * +ethtool_get_stringset (SocketHandle *shandle, int stringset_id) +{ + struct { + struct ethtool_sset_info info; + guint32 sentinel; + } sset_info = { }; + gs_free struct ethtool_gstrings *gstrings = NULL; + guint32 i, len; + + sset_info.info.cmd = ETHTOOL_GSSET_INFO; + sset_info.info.reserved = 0; + sset_info.info.sset_mask = (1ULL << stringset_id); + + if (ethtool_call_handle (shandle, &sset_info) < 0) + return NULL; + if (!sset_info.info.sset_mask) + return NULL; + + len = sset_info.info.data[0]; + + gstrings = g_malloc0 (sizeof (*gstrings) + (len * ETH_GSTRING_LEN)); + gstrings->cmd = ETHTOOL_GSTRINGS; + gstrings->string_set = stringset_id; + gstrings->len = len; + if (gstrings->len > 0) { + if (ethtool_call_handle (shandle, gstrings) < 0) + return NULL; + for (i = 0; i < gstrings->len; i++) { + /* ensure NUL terminated */ + gstrings->data[i * ETH_GSTRING_LEN + (ETH_GSTRING_LEN - 1)] = '\0'; + } + } + + return g_steal_pointer (&gstrings); +} + +static int +ethtool_gstrings_find (const struct ethtool_gstrings *gstrings, const char *needle) +{ + guint32 i; + + /* ethtool_get_stringset() always ensures NUL terminated strings at ETH_GSTRING_LEN. + * that means, we cannot possibly request longer names. */ + nm_assert (needle && strlen (needle) < ETH_GSTRING_LEN); + + for (i = 0; i < gstrings->len; i++) { + if (nm_streq ((char *) &gstrings->data[i * ETH_GSTRING_LEN], needle)) + return i; + } + return -1; +} + +static int +ethtool_get_stringset_index (SocketHandle *shandle, int stringset_id, const char *needle) +{ + gs_free struct ethtool_gstrings *gstrings = NULL; + + /* ethtool_get_stringset() always ensures NUL terminated strings at ETH_GSTRING_LEN. + * that means, we cannot possibly request longer names. */ + nm_assert (needle && strlen (needle) < ETH_GSTRING_LEN); + + gstrings = ethtool_get_stringset (shandle, stringset_id); + if (gstrings) + return ethtool_gstrings_find (gstrings, needle); + return -1; +} + +/*****************************************************************************/ + +static const NMEthtoolFeatureInfo _ethtool_feature_infos[_NM_ETHTOOL_ID_FEATURE_NUM] = { +#define ETHT_FEAT(eid, ...) \ + { \ + .ethtool_id = eid, \ + .n_kernel_names = NM_NARG (__VA_ARGS__), \ + .kernel_names = ((const char *const[]) { __VA_ARGS__ }), \ + } + + /* the order does only matter for one thing: if it happens that more than one NMEthtoolID + * reference the same kernel-name, then the one that is mentioned *later* will win in + * case these NMEthtoolIDs are set. That mostly only makes sense for ethtool-ids which + * refer to multiple features ("feature-tso"), while also having more specific ids + * ("feature-tx-tcp-segmentation"). */ + + /* names from ethtool utility, which are aliases for multiple features. */ + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_SG, "tx-scatter-gather", + "tx-scatter-gather-fraglist"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TSO, "tx-tcp-segmentation", + "tx-tcp-ecn-segmentation", + "tx-tcp-mangleid-segmentation", + "tx-tcp6-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX, "tx-checksum-ipv4", + "tx-checksum-ip-generic", + "tx-checksum-ipv6", + "tx-checksum-fcoe-crc", + "tx-checksum-sctp"), + + /* names from ethtool utility, which are aliases for one feature. */ + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_GRO, "rx-gro"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_GSO, "tx-generic-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_LRO, "rx-lro"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_NTUPLE, "rx-ntuple-filter"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX, "rx-checksum"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RXHASH, "rx-hashing"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RXVLAN, "rx-vlan-hw-parse"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TXVLAN, "tx-vlan-hw-insert"), + + /* names of features, as known by kernel. */ + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD, "esp-hw-offload"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD, "esp-tx-csum-hw-offload"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_FCOE_MTU, "fcoe-mtu"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_HIGHDMA, "highdma"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_HW_TC_OFFLOAD, "hw-tc-offload"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_L2_FWD_OFFLOAD, "l2-fwd-offload"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_LOOPBACK, "loopback"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX_ALL, "rx-all"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX_FCS, "rx-fcs"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX_GRO_HW, "rx-gro-hw"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD, "rx-udp_tunnel-port-offload"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX_VLAN_FILTER, "rx-vlan-filter"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_FILTER, "rx-vlan-stag-filter"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_HW_PARSE, "rx-vlan-stag-hw-parse"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TLS_HW_RECORD, "tls-hw-record"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TLS_HW_TX_OFFLOAD, "tls-hw-tx-offload"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_FCOE_CRC, "tx-checksum-fcoe-crc"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV4, "tx-checksum-ipv4"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV6, "tx-checksum-ipv6"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IP_GENERIC, "tx-checksum-ip-generic"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_SCTP, "tx-checksum-sctp"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_ESP_SEGMENTATION, "tx-esp-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_FCOE_SEGMENTATION, "tx-fcoe-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_GRE_CSUM_SEGMENTATION, "tx-gre-csum-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_GRE_SEGMENTATION, "tx-gre-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_GSO_PARTIAL, "tx-gso-partial"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_GSO_ROBUST, "tx-gso-robust"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_IPXIP4_SEGMENTATION, "tx-ipxip4-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_IPXIP6_SEGMENTATION, "tx-ipxip6-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_NOCACHE_COPY, "tx-nocache-copy"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER, "tx-scatter-gather"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER_FRAGLIST, "tx-scatter-gather-fraglist"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_SCTP_SEGMENTATION, "tx-sctp-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION, "tx-tcp6-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_TCP_ECN_SEGMENTATION, "tx-tcp-ecn-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_TCP_MANGLEID_SEGMENTATION, "tx-tcp-mangleid-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_TCP_SEGMENTATION, "tx-tcp-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_UDP_SEGMENTATION, "tx-udp-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION, "tx-udp_tnl-csum-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION, "tx-udp_tnl-segmentation"), + ETHT_FEAT (NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT, "tx-vlan-stag-hw-insert"), +}; + +/* the number of kernel features that we handle. It essentially is the sum of all + * kernel_names. So, all ethtool-ids that reference exactly one kernel-name + * (_NM_ETHTOOL_ID_FEATURE_NUM) + some extra, for ethtool-ids that are aliases + * for multiple kernel-names. */ +#define N_ETHTOOL_KERNEL_FEATURES (((guint) _NM_ETHTOOL_ID_FEATURE_NUM) + 8u) + +static void +_ASSERT_ethtool_feature_infos (void) +{ +#if NM_MORE_ASSERTS > 10 + guint i, k, n; + bool found[_NM_ETHTOOL_ID_FEATURE_NUM] = { }; + + G_STATIC_ASSERT_EXPR (G_N_ELEMENTS (_ethtool_feature_infos) == _NM_ETHTOOL_ID_FEATURE_NUM); + + n = 0; + for (i = 0; i < G_N_ELEMENTS (_ethtool_feature_infos); i++) { + NMEthtoolFeatureState kstate; + const NMEthtoolFeatureInfo *inf = &_ethtool_feature_infos[i]; + + g_assert (inf->ethtool_id >= _NM_ETHTOOL_ID_FEATURE_FIRST); + g_assert (inf->ethtool_id <= _NM_ETHTOOL_ID_FEATURE_LAST); + g_assert (inf->n_kernel_names > 0); + + for (k = 0; k < i; k++) + g_assert (inf->ethtool_id != _ethtool_feature_infos[k].ethtool_id); + + g_assert (!found[inf->ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST]); + found[inf->ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST] = TRUE; + + kstate.idx_kernel_name = inf->n_kernel_names - 1; + g_assert ((guint) kstate.idx_kernel_name == (guint) (inf->n_kernel_names - 1)); + + n += inf->n_kernel_names; + for (k = 0; k < inf->n_kernel_names; k++) { + g_assert (nm_utils_strv_find_first ((char **) inf->kernel_names, + k, + inf->kernel_names[k]) < 0); + } + } + + for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++) + g_assert (found[i]); + + g_assert (n == N_ETHTOOL_KERNEL_FEATURES); +#endif +} + +static NMEthtoolFeatureStates * +ethtool_get_features (SocketHandle *shandle) +{ + gs_free NMEthtoolFeatureStates *states = NULL; + gs_free struct ethtool_gstrings *ss_features = NULL; + + _ASSERT_ethtool_feature_infos (); + + ss_features = ethtool_get_stringset (shandle, ETH_SS_FEATURES); + if (!ss_features) + return NULL; + + if (ss_features->len > 0) { + gs_free struct ethtool_gfeatures *gfeatures = NULL; + guint idx; + const NMEthtoolFeatureState *states_list0 = NULL; + const NMEthtoolFeatureState *const*states_plist0 = NULL; + guint states_plist_n = 0; + + gfeatures = g_malloc0 ( sizeof (struct ethtool_gfeatures) + + (NM_DIV_ROUND_UP (ss_features->len, 32u) * sizeof(gfeatures->features[0]))); + + gfeatures->cmd = ETHTOOL_GFEATURES; + gfeatures->size = NM_DIV_ROUND_UP (ss_features->len, 32u); + if (ethtool_call_handle (shandle, gfeatures) < 0) + return NULL; + + for (idx = 0; idx < G_N_ELEMENTS (_ethtool_feature_infos); idx++) { + const NMEthtoolFeatureInfo *info = &_ethtool_feature_infos[idx]; + guint idx_kernel_name; + + for (idx_kernel_name = 0; idx_kernel_name < info->n_kernel_names; idx_kernel_name++) { + NMEthtoolFeatureState *kstate; + const char *kernel_name = info->kernel_names[idx_kernel_name]; + int i_feature; + guint i_block; + guint32 i_flag; + + i_feature = ethtool_gstrings_find (ss_features, kernel_name); + if (i_feature < 0) + continue; + + i_block = ((guint) i_feature) / 32u; + i_flag = (guint32) (1u << (((guint) i_feature) % 32u)); + + if (!states) { + states = g_malloc0 (sizeof (NMEthtoolFeatureStates) + + (N_ETHTOOL_KERNEL_FEATURES * sizeof (NMEthtoolFeatureState)) + + ((N_ETHTOOL_KERNEL_FEATURES + G_N_ELEMENTS (_ethtool_feature_infos)) * sizeof (NMEthtoolFeatureState *))); + states_list0 = &states->states_list[0]; + states_plist0 = (gpointer) &states_list0[N_ETHTOOL_KERNEL_FEATURES]; + states->n_ss_features = ss_features->len; + } + + nm_assert (states->n_states < N_ETHTOOL_KERNEL_FEATURES); + kstate = (NMEthtoolFeatureState *) &states_list0[states->n_states]; + states->n_states++; + + kstate->info = info; + kstate->idx_ss_features = i_feature; + kstate->idx_kernel_name = idx_kernel_name; + kstate->available = !!(gfeatures->features[i_block].available & i_flag); + kstate->requested = !!(gfeatures->features[i_block].requested & i_flag); + kstate->active = !!(gfeatures->features[i_block].active & i_flag); + kstate->never_changed = !!(gfeatures->features[i_block].never_changed & i_flag); + + nm_assert (states_plist_n < N_ETHTOOL_KERNEL_FEATURES + G_N_ELEMENTS (_ethtool_feature_infos)); + + if (!states->states_indexed[info->ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST]) + states->states_indexed[info->ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST] = &states_plist0[states_plist_n]; + ((const NMEthtoolFeatureState **) states_plist0)[states_plist_n] = kstate; + states_plist_n++; + } + + if (states && states->states_indexed[info->ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST]) { + nm_assert (states_plist_n < N_ETHTOOL_KERNEL_FEATURES + G_N_ELEMENTS (_ethtool_feature_infos)); + nm_assert (!states_plist0[states_plist_n]); + states_plist_n++; + } + } + } + + return g_steal_pointer (&states); +} + +NMEthtoolFeatureStates * +nmp_utils_ethtool_get_features (int ifindex) +{ + nm_auto_socket_handle SocketHandle shandle = { }; + NMEthtoolFeatureStates *features; + int r; + + g_return_val_if_fail (ifindex > 0, 0); + + if ((r = socket_handle_init (&shandle, ifindex)) < 0) { + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", + ifindex, + "get-features", + g_strerror (-r)); return FALSE; } - { - nm_auto_close int fd = -1; - struct ifreq ifr = { - .ifr_data = edata, - }; + features = ethtool_get_features (&shandle); - memcpy (ifr.ifr_name, ifname, sizeof (ifname)); + if (!features) { + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failure getting features", + ifindex, + "get-features"); + return NULL; + } - fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (fd < 0) { - nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: failed creating socket for ioctl: %s", - ifindex, - _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)), - ifname, - g_strerror (errno)); - return FALSE; + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: retrieved kernel features", + ifindex, + "get-features"); + return features; +} + +static const char * +_ethtool_feature_state_to_string (char *buf, gsize buf_size, const NMEthtoolFeatureState *s, const char *prefix) +{ + int l; + + l = g_snprintf (buf, buf_size, + "%s %s%s", + prefix ?: "", + ONOFF (s->active), + (!s->available || s->never_changed) + ? ", [fixed]" + : ((s->requested != s->active) + ? (s->requested ? ", [requested on]" : ", [requested off]") + : "")); + nm_assert (l < buf_size); + return buf; +} + +gboolean +nmp_utils_ethtool_set_features (int ifindex, + const NMEthtoolFeatureStates *features, + const NMTernary *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */, + gboolean do_set /* or reset */) +{ + nm_auto_socket_handle SocketHandle shandle = { }; + gs_free struct ethtool_sfeatures *sfeatures = NULL; + int r; + guint i, j; + struct { + const NMEthtoolFeatureState *f_state; + NMTernary requested; + } set_states[N_ETHTOOL_KERNEL_FEATURES]; + guint set_states_n = 0; + gboolean success = TRUE; + + g_return_val_if_fail (ifindex > 0, 0); + g_return_val_if_fail (features, 0); + g_return_val_if_fail (requested, 0); + + nm_assert (features->n_states <= N_ETHTOOL_KERNEL_FEATURES); + + for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++) { + const NMEthtoolFeatureState *const*states_indexed; + + if (requested[i] == NM_TERNARY_DEFAULT) + continue; + + if (!(states_indexed = features->states_indexed[i])) { + if (do_set) { + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: set feature %s: skip (not found)", + ifindex, + "set-features", + nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname); + success = FALSE; + } + continue; } - if (ioctl (fd, SIOCETHTOOL, &ifr) < 0) { - nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: failed: %s", + for (j = 0; states_indexed[j]; j++) { + const NMEthtoolFeatureState *s = states_indexed[j]; + char sbuf[255]; + + if (set_states_n >= G_N_ELEMENTS (set_states)) + g_return_val_if_reached (FALSE); + + if (s->never_changed) { + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: %s feature %s (%s): %s, %s (skip feature marked as never changed)", + ifindex, + "set-features", + do_set ? "set" : "reset", + nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname, + s->info->kernel_names[s->idx_kernel_name], + ONOFF (do_set ? requested[i] == NM_TERNARY_TRUE : s->active), + _ethtool_feature_state_to_string (sbuf, sizeof (sbuf), s, do_set ? " currently:" : " before:")); + continue; + } + + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: %s feature %s (%s): %s, %s", ifindex, - _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)), - ifname, - strerror (errno)); - return FALSE; + "set-features", + do_set ? "set" : "reset", + nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname, + s->info->kernel_names[s->idx_kernel_name], + ONOFF (do_set ? requested[i] == NM_TERNARY_TRUE : s->active), + _ethtool_feature_state_to_string (sbuf, sizeof (sbuf), s, do_set ? " currently:" : " before:")); + + if ( do_set + && (!s->available || s->never_changed) + && (s->active != (requested[i] == NM_TERNARY_TRUE))) { + /* we request to change a flag which kernel reported as fixed. + * While the ethtool operation will silently succeed, mark the request + * as failure. */ + success = FALSE; + } + + set_states[set_states_n].f_state = s; + set_states[set_states_n].requested = requested[i]; + set_states_n++; } + } - nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s, %s: success", + if (set_states_n == 0) { + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: no feature requested", ifindex, - _ethtool_data_to_string (edata, sbuf, sizeof (sbuf)), - ifname); + "set-features"); return TRUE; } -} -static int -ethtool_get_stringset_index (int ifindex, int stringset_id, const char *string) -{ - gs_free struct ethtool_sset_info *info = NULL; - gs_free struct ethtool_gstrings *strings = NULL; - guint32 len, i; + if ((r = socket_handle_init (&shandle, ifindex)) < 0) { + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", + ifindex, + "set-features", + g_strerror (-r)); + return FALSE; + } - g_return_val_if_fail (ifindex > 0, -1); + sfeatures = g_malloc0 (sizeof (struct ethtool_sfeatures) + + (NM_DIV_ROUND_UP (features->n_ss_features, 32U) * sizeof(sfeatures->features[0]))); + sfeatures->cmd = ETHTOOL_SFEATURES; + sfeatures->size = NM_DIV_ROUND_UP (features->n_ss_features, 32U); - info = g_malloc0 (sizeof (*info) + sizeof (guint32)); - info->cmd = ETHTOOL_GSSET_INFO; - info->reserved = 0; - info->sset_mask = 1ULL << stringset_id; + for (i = 0; i < set_states_n; i++) { + const NMEthtoolFeatureState *s = set_states[i].f_state; + guint i_block; + guint32 i_flag; + gboolean is_requested; - if (!ethtool_get (ifindex, info)) - return -1; - if (!info->sset_mask) - return -1; + i_block = s->idx_ss_features / 32u; + i_flag = (guint32) (1u << (s->idx_ss_features % 32u)); - len = info->data[0]; + sfeatures->features[i_block].valid |= i_flag; - strings = g_malloc0 (sizeof (*strings) + len * ETH_GSTRING_LEN); - strings->cmd = ETHTOOL_GSTRINGS; - strings->string_set = stringset_id; - strings->len = len; - if (!ethtool_get (ifindex, strings)) - return -1; + if (do_set) + is_requested = (set_states[i].requested == NM_TERNARY_TRUE); + else + is_requested = s->active; - for (i = 0; i < len; i++) { - if (!strcmp ((char *) &strings->data[i * ETH_GSTRING_LEN], string)) - return i; + if (is_requested) + sfeatures->features[i_block].requested |= i_flag; + else + sfeatures->features[i_block].requested &= ~i_flag; } - return -1; + if ((r = ethtool_call_handle (&shandle, sfeatures)) < 0) { + success = FALSE; + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failure setting features (%s)", + ifindex, + "set-features", + g_strerror (-r)); + return FALSE; + } + + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: %s", + ifindex, + "set-features", + success + ? "successfully setting features" + : "at least some of the features were not successfuly set"); + return success; } +/*****************************************************************************/ + gboolean nmp_utils_ethtool_get_driver_info (int ifindex, NMPUtilsEthtoolDriverInfo *data) { struct ethtool_drvinfo *drvinfo; - G_STATIC_ASSERT (sizeof (*data) == sizeof (*drvinfo)); - G_STATIC_ASSERT (offsetof (NMPUtilsEthtoolDriverInfo, driver) == offsetof (struct ethtool_drvinfo, driver)); - G_STATIC_ASSERT (offsetof (NMPUtilsEthtoolDriverInfo, version) == offsetof (struct ethtool_drvinfo, version)); - G_STATIC_ASSERT (offsetof (NMPUtilsEthtoolDriverInfo, fw_version) == offsetof (struct ethtool_drvinfo, fw_version)); - G_STATIC_ASSERT (sizeof (data->driver) == sizeof (drvinfo->driver)); - G_STATIC_ASSERT (sizeof (data->version) == sizeof (drvinfo->version)); - G_STATIC_ASSERT (sizeof (data->fw_version) == sizeof (drvinfo->fw_version)); + + G_STATIC_ASSERT_EXPR (sizeof (*data) == sizeof (*drvinfo)); + G_STATIC_ASSERT_EXPR (offsetof (NMPUtilsEthtoolDriverInfo, driver) == offsetof (struct ethtool_drvinfo, driver)); + G_STATIC_ASSERT_EXPR (offsetof (NMPUtilsEthtoolDriverInfo, version) == offsetof (struct ethtool_drvinfo, version)); + G_STATIC_ASSERT_EXPR (offsetof (NMPUtilsEthtoolDriverInfo, fw_version) == offsetof (struct ethtool_drvinfo, fw_version)); + G_STATIC_ASSERT_EXPR (sizeof (data->driver) == sizeof (drvinfo->driver)); + G_STATIC_ASSERT_EXPR (sizeof (data->version) == sizeof (drvinfo->version)); + G_STATIC_ASSERT_EXPR (sizeof (data->fw_version) == sizeof (drvinfo->fw_version)); g_return_val_if_fail (ifindex > 0, FALSE); g_return_val_if_fail (data, FALSE); @@ -213,7 +691,7 @@ nmp_utils_ethtool_get_driver_info (int ifindex, memset (drvinfo, 0, sizeof (*drvinfo)); drvinfo->cmd = ETHTOOL_GDRVINFO; - return ethtool_get (ifindex, drvinfo); + return ethtool_call_ifindex (ifindex, drvinfo) >= 0; } gboolean @@ -233,7 +711,7 @@ nmp_utils_ethtool_get_permanent_address (int ifindex, edata.e.cmd = ETHTOOL_GPERMADDR; edata.e.size = NM_UTILS_HWADDR_LEN_MAX; - if (!ethtool_get (ifindex, &edata.e)) + if (ethtool_call_ifindex (ifindex, &edata.e) < 0) return FALSE; if (edata.e.size > NM_UTILS_HWADDR_LEN_MAX) @@ -252,8 +730,8 @@ nmp_utils_ethtool_get_permanent_address (int ifindex, } return FALSE; } -not_all_0or1: +not_all_0or1: memcpy (buf, edata.e.data, edata.e.size); *length = edata.e.size; return TRUE; @@ -270,20 +748,30 @@ nmp_utils_ethtool_supports_carrier_detect (int ifindex) * assume the device supports carrier-detect, otherwise we assume it * doesn't. */ - return ethtool_get (ifindex, &edata); + return ethtool_call_ifindex (ifindex, &edata) >= 0; } gboolean nmp_utils_ethtool_supports_vlans (int ifindex) { + nm_auto_socket_handle SocketHandle shandle = { }; + int r; gs_free struct ethtool_gfeatures *features = NULL; int idx, block, bit, size; g_return_val_if_fail (ifindex > 0, FALSE); - idx = ethtool_get_stringset_index (ifindex, ETH_SS_FEATURES, "vlan-challenged"); - if (idx == -1) { - nm_log_dbg (LOGD_PLATFORM, "ethtool: vlan-challenged ethtool feature does not exist for %d?", ifindex); + if ((r = socket_handle_init (&shandle, ifindex)) < 0) { + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", + ifindex, + "support-vlans", + g_strerror (-r)); + return FALSE; + } + + idx = ethtool_get_stringset_index (&shandle, ETH_SS_FEATURES, "vlan-challenged"); + if (idx < 0) { + nm_log_dbg (LOGD_PLATFORM, "ethtool[%d]: vlan-challenged ethtool feature does not exist?", ifindex); return FALSE; } @@ -295,7 +783,7 @@ nmp_utils_ethtool_supports_vlans (int ifindex) features->cmd = ETHTOOL_GFEATURES; features->size = size; - if (!ethtool_get (ifindex, features)) + if (ethtool_call_handle (&shandle, features) < 0) return FALSE; return !(features->features[block].active & (1 << bit)); @@ -304,21 +792,32 @@ nmp_utils_ethtool_supports_vlans (int ifindex) int nmp_utils_ethtool_get_peer_ifindex (int ifindex) { + nm_auto_socket_handle SocketHandle shandle = { }; + int r; + gs_free struct ethtool_stats *stats = NULL; int peer_ifindex_stat; g_return_val_if_fail (ifindex > 0, 0); - peer_ifindex_stat = ethtool_get_stringset_index (ifindex, ETH_SS_STATS, "peer_ifindex"); - if (peer_ifindex_stat == -1) { - nm_log_dbg (LOGD_PLATFORM, "ethtool: peer_ifindex stat for %d does not exist?", ifindex); + if ((r = socket_handle_init (&shandle, ifindex)) < 0) { + nm_log_trace (LOGD_PLATFORM, "ethtool[%d]: %s: failed creating ethtool socket: %s", + ifindex, + "get-peer-ifindex", + g_strerror (-r)); + return FALSE; + } + + peer_ifindex_stat = ethtool_get_stringset_index (&shandle, ETH_SS_STATS, "peer_ifindex"); + if (peer_ifindex_stat < 0) { + nm_log_dbg (LOGD_PLATFORM, "ethtool[%d]: peer_ifindex stat does not exist?", ifindex); return FALSE; } stats = g_malloc0 (sizeof (*stats) + (peer_ifindex_stat + 1) * sizeof (guint64)); stats->cmd = ETHTOOL_GSTATS; stats->n_stats = peer_ifindex_stat + 1; - if (!ethtool_get (ifindex, stats)) + if (ethtool_call_ifindex (ifindex, stats) < 0) return 0; return stats->data[peer_ifindex_stat]; @@ -333,7 +832,7 @@ nmp_utils_ethtool_get_wake_on_lan (int ifindex) memset (&wol, 0, sizeof (wol)); wol.cmd = ETHTOOL_GWOL; - if (!ethtool_get (ifindex, &wol)) + if (ethtool_call_ifindex (ifindex, &wol) < 0) return FALSE; return wol.wolopts != 0; @@ -351,7 +850,7 @@ nmp_utils_ethtool_get_link_settings (int ifindex, g_return_val_if_fail (ifindex > 0, FALSE); - if (!ethtool_get (ifindex, &edata)) + if (ethtool_call_ifindex (ifindex, &edata) < 0) return FALSE; if (out_autoneg) @@ -433,9 +932,13 @@ nmp_utils_ethtool_set_link_settings (int ifindex, || (!speed && duplex == NM_PLATFORM_LINK_DUPLEX_UNKNOWN), FALSE); /* retrieve first current settings */ - if (!ethtool_get (ifindex, &edata)) + if (ethtool_call_ifindex (ifindex, &edata) < 0) return FALSE; + /* FIXME: try first new ETHTOOL_GLINKSETTINGS/SLINKSETTINGS API + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3f1ac7a700d039c61d8d8b99f28d605d489a60cf + */ + /* then change the needed ones */ edata.cmd = ETHTOOL_SSET; if (autoneg) { @@ -485,7 +988,7 @@ nmp_utils_ethtool_set_link_settings (int ifindex, } } - return ethtool_get (ifindex, &edata); + return ethtool_call_ifindex (ifindex, &edata) >= 0; } gboolean @@ -500,8 +1003,8 @@ nmp_utils_ethtool_set_wake_on_lan (int ifindex, if (wol == NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE) return TRUE; - nm_log_dbg (LOGD_PLATFORM, "setting Wake-on-LAN options 0x%x, password '%s'", - (unsigned) wol, wol_password); + nm_log_dbg (LOGD_PLATFORM, "ethtool[%d]: setting Wake-on-LAN options 0x%x, password '%s'", + ifindex, (unsigned) wol, wol_password); wol_info.cmd = ETHTOOL_SWOL; wol_info.wolopts = 0; @@ -521,45 +1024,41 @@ nmp_utils_ethtool_set_wake_on_lan (int ifindex, if (wol_password) { if (!nm_utils_hwaddr_aton (wol_password, wol_info.sopass, ETH_ALEN)) { - nm_log_dbg (LOGD_PLATFORM, "couldn't parse Wake-on-LAN password '%s'", wol_password); + nm_log_dbg (LOGD_PLATFORM, "ethtool[%d]: couldn't parse Wake-on-LAN password '%s'", ifindex, wol_password); return FALSE; } wol_info.wolopts |= WAKE_MAGICSECURE; } - return ethtool_get (ifindex, &wol_info); + return ethtool_call_ifindex (ifindex, &wol_info) >= 0; } -/****************************************************************** +/****************************************************************************** * mii - ******************************************************************/ + *****************************************************************************/ gboolean nmp_utils_mii_supports_carrier_detect (int ifindex) { - char ifname[IFNAMSIZ]; - nm_auto_close int fd = -1; + nm_auto_socket_handle SocketHandle shandle = { }; + int r; struct ifreq ifr; struct mii_ioctl_data *mii; g_return_val_if_fail (ifindex > 0, FALSE); - if (!nmp_utils_if_indextoname (ifindex, ifname)) { - nm_log_trace (LOGD_PLATFORM, "mii[%d]: carrier-detect no: request fails resolving ifindex: %s", ifindex, g_strerror (errno)); - return FALSE; - } - - fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (fd < 0) { - nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: couldn't open control socket: %s", ifindex, ifname, g_strerror (errno)); + if ((r = socket_handle_init (&shandle, ifindex)) < 0) { + nm_log_trace (LOGD_PLATFORM, "mii[%d]: carrier-detect no: failed creating ethtool socket: %s", + ifindex, + g_strerror (-r)); return FALSE; } memset (&ifr, 0, sizeof (struct ifreq)); - memcpy (ifr.ifr_name, ifname, IFNAMSIZ); + memcpy (ifr.ifr_name, shandle.ifname, IFNAMSIZ); - if (ioctl (fd, SIOCGMIIPHY, &ifr) < 0) { - nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIPHY failed: %s", ifindex, ifname, strerror (errno)); + if (ioctl (shandle.fd, SIOCGMIIPHY, &ifr) < 0) { + nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIPHY failed: %s", ifindex, shandle.ifname, strerror (errno)); return FALSE; } @@ -567,18 +1066,18 @@ nmp_utils_mii_supports_carrier_detect (int ifindex) mii = (struct mii_ioctl_data *) &ifr.ifr_ifru; mii->reg_num = MII_BMSR; - if (ioctl (fd, SIOCGMIIREG, &ifr) != 0) { - nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIREG failed: %s", ifindex, ifname, strerror (errno)); + if (ioctl (shandle.fd, SIOCGMIIREG, &ifr) != 0) { + nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect no: SIOCGMIIREG failed: %s", ifindex, shandle.ifname, strerror (errno)); return FALSE; } - nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect yes: SIOCGMIIREG result 0x%X", ifindex, ifname, mii->val_out); + nm_log_trace (LOGD_PLATFORM, "mii[%d,%s]: carrier-detect yes: SIOCGMIIREG result 0x%X", ifindex, shandle.ifname, mii->val_out); return TRUE; } -/****************************************************************** +/****************************************************************************** * udev - ******************************************************************/ + *****************************************************************************/ const char * nmp_utils_udev_get_driver (struct udev_device *udevice) diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h index 97f5630a..bad77aee 100644 --- a/src/platform/nm-platform-utils.h +++ b/src/platform/nm-platform-utils.h @@ -23,6 +23,9 @@ #include "nm-platform.h" #include "nm-setting-wired.h" +#include "nm-ethtool-utils.h" + +/*****************************************************************************/ const char *nmp_utils_ethtool_get_driver (int ifindex); gboolean nmp_utils_ethtool_supports_carrier_detect (int ifindex); @@ -35,6 +38,10 @@ gboolean nmp_utils_ethtool_set_wake_on_lan (int ifindex, NMSettingWiredWakeOnLan gboolean nmp_utils_ethtool_get_link_settings (int ifindex, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex); gboolean nmp_utils_ethtool_set_link_settings (int ifindex, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex); +gboolean nmp_utils_ethtool_get_permanent_address (int ifindex, + guint8 *buf, + size_t *length); + typedef struct { /* We don't want to include <linux/ethtool.h> in header files, * thus create a ABI compatible version of struct ethtool_drvinfo.*/ @@ -55,9 +62,52 @@ typedef struct { gboolean nmp_utils_ethtool_get_driver_info (int ifindex, NMPUtilsEthtoolDriverInfo *data); -gboolean nmp_utils_ethtool_get_permanent_address (int ifindex, - guint8 *buf, - size_t *length); +typedef struct { + NMEthtoolID ethtool_id; + + guint8 n_kernel_names; + + /* one NMEthtoolID refers to one or more kernel_names. The reason for supporting this complexity + * (where one NMSettingEthtool option refers to multiple kernel features) is to follow what + * ethtool does, where "tx" is an alias for multiple features. */ + const char *const*kernel_names; +} NMEthtoolFeatureInfo; + +typedef struct { + const NMEthtoolFeatureInfo *info; + + guint idx_ss_features; + + /* one NMEthtoolFeatureInfo references one or more kernel_names. This is the index + * of the matching info->kernel_names */ + guint8 idx_kernel_name; + + bool available:1; + bool requested:1; + bool active:1; + bool never_changed:1; +} NMEthtoolFeatureState; + +struct _NMEthtoolFeatureStates { + guint n_states; + + guint n_ss_features; + + /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */ + const NMEthtoolFeatureState *const*states_indexed[_NM_ETHTOOL_ID_FEATURE_NUM]; + + /* the same content, here as a list of n_states entries. */ + const NMEthtoolFeatureState states_list[]; +}; + +NMEthtoolFeatureStates *nmp_utils_ethtool_get_features (int ifindex); + +gboolean nmp_utils_ethtool_set_features (int ifindex, + const NMEthtoolFeatureStates *features, + const NMTernary *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */, + gboolean do_set /* or reset */); + +/*****************************************************************************/ gboolean nmp_utils_mii_supports_carrier_detect (int ifindex); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index f75019e8..7ddcf41a 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.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) 2012 - 2017 Red Hat, Inc. + * Copyright (C) 2012 - 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -27,6 +27,8 @@ #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> +#include <sys/socket.h> +#include <netdb.h> #include <string.h> #include <linux/ip.h> #include <linux/if_tun.h> @@ -74,8 +76,6 @@ G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OF } \ } G_STMT_END -#define LOG_FMT_IP_TUNNEL "adding %s '%s' parent %u local %s remote %s" - /*****************************************************************************/ static guint signals[_NM_PLATFORM_SIGNAL_ID_LAST] = { 0 }; @@ -807,6 +807,7 @@ _nm_platform_link_get_by_address_match_link (const NMPObject *obj, struct _nm_pl **/ const NMPlatformLink * nm_platform_link_get_by_address (NMPlatform *self, + NMLinkType link_type, gconstpointer address, size_t length) { @@ -827,7 +828,7 @@ nm_platform_link_get_by_address (NMPlatform *self, g_return_val_if_reached (NULL); obj = nmp_cache_lookup_link_full (nm_platform_get_cache (self), - 0, NULL, TRUE, NM_LINK_TYPE_NONE, + 0, NULL, TRUE, link_type, (NMPObjectMatchFn) _nm_platform_link_get_by_address_match_link, &d); return NMP_OBJECT_CAST_LINK (obj); } @@ -901,7 +902,7 @@ nm_platform_link_add (NMPlatform *self, if (plerr != NM_PLATFORM_ERROR_SUCCESS) return plerr; - _LOGD ("link: adding link '%s' of type '%s' (%d)" + _LOGD ("link: adding link '%s': %s (%d)" "%s%s" /* address */ "%s%s" /* veth peer */ "", @@ -985,7 +986,7 @@ nm_platform_link_set_netns (NMPlatform *self, int ifindex, int netns_fd) if (!pllink) return FALSE; - _LOGD ("link: ifindex %d changing network namespace to %d", ifindex, netns_fd); + _LOGD ("link: move link %d to network namespace with fd %d", ifindex, netns_fd); return klass->link_set_netns (self, ifindex, netns_fd); } @@ -1354,15 +1355,18 @@ nm_platform_link_set_user_ipv6ll_enabled (NMPlatform *self, int ifindex, gboolea NMPlatformError nm_platform_link_set_address (NMPlatform *self, int ifindex, gconstpointer address, size_t length) { + gs_free char *mac = NULL; + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (ifindex > 0, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (address, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (length > 0, NM_PLATFORM_ERROR_BUG); - _LOGD ("link: setting %s (%d) hardware address", + _LOGD ("link: setting %s (%d) hardware address to %s", nm_strquote_a (20, nm_platform_link_get_name (self, ifindex)), - ifindex); + ifindex, + (mac = nm_utils_hwaddr_ntoa (address, length))); return klass->link_set_address (self, ifindex, address, length); } @@ -1459,18 +1463,52 @@ nm_platform_link_supports_sriov (NMPlatform *self, int ifindex) return klass->link_supports_sriov (self, ifindex); } +/** + * nm_platform_link_set_sriov_params: + * @self: platform instance + * @ifindex: the index of the interface to change + * @num_vfs: the number of VFs to create + * @autoprobe: -1 to keep the current autoprobe-drivers value, + * or {0,1} to set a new value + */ gboolean -nm_platform_link_set_sriov_num_vfs (NMPlatform *self, int ifindex, guint num_vfs) +nm_platform_link_set_sriov_params (NMPlatform *self, + int ifindex, + guint num_vfs, + int autoprobe) { _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (NM_IN_SET (autoprobe, -1, 0, 1), FALSE); - _LOGD ("link: setting %u VFs for %s (%d)", + _LOGD ("link: setting %u total VFs and autoprobe %d for %s (%d)", num_vfs, + autoprobe, nm_strquote_a (25, nm_platform_link_get_name (self, ifindex)), ifindex); - return klass->link_set_sriov_num_vfs (self, ifindex, num_vfs); + return klass->link_set_sriov_params (self, ifindex, num_vfs, autoprobe); +} + +gboolean +nm_platform_link_set_sriov_vfs (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs) +{ + guint i; + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (ifindex > 0, FALSE); + + _LOGD ("link: setting VFs for \"%s\" (%d):", + nm_platform_link_get_name (self, ifindex), + ifindex); + + for (i = 0; vfs[i]; i++) { + const NMPlatformVF *vf = vfs[i]; + + _LOGD ("link: VF %s", nm_platform_vf_to_string (vf, NULL, 0)); + } + + return klass->link_set_sriov_vfs (self, ifindex, vfs); } /** @@ -1852,6 +1890,12 @@ nm_platform_link_get_lnk_gre (NMPlatform *self, int ifindex, const NMPlatformLin return _link_get_lnk (self, ifindex, NM_LINK_TYPE_GRE, out_link); } +const NMPlatformLnkGre * +nm_platform_link_get_lnk_gretap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_GRETAP, out_link); +} + const NMPlatformLnkInfiniband * nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -1864,6 +1908,18 @@ nm_platform_link_get_lnk_ip6tnl (NMPlatform *self, int ifindex, const NMPlatform return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IP6TNL, out_link); } +const NMPlatformLnkIp6Tnl * +nm_platform_link_get_lnk_ip6gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IP6GRE, out_link); +} + +const NMPlatformLnkIp6Tnl * +nm_platform_link_get_lnk_ip6gretap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IP6GRETAP, out_link); +} + const NMPlatformLnkIpIp * nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -1912,6 +1968,12 @@ nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformL return _link_get_lnk (self, ifindex, NM_LINK_TYPE_VXLAN, out_link); } +const NMPlatformLnkWireGuard * +nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_WIREGUARD, out_link); +} + /*****************************************************************************/ /** @@ -1996,8 +2058,9 @@ nm_platform_link_vlan_add (NMPlatform *self, if (plerr != NM_PLATFORM_ERROR_SUCCESS) return plerr; - _LOGD ("link: adding vlan '%s' parent %d vlanid %d vlanflags %x", + _LOGD ("link: adding link '%s': vlan parent %d vlanid %d vlanflags %x", name, parent, vlanid, vlanflags); + if (!klass->vlan_add (self, name, parent, vlanid, vlanflags, out_link)) return NM_PLATFORM_ERROR_UNSPECIFIED; return NM_PLATFORM_ERROR_SUCCESS; @@ -2028,8 +2091,9 @@ nm_platform_link_vxlan_add (NMPlatform *self, if (plerr != NM_PLATFORM_ERROR_SUCCESS) return plerr; - _LOGD ("link: adding vxlan '%s' parent %d id %d", - name, props->parent_ifindex, props->id); + _LOGD ("link: adding link '%s': %s", + name, nm_platform_lnk_vxlan_to_string (props, NULL, 0)); + if (!klass->link_vxlan_add (self, name, props, out_link)) return NM_PLATFORM_ERROR_UNSPECIFIED; return NM_PLATFORM_ERROR_SUCCESS; @@ -2080,13 +2144,78 @@ nm_platform_link_tun_add (NMPlatform *self, if (plerr != NM_PLATFORM_ERROR_SUCCESS) return plerr; - _LOGD ("link: adding tun '%s' %s", + _LOGD ("link: adding link '%s': %s", name, nm_platform_lnk_tun_to_string (props, b, sizeof (b))); + if (!klass->link_tun_add (self, name, props, out_link, out_fd)) return NM_PLATFORM_ERROR_UNSPECIFIED; return NM_PLATFORM_ERROR_SUCCESS; } +/** + * nm_platform_6lowpan_add: + * @self: platform instance + * @parent: parent link + * @name: name of the new interface + * @out_link: on success, the link object + * + * Create a 6LoWPAN interface. + */ +NMPlatformError +nm_platform_link_6lowpan_add (NMPlatform *self, + const char *name, + int parent, + const NMPlatformLink **out_link) +{ + NMPlatformError plerr; + + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + + plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_6LOWPAN, out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; + + _LOGD ("adding link '%s': 6lowpan parent %u", name, parent); + + if (!klass->link_6lowpan_add (self, name, parent, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; +} + +gboolean +nm_platform_link_6lowpan_get_properties (NMPlatform *self, int ifindex, int *out_parent) +{ + const NMPlatformLink *plink; + _CHECK_SELF (self, klass, FALSE); + + plink = nm_platform_link_get (self, ifindex); + + if (!plink) + return FALSE; + if (plink->type != NM_LINK_TYPE_6LOWPAN) + return FALSE; + + if (plink->parent != 0) { + NM_SET_OUT (out_parent, plink->parent); + return TRUE; + } + + /* As of 4.16 kernel does not expose the peer_ifindex as IFA_LINK. + * Find the WPAN device with the same MAC address. */ + if (out_parent) { + const NMPlatformLink *parent_plink; + + parent_plink = nm_platform_link_get_by_address (self, NM_LINK_TYPE_WPAN, + plink->addr.data, + plink->addr.len); + NM_SET_OUT (out_parent, parent_plink ? parent_plink->ifindex : -1); + } + + return TRUE; +} + /*****************************************************************************/ static gboolean @@ -2310,23 +2439,18 @@ nm_platform_link_gre_add (NMPlatform *self, const NMPlatformLink **out_link) { NMPlatformError plerr; - char buffer[INET_ADDRSTRLEN]; _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); - plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_GRE, out_link); + plerr = _link_add_check_existing (self, name, props->is_tap ? NM_LINK_TYPE_GRETAP : NM_LINK_TYPE_GRE, out_link); if (plerr != NM_PLATFORM_ERROR_SUCCESS) return plerr; - _LOGD (LOG_FMT_IP_TUNNEL, - "gre", - name, - props->parent_ifindex, - nm_utils_inet4_ntop (props->local, NULL), - nm_utils_inet4_ntop (props->remote, buffer)); + _LOGD ("adding link '%s': %s", + name, nm_platform_lnk_gre_to_string (props, NULL, 0)); if (!klass->link_gre_add (self, name, props, out_link)) return NM_PLATFORM_ERROR_UNSPECIFIED; @@ -2372,6 +2496,9 @@ _infiniband_add_add_or_delete (NMPlatform *self, if (!klass->infiniband_partition_add (self, parent, p_key, out_link)) return NM_PLATFORM_ERROR_UNSPECIFIED; } else { + _LOGD ("link: deleting infiniband partition %s for parent '%s' (%d), key %d", + name, parent_link->name, parent, p_key); + if (!klass->infiniband_partition_delete (self, parent, p_key)) return NM_PLATFORM_ERROR_UNSPECIFIED; } @@ -2472,23 +2599,19 @@ nm_platform_link_ip6tnl_add (NMPlatform *self, const NMPlatformLink **out_link) { NMPlatformError plerr; - char buffer[INET6_ADDRSTRLEN]; _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (!props->is_gre, NM_PLATFORM_ERROR_BUG); plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_IP6TNL, out_link); if (plerr != NM_PLATFORM_ERROR_SUCCESS) return plerr; - _LOGD (LOG_FMT_IP_TUNNEL, - "ip6tnl", - name, - props->parent_ifindex, - nm_utils_inet6_ntop (&props->local, NULL), - nm_utils_inet6_ntop (&props->remote, buffer)); + _LOGD ("adding link '%s': %s", + name, nm_platform_lnk_ip6tnl_to_string (props, NULL, 0)); if (!klass->link_ip6tnl_add (self, name, props, out_link)) return NM_PLATFORM_ERROR_UNSPECIFIED; @@ -2496,6 +2619,46 @@ nm_platform_link_ip6tnl_add (NMPlatform *self, } /** + * nm_platform_ip6gre_add: + * @self: platform instance + * @name: name of the new interface + * @props: interface properties + * @out_link: on success, the link object + * + * Create an IPv6 GRE/GRETAP tunnel. + */ +NMPlatformError +nm_platform_link_ip6gre_add (NMPlatform *self, + const char *name, + const NMPlatformLnkIp6Tnl *props, + const NMPlatformLink **out_link) +{ + NMPlatformError plerr; + + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (props->is_gre, NM_PLATFORM_ERROR_BUG); + + plerr = _link_add_check_existing (self, + name, + props->is_tap + ? NM_LINK_TYPE_IP6GRETAP + : NM_LINK_TYPE_IP6GRE, + out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; + + _LOGD ("adding link '%s': %s", + name, nm_platform_lnk_ip6tnl_to_string (props, NULL, 0)); + + if (!klass->link_ip6gre_add (self, name, props, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; +} + +/** * nm_platform_ipip_add: * @self: platform instance * @name: name of the new interface @@ -2511,7 +2674,6 @@ nm_platform_link_ipip_add (NMPlatform *self, const NMPlatformLink **out_link) { NMPlatformError plerr; - char buffer[INET_ADDRSTRLEN]; _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); @@ -2522,12 +2684,8 @@ nm_platform_link_ipip_add (NMPlatform *self, if (plerr != NM_PLATFORM_ERROR_SUCCESS) return plerr; - _LOGD (LOG_FMT_IP_TUNNEL, - "ipip", - name, - props->parent_ifindex, - nm_utils_inet4_ntop (props->local, NULL), - nm_utils_inet4_ntop (props->remote, buffer)); + _LOGD ("adding link '%s': %s", + name, nm_platform_lnk_ipip_to_string (props, NULL, 0)); if (!klass->link_ipip_add (self, name, props, out_link)) return NM_PLATFORM_ERROR_UNSPECIFIED; @@ -2538,6 +2696,7 @@ nm_platform_link_ipip_add (NMPlatform *self, * nm_platform_macsec_add: * @self: platform instance * @name: name of the new interface + * @parent: parent link * @props: interface properties * @out_link: on success, the link object * @@ -2561,10 +2720,8 @@ nm_platform_link_macsec_add (NMPlatform *self, if (plerr != NM_PLATFORM_ERROR_SUCCESS) return plerr; - _LOGD ("adding macsec '%s' parent %u sci %llx", - name, - parent, - (unsigned long long) props->sci); + _LOGD ("adding link '%s': %s", + name, nm_platform_lnk_macsec_to_string (props, NULL, 0)); if (!klass->link_macsec_add (self, name, parent, props, out_link)) return NM_PLATFORM_ERROR_UNSPECIFIED; @@ -2601,11 +2758,8 @@ nm_platform_link_macvlan_add (NMPlatform *self, if (plerr != NM_PLATFORM_ERROR_SUCCESS) return plerr; - _LOGD ("adding %s '%s' parent %u mode %u", - props->tap ? "macvtap" : "macvlan", - name, - parent, - props->mode); + _LOGD ("adding link '%s': %s", + name, nm_platform_lnk_macvlan_to_string (props, NULL, 0)); if (!klass->link_macvlan_add (self, name, parent, props, out_link)) return NM_PLATFORM_ERROR_UNSPECIFIED; @@ -2628,7 +2782,6 @@ nm_platform_link_sit_add (NMPlatform *self, const NMPlatformLink **out_link) { NMPlatformError plerr; - char buffer[INET_ADDRSTRLEN]; _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); @@ -2639,12 +2792,8 @@ nm_platform_link_sit_add (NMPlatform *self, if (plerr != NM_PLATFORM_ERROR_SUCCESS) return plerr; - _LOGD (LOG_FMT_IP_TUNNEL, - "sit", - name, - props->parent_ifindex, - nm_utils_inet4_ntop (props->local, NULL), - nm_utils_inet4_ntop (props->remote, buffer)); + _LOGD ("adding link '%s': %s", + name, nm_platform_lnk_sit_to_string (props, NULL, 0)); if (!klass->link_sit_add (self, name, props, out_link)) return NM_PLATFORM_ERROR_UNSPECIFIED; @@ -2888,6 +3037,16 @@ nm_platform_wifi_indicate_addressing_running (NMPlatform *self, int ifindex, gbo klass->wifi_indicate_addressing_running (self, ifindex, running); } +NMSettingWirelessWakeOnWLan +nm_platform_wifi_get_wake_on_wlan (NMPlatform *self, int ifindex) +{ + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (ifindex > 0, FALSE); + + return klass->wifi_get_wake_on_wlan (self, ifindex); +} + gboolean nm_platform_wifi_set_wake_on_wlan (NMPlatform *self, int ifindex, NMSettingWirelessWakeOnWLan wowl) { @@ -2929,6 +3088,46 @@ nm_platform_mesh_set_ssid (NMPlatform *self, int ifindex, const guint8 *ssid, gs return klass->mesh_set_ssid (self, ifindex, ssid, len); } +guint16 +nm_platform_wpan_get_pan_id (NMPlatform *self, int ifindex) +{ + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (ifindex > 0, FALSE); + + return klass->wpan_get_pan_id (self, ifindex); +} + +gboolean +nm_platform_wpan_set_pan_id (NMPlatform *self, int ifindex, guint16 pan_id) +{ + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (ifindex > 0, FALSE); + + return klass->wpan_set_pan_id (self, ifindex, pan_id); +} + +guint16 +nm_platform_wpan_get_short_addr (NMPlatform *self, int ifindex) +{ + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (ifindex > 0, FALSE); + + return klass->wpan_get_short_addr (self, ifindex); +} + +gboolean +nm_platform_wpan_set_short_addr (NMPlatform *self, int ifindex, guint16 short_addr) +{ + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (ifindex > 0, FALSE); + + return klass->wpan_set_short_addr (self, ifindex, short_addr); +} + #define TO_STRING_DEV_BUF_SIZE (5+15+1) static const char * _to_string_dev (NMPlatform *self, int ifindex, char *buf, size_t size) @@ -3014,6 +3213,32 @@ NM_UTILS_LOOKUP_STR_DEFINE (nm_platform_link_duplex_type_to_string, NMPlatformLi /*****************************************************************************/ +NMEthtoolFeatureStates * +nm_platform_ethtool_get_link_features (NMPlatform *self, int ifindex) +{ + _CHECK_SELF_NETNS (self, klass, netns, NULL); + + g_return_val_if_fail (ifindex > 0, NULL); + + return nmp_utils_ethtool_get_features (ifindex); +} + +gboolean +nm_platform_ethtool_set_features (NMPlatform *self, + int ifindex, + const NMEthtoolFeatureStates *features, + const NMTernary *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */, + gboolean do_set /* or reset */) +{ + _CHECK_SELF_NETNS (self, klass, netns, FALSE); + + g_return_val_if_fail (ifindex > 0, FALSE); + + return nmp_utils_ethtool_set_features (ifindex, features, requested, do_set); +} + +/*****************************************************************************/ + const NMDedupMultiHeadEntry * nm_platform_lookup_all (NMPlatform *platform, NMPCacheIdType cache_id_type, @@ -3622,7 +3847,7 @@ ip6_address_scope_priority (const struct in6_addr *addr) return 3; } -static gint +static int ip6_address_scope_cmp (gconstpointer a, gconstpointer b) { const NMPlatformIP6Address *x = NMP_OBJECT_CAST_IP6_ADDRESS (*(const void **) a); @@ -4957,7 +5182,7 @@ nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len return buf; g_snprintf (buf, len, - "gre" + lnk->is_tap ? "gretap" : "gre" "%s" /* remote */ "%s" /* local */ "%s" /* parent_ifindex */ @@ -5014,12 +5239,18 @@ nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsi char str_encap[30]; char str_proto[30]; char str_parent_ifindex[30]; + char *str_type; if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) return buf; + if (lnk->is_gre) + str_type = lnk->is_tap ? "ip6gretap" : "ip6gre"; + else + str_type = "ip6tnl"; + g_snprintf (buf, len, - "ip6tnl" + "%s" /* type */ "%s" /* remote */ "%s" /* local */ "%s" /* parent_ifindex */ @@ -5030,6 +5261,7 @@ nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsi "%s" /* proto */ " flags 0x%x" "", + str_type, nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet6_ntop (&lnk->remote, str_remote1)), nm_sprintf_buf (str_local, " local %s", nm_utils_inet6_ntop (&lnk->local, str_local1)), lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "", @@ -5114,7 +5346,8 @@ nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, g return buf; g_snprintf (buf, len, - "macvlan mode %u %s", + "%s mode %u %s", + lnk->tap ? "macvtap" : "macvlan", lnk->mode, lnk->no_promisc ? "not-promisc" : "promisc"); return buf; @@ -5298,6 +5531,91 @@ nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize return buf; } +const char * +nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, gsize len) +{ + gs_free char *public_key_b64 = NULL; + char s_endpoint[NM_UTILS_INET_ADDRSTRLEN + 100]; + char s_addr[NM_UTILS_INET_ADDRSTRLEN]; + guint i; + + nm_utils_to_string_buffer_init (&buf, &len); + + if (peer->endpoint_family == AF_INET) { + nm_sprintf_buf (s_endpoint, + " endpoint %s:%u", + nm_utils_inet4_ntop (peer->endpoint_addr.addr4, s_addr), + (guint) peer->endpoint_port); + } else if (peer->endpoint_family == AF_INET6) { + nm_sprintf_buf (s_endpoint, + " endpoint [%s]:%u", + nm_utils_inet6_ntop (&peer->endpoint_addr.addr6, s_addr), + (guint) peer->endpoint_port); + } else + s_endpoint[0] = '\0'; + + public_key_b64 = g_base64_encode (peer->public_key, sizeof (peer->public_key)); + + nm_utils_strbuf_append (&buf, &len, + "public-key %s" + "%s" /* preshared-key */ + "%s" /* endpoint */ + " rx %"G_GUINT64_FORMAT + " tx %"G_GUINT64_FORMAT + "%s", /* allowed-ips */ + public_key_b64, + nm_utils_mem_all_zero (peer->preshared_key, sizeof (peer->preshared_key)) + ? "" + : " preshared-key (hidden)", + s_endpoint, + peer->rx_bytes, + peer->tx_bytes, + peer->allowed_ips_len > 0 + ? " allowed-ips" + : ""); + + for (i = 0; i < peer->allowed_ips_len; i++) { + const NMPWireGuardAllowedIP *allowed_ip = &peer->allowed_ips[i]; + + nm_utils_strbuf_append (&buf, &len, + " %s/%u", + nm_utils_inet_ntop (allowed_ip->family, &allowed_ip->addr, s_addr), + allowed_ip->mask); + } + + return buf; +} + +const char * +nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireGuard *lnk, char *buf, gsize len) +{ + gs_free char *public_b64 = NULL; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + if (!nm_utils_mem_all_zero (lnk->public_key, sizeof (lnk->public_key))) + public_b64 = g_base64_encode (lnk->public_key, sizeof (lnk->public_key)); + + g_snprintf (buf, len, + "wireguard" + "%s%s" /* public-key */ + "%s" /* private-key */ + " listen-port %u" + " fwmark 0x%x", + public_b64 + ? " public-key " + : "", + public_b64 ?: "", + nm_utils_mem_all_zero (lnk->private_key, sizeof (lnk->private_key)) + ? "" + : " private-key (hidden)", + lnk->listen_port, + lnk->fwmark); + + return buf; +} + /** * nm_platform_ip4_address_to_string: * @route: pointer to NMPlatformIP4Address address structure @@ -5775,6 +6093,56 @@ nm_platform_tfilter_cmp (const NMPlatformTfilter *a, const NMPlatformTfilter *b) return 0; } +const char * +nm_platform_vf_to_string (const NMPlatformVF *vf, char *buf, gsize len) +{ + char str_mac[128], mac[128]; + char str_spoof_check[64]; + char str_trust[64]; + char str_min_tx_rate[64]; + char str_max_tx_rate[64]; + nm_auto_free_gstring GString *gstr_vlans = NULL; + guint i; + + if (!nm_utils_to_string_buffer_init_null (vf, &buf, &len)) + return buf; + + if (vf->mac.len) { + nm_utils_hwaddr_ntoa_buf (vf->mac.data, vf->mac.len, TRUE, mac, sizeof (mac)); + nm_sprintf_buf (str_mac, " mac %s", mac); + } else + str_mac[0] = '\0'; + + if (vf->num_vlans) { + gstr_vlans = g_string_new (""); + for (i = 0; i < vf->num_vlans; i++) { + g_string_append_printf (gstr_vlans, " vlan %u", (unsigned) vf->vlans[i].id); + if (vf->vlans[i].qos) + g_string_append_printf (gstr_vlans, " qos %u", (unsigned) vf->vlans[i].qos); + if (vf->vlans[i].proto_ad) + g_string_append (gstr_vlans, " proto 802.1ad"); + } + } + + g_snprintf (buf, len, + "%u" /* index */ + "%s" /* MAC */ + "%s" /* spoof check */ + "%s" /* trust */ + "%s" /* min tx rate */ + "%s" /* max tx rate */ + "%s", /* VLANs */ + vf->index, + str_mac, + vf->spoofchk >= 0 ? nm_sprintf_buf (str_spoof_check, " spoofchk %d", vf->spoofchk) : "", + vf->trust >= 0 ? nm_sprintf_buf (str_trust, " trust %d", vf->trust) : "", + vf->min_tx_rate ? nm_sprintf_buf (str_min_tx_rate, " min_tx_rate %u", (unsigned) vf->min_tx_rate) : "", + vf->max_tx_rate ? nm_sprintf_buf (str_max_tx_rate, " max_tx_rate %u", (unsigned) vf->max_tx_rate) : "", + gstr_vlans ? gstr_vlans->str : ""); + + return buf; +} + void nm_platform_link_hash_update (const NMPlatformLink *obj, NMHashState *h) { @@ -5843,7 +6211,8 @@ nm_platform_lnk_gre_hash_update (const NMPlatformLnkGre *obj, NMHashState *h) obj->output_key, obj->ttl, obj->tos, - (bool) obj->path_mtu_discovery); + (bool) obj->path_mtu_discovery, + (bool) obj->is_tap); } int @@ -5860,6 +6229,7 @@ nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b) NM_CMP_FIELD (a, b, ttl); NM_CMP_FIELD (a, b, tos); NM_CMP_FIELD_BOOL (a, b, path_mtu_discovery); + NM_CMP_FIELD_BOOL (a, b, is_tap); return 0; } @@ -5891,7 +6261,13 @@ nm_platform_lnk_ip6tnl_hash_update (const NMPlatformLnkIp6Tnl *obj, NMHashState obj->encap_limit, obj->proto, obj->flow_label, - obj->flags); + obj->flags, + obj->input_flags, + obj->output_flags, + obj->input_key, + obj->output_key, + (bool) obj->is_gre, + (bool) obj->is_tap); } int @@ -5907,6 +6283,12 @@ nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6 NM_CMP_FIELD (a, b, flow_label); NM_CMP_FIELD (a, b, proto); NM_CMP_FIELD (a, b, flags); + NM_CMP_FIELD (a, b, input_flags); + NM_CMP_FIELD (a, b, output_flags); + NM_CMP_FIELD (a, b, input_key); + NM_CMP_FIELD (a, b, output_key); + NM_CMP_FIELD_BOOL (a, b, is_gre); + NM_CMP_FIELD_BOOL (a, b, is_tap); return 0; } @@ -6124,6 +6506,27 @@ nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan } void +nm_platform_lnk_wireguard_hash_update (const NMPlatformLnkWireGuard *obj, NMHashState *h) +{ + nm_hash_update_vals (h, + obj->listen_port, + obj->fwmark); + nm_hash_update (h, obj->private_key, sizeof (obj->private_key)); + nm_hash_update (h, obj->public_key, sizeof (obj->public_key)); +} + +int +nm_platform_lnk_wireguard_cmp (const NMPlatformLnkWireGuard *a, const NMPlatformLnkWireGuard *b) +{ + NM_CMP_SELF (a, b); + NM_CMP_FIELD (a, b, listen_port); + NM_CMP_FIELD (a, b, fwmark); + NM_CMP_FIELD_MEMCMP (a, b, private_key); + NM_CMP_FIELD_MEMCMP (a, b, public_key); + return 0; +} + +void nm_platform_ip4_address_hash_update (const NMPlatformIP4Address *obj, NMHashState *h) { nm_hash_update_vals (h, diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 866df736..11495aff 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -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) 2009 - 2017 Red Hat, Inc. + * Copyright (C) 2009 - 2018 Red Hat, Inc. */ #ifndef __NETWORKMANAGER_PLATFORM_H__ @@ -608,6 +608,26 @@ extern const NMPlatformVTableRoute nm_platform_vtable_route_v4; extern const NMPlatformVTableRoute nm_platform_vtable_route_v6; typedef struct { + guint16 id; + guint32 qos; + bool proto_ad:1; +} NMPlatformVFVlan; + +typedef struct { + guint32 index; + guint32 min_tx_rate; + guint32 max_tx_rate; + guint num_vlans; + NMPlatformVFVlan *vlans; + struct { + guint8 data[20]; /* NM_UTILS_HWADDR_LEN_MAX */ + guint8 len; + } mac; + gint8 spoofchk; + gint8 trust; +} NMPlatformVF; + +typedef struct { in_addr_t local; in_addr_t remote; int parent_ifindex; @@ -618,6 +638,7 @@ typedef struct { guint8 ttl; guint8 tos; bool path_mtu_discovery:1; + bool is_tap:1; } NMPlatformLnkGre; typedef struct { @@ -635,6 +656,14 @@ typedef struct { guint8 proto; guint flow_label; guint32 flags; + + /* IP6GRE only */ + guint32 input_key; + guint32 output_key; + guint16 input_flags; + guint16 output_flags; + bool is_tap:1; + bool is_gre:1; } NMPlatformLnkIp6Tnl; typedef struct { @@ -723,6 +752,16 @@ typedef struct { bool l3miss:1; } NMPlatformLnkVxlan; +#define NMP_WIREGUARD_PUBLIC_KEY_LEN 32 +#define NMP_WIREGUARD_SYMMETRIC_KEY_LEN 32 + +typedef struct { + guint32 fwmark; + guint16 listen_port; + guint8 private_key[NMP_WIREGUARD_PUBLIC_KEY_LEN]; + guint8 public_key[NMP_WIREGUARD_PUBLIC_KEY_LEN]; +} NMPlatformLnkWireGuard; + typedef enum { NM_PLATFORM_LINK_DUPLEX_UNKNOWN, NM_PLATFORM_LINK_DUPLEX_HALF, @@ -786,7 +825,8 @@ typedef struct { NMPlatformError (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length); NMPlatformError (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu); gboolean (*link_set_name) (NMPlatform *, int ifindex, const char *name); - gboolean (*link_set_sriov_num_vfs) (NMPlatform *, int ifindex, guint num_vfs); + gboolean (*link_set_sriov_params) (NMPlatform *, int ifindex, guint num_vfs, int autoprobe); + gboolean (*link_set_sriov_vfs) (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs); char * (*link_get_physical_port_id) (NMPlatform *, int ifindex); guint (*link_get_dev_id) (NMPlatform *, int ifindex); @@ -829,6 +869,10 @@ typedef struct { const char *name, const NMPlatformLnkIp6Tnl *props, const NMPlatformLink **out_link); + gboolean (*link_ip6gre_add) (NMPlatform *, + const char *name, + const NMPlatformLnkIp6Tnl *props, + const NMPlatformLink **out_link); gboolean (*link_ipip_add) (NMPlatform *, const char *name, const NMPlatformLnkIpIp *props, @@ -854,12 +898,16 @@ typedef struct { const NMPlatformLink **out_link, int *out_fd); + gboolean (*link_6lowpan_add) (NMPlatform *platform, + const char *name, + int parent, + const NMPlatformLink **out_link); + gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, const NMPlatformLink **out_link); gboolean (*infiniband_partition_delete) (NMPlatform *, int parent, int p_key); gboolean (*wifi_get_capabilities) (NMPlatform *, int ifindex, NMDeviceWifiCapabilities *caps); gboolean (*wifi_get_bssid) (NMPlatform *, int ifindex, guint8 *bssid); - GByteArray *(*wifi_get_ssid) (NMPlatform *, int ifindex); guint32 (*wifi_get_frequency) (NMPlatform *, int ifindex); int (*wifi_get_quality) (NMPlatform *, int ifindex); guint32 (*wifi_get_rate) (NMPlatform *, int ifindex); @@ -868,12 +916,18 @@ typedef struct { void (*wifi_set_powersave) (NMPlatform *, int ifindex, guint32 powersave); guint32 (*wifi_find_frequency) (NMPlatform *, int ifindex, const guint32 *freqs); void (*wifi_indicate_addressing_running) (NMPlatform *, int ifindex, gboolean running); + NMSettingWirelessWakeOnWLan (*wifi_get_wake_on_wlan) (NMPlatform *, int ifindex); gboolean (*wifi_set_wake_on_wlan) (NMPlatform *, int ifindex, NMSettingWirelessWakeOnWLan wowl); guint32 (*mesh_get_channel) (NMPlatform *, int ifindex); gboolean (*mesh_set_channel) (NMPlatform *, int ifindex, guint32 channel); gboolean (*mesh_set_ssid) (NMPlatform *, int ifindex, const guint8 *ssid, gsize len); + guint16 (*wpan_get_pan_id) (NMPlatform *, int ifindex); + gboolean (*wpan_set_pan_id) (NMPlatform *, int ifindex, guint16 pan_id); + guint16 (*wpan_get_short_addr) (NMPlatform *, int ifindex); + gboolean (*wpan_set_short_addr) (NMPlatform *, int ifindex, guint16 short_addr); + gboolean (*object_delete) (NMPlatform *, const NMPObject *obj); gboolean (*ip4_address_add) (NMPlatform *, @@ -1078,7 +1132,7 @@ const NMPObject *nm_platform_link_get_obj (NMPlatform *self, gboolean visible_only); const NMPlatformLink *nm_platform_link_get (NMPlatform *self, int ifindex); const NMPlatformLink *nm_platform_link_get_by_ifname (NMPlatform *self, const char *ifname); -const NMPlatformLink *nm_platform_link_get_by_address (NMPlatform *self, gconstpointer address, size_t length); +const NMPlatformLink *nm_platform_link_get_by_address (NMPlatform *self, NMLinkType link_type, gconstpointer address, size_t length); GPtrArray *nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name); NMPlatformError nm_platform_link_dummy_add (NMPlatform *self, const char *name, const NMPlatformLink **out_link); @@ -1162,7 +1216,8 @@ gboolean nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex, NMPlatformError nm_platform_link_set_address (NMPlatform *self, int ifindex, const void *address, size_t length); NMPlatformError nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu); gboolean nm_platform_link_set_name (NMPlatform *self, int ifindex, const char *name); -gboolean nm_platform_link_set_sriov_num_vfs (NMPlatform *self, int ifindex, guint num_vfs); +gboolean nm_platform_link_set_sriov_params (NMPlatform *self, int ifindex, guint num_vfs, int autoprobe); +gboolean nm_platform_link_set_sriov_vfs (NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs); char *nm_platform_link_get_physical_port_id (NMPlatform *self, int ifindex); guint nm_platform_link_get_dev_id (NMPlatform *self, int ifindex); @@ -1187,7 +1242,10 @@ char *nm_platform_sysctl_slave_get_option (NMPlatform *self, int ifindex, const const NMPObject *nm_platform_link_get_lnk (NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link); const NMPlatformLnkGre *nm_platform_link_get_lnk_gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkGre *nm_platform_link_get_lnk_gretap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkIp6Tnl *nm_platform_link_get_lnk_ip6tnl (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkIp6Tnl *nm_platform_link_get_lnk_ip6gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkIp6Tnl *nm_platform_link_get_lnk_ip6gretap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkInfiniband *nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); @@ -1198,6 +1256,7 @@ const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform *self, int ifin const NMPlatformLnkTun *nm_platform_link_get_lnk_tun (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkWireGuard *nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); NMPlatformError nm_platform_link_vlan_add (NMPlatform *self, const char *name, @@ -1247,12 +1306,18 @@ void nm_platform_wifi_set_mode (NMPlatform *self, int ifindex, NM void nm_platform_wifi_set_powersave (NMPlatform *self, int ifindex, guint32 powersave); guint32 nm_platform_wifi_find_frequency (NMPlatform *self, int ifindex, const guint32 *freqs); void nm_platform_wifi_indicate_addressing_running (NMPlatform *self, int ifindex, gboolean running); +NMSettingWirelessWakeOnWLan nm_platform_wifi_get_wake_on_wlan (NMPlatform *self, int ifindex); gboolean nm_platform_wifi_set_wake_on_wlan (NMPlatform *self, int ifindex, NMSettingWirelessWakeOnWLan wowl); guint32 nm_platform_mesh_get_channel (NMPlatform *self, int ifindex); gboolean nm_platform_mesh_set_channel (NMPlatform *self, int ifindex, guint32 channel); gboolean nm_platform_mesh_set_ssid (NMPlatform *self, int ifindex, const guint8 *ssid, gsize len); +guint16 nm_platform_wpan_get_pan_id (NMPlatform *platform, int ifindex); +gboolean nm_platform_wpan_set_pan_id (NMPlatform *platform, int ifindex, guint16 pan_id); +guint16 nm_platform_wpan_get_short_addr (NMPlatform *platform, int ifindex); +gboolean nm_platform_wpan_set_short_addr (NMPlatform *platform, int ifindex, guint16 short_addr); + void nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address, guint8 plen); const struct in6_addr *nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr); @@ -1266,6 +1331,10 @@ NMPlatformError nm_platform_link_ip6tnl_add (NMPlatform *self, const char *name, const NMPlatformLnkIp6Tnl *props, const NMPlatformLink **out_link); +NMPlatformError nm_platform_link_ip6gre_add (NMPlatform *self, + const char *name, + const NMPlatformLnkIp6Tnl *props, + const NMPlatformLink **out_link); NMPlatformError nm_platform_link_ipip_add (NMPlatform *self, const char *name, const NMPlatformLnkIpIp *props, @@ -1289,6 +1358,13 @@ NMPlatformError nm_platform_link_tun_add (NMPlatform *self, const NMPlatformLnkTun *props, const NMPlatformLink **out_link, int *out_fd); +NMPlatformError nm_platform_link_6lowpan_add (NMPlatform *self, + const char *name, + int parent, + const NMPlatformLink **out_link); +gboolean nm_platform_link_6lowpan_get_properties (NMPlatform *self, + int ifindex, + int *out_parent); const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address); @@ -1375,12 +1451,14 @@ const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *bu const char *nm_platform_lnk_tun_to_string (const NMPlatformLnkTun *lnk, char *buf, gsize len); const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len); const char *nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len); +const char *nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireGuard *lnk, char *buf, gsize len); const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len); const char *nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *buf, gsize len); const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsize len); const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len); const char *nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len); const char *nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsize len); +const char *nm_platform_vf_to_string (const NMPlatformVF *vf, char *buf, gsize len); const char *nm_platform_vlan_qos_mapping_to_string (const char *name, const NMVlanQosMapping *map, @@ -1388,6 +1466,11 @@ const char *nm_platform_vlan_qos_mapping_to_string (const char *name, char *buf, gsize len); +struct _NMPWireGuardPeer; +const char *nm_platform_wireguard_peer_to_string (const struct _NMPWireGuardPeer *peer, + char *buf, + gsize len); + int nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b); int nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b); int nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b); @@ -1399,6 +1482,7 @@ int nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit * int nm_platform_lnk_tun_cmp (const NMPlatformLnkTun *a, const NMPlatformLnkTun *b); int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b); int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b); +int nm_platform_lnk_wireguard_cmp (const NMPlatformLnkWireGuard *a, const NMPlatformLnkWireGuard *b); int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b); int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b); @@ -1435,6 +1519,7 @@ void nm_platform_lnk_sit_hash_update (const NMPlatformLnkSit *obj, NMHashState * void nm_platform_lnk_tun_hash_update (const NMPlatformLnkTun *obj, NMHashState *h); void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h); void nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h); +void nm_platform_lnk_wireguard_hash_update (const NMPlatformLnkWireGuard *obj, NMHashState *h); void nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h); void nm_platform_tfilter_hash_update (const NMPlatformTfilter *obj, NMHashState *h); @@ -1452,6 +1537,17 @@ int nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPla gboolean nm_platform_ethtool_set_wake_on_lan (NMPlatform *self, int ifindex, NMSettingWiredWakeOnLan wol, const char *wol_password); gboolean nm_platform_ethtool_set_link_settings (NMPlatform *self, int ifindex, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex); gboolean nm_platform_ethtool_get_link_settings (NMPlatform *self, int ifindex, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex); + +typedef struct _NMEthtoolFeatureStates NMEthtoolFeatureStates; + +NMEthtoolFeatureStates *nm_platform_ethtool_get_link_features (NMPlatform *self, + int ifindex); +gboolean nm_platform_ethtool_set_features (NMPlatform *self, + int ifindex, + const NMEthtoolFeatureStates *features, + const NMTernary *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */, + gboolean do_set /* or reset */); + const char * nm_platform_link_duplex_type_to_string (NMPlatformLinkDuplexType duplex); void nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self, diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 50e6825b..fdc27440 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.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) 2015 - 2017 Red Hat, Inc. + * Copyright (C) 2015 - 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -27,10 +27,14 @@ #include <libudev.h> #include "nm-utils.h" +#include "nm-utils/nm-secret-utils.h" #include "nm-core-utils.h" #include "nm-platform-utils.h" +#include "wifi/nm-wifi-utils.h" +#include "wpan/nm-wpan-utils.h" + /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_PLATFORM @@ -337,12 +341,103 @@ _vlan_xgress_qos_mappings_cpy (guint *dst_n_map, g_clear_pointer (dst_map, g_free); *dst_n_map = src_n_map; if (src_n_map > 0) - *dst_map = g_memdup (src_map, sizeof (*src_map) * src_n_map); + *dst_map = nm_memdup (src_map, sizeof (*src_map) * src_n_map); } } /*****************************************************************************/ +static void +_wireguard_allowed_ip_hash_update (const NMPWireGuardAllowedIP *ip, + NMHashState *h) +{ + nm_hash_update_vals (h, ip->family, + ip->mask); + + if (ip->family == AF_INET) + nm_hash_update_val (h, ip->addr.addr4); + else if (ip->family == AF_INET6) + nm_hash_update_val (h, ip->addr.addr6); +} + +static int +_wireguard_allowed_ip_cmp (const NMPWireGuardAllowedIP *a, + const NMPWireGuardAllowedIP *b) +{ + NM_CMP_SELF (a, b); + + NM_CMP_FIELD (a, b, family); + NM_CMP_FIELD (a, b, mask); + + if (a->family == AF_INET) + NM_CMP_FIELD (a, b, addr.addr4); + else if (a->family == AF_INET6) + NM_CMP_FIELD_IN6ADDR (a, b, addr.addr6); + + return 0; +} + +static void +_wireguard_peer_hash_update (const NMPWireGuardPeer *peer, + NMHashState *h) +{ + guint i; + + nm_hash_update (h, peer->public_key, sizeof (peer->public_key)); + nm_hash_update (h, peer->preshared_key, sizeof (peer->preshared_key)); + nm_hash_update_vals (h, + peer->persistent_keepalive_interval, + peer->allowed_ips_len, + peer->rx_bytes, + peer->tx_bytes, + peer->last_handshake_time.tv_sec, + peer->last_handshake_time.tv_nsec, + peer->endpoint_port, + peer->endpoint_family); + + if (peer->endpoint_family == AF_INET) + nm_hash_update_val (h, peer->endpoint_addr.addr4); + else if (peer->endpoint_family == AF_INET6) + nm_hash_update_val (h, peer->endpoint_addr.addr6); + + for (i = 0; i < peer->allowed_ips_len; i++) + _wireguard_allowed_ip_hash_update (&peer->allowed_ips[i], h); +} + +static int +_wireguard_peer_cmp (const NMPWireGuardPeer *a, + const NMPWireGuardPeer *b) +{ + guint i; + + NM_CMP_SELF (a, b); + + NM_CMP_FIELD (a, b, last_handshake_time.tv_sec); + NM_CMP_FIELD (a, b, last_handshake_time.tv_nsec); + NM_CMP_FIELD (a, b, rx_bytes); + NM_CMP_FIELD (a, b, tx_bytes); + NM_CMP_FIELD (a, b, allowed_ips_len); + NM_CMP_FIELD (a, b, persistent_keepalive_interval); + NM_CMP_FIELD (a, b, endpoint_port); + NM_CMP_FIELD (a, b, endpoint_family); + NM_CMP_FIELD_MEMCMP (a, b, public_key); + NM_CMP_FIELD_MEMCMP (a, b, preshared_key); + + if (a->endpoint_family == AF_INET) + NM_CMP_FIELD (a, b, endpoint_addr.addr4); + else if (a->endpoint_family == AF_INET6) + NM_CMP_FIELD_IN6ADDR (a, b, endpoint_addr.addr6); + + for (i = 0; i < a->allowed_ips_len; i++) { + NM_CMP_RETURN (_wireguard_allowed_ip_cmp (&a->allowed_ips[i], + &b->allowed_ips[i])); + } + + return 0; +} + +/*****************************************************************************/ + static const char * _link_get_driver (struct udev_device *udevice, const char *kind, int ifindex) { @@ -456,6 +551,7 @@ _vt_cmd_obj_dispose_link (NMPObject *obj) udev_device_unref (obj->_link.udev.device); obj->_link.udev.device = NULL; } + g_clear_object (&obj->_link.ext_data); nmp_object_unref (obj->_link.netlink.lnk); } @@ -466,6 +562,28 @@ _vt_cmd_obj_dispose_lnk_vlan (NMPObject *obj) g_free ((gpointer) obj->_lnk_vlan.egress_qos_map); } +static void +_wireguard_clear (NMPObjectLnkWireGuard *lnk) +{ + guint i; + + nm_explicit_bzero (lnk->_public.private_key, + sizeof (lnk->_public.private_key)); + for (i = 0; i < lnk->peers_len; i++) { + NMPWireGuardPeer *peer = (NMPWireGuardPeer *) &lnk->peers[i]; + + nm_explicit_bzero (peer->preshared_key, sizeof (peer->preshared_key)); + } + g_free ((gpointer) lnk->peers); + g_free ((gpointer) lnk->_allowed_ips_buf); +} + +static void +_vt_cmd_obj_dispose_lnk_wireguard (NMPObject *obj) +{ + _wireguard_clear (&obj->_lnk_wireguard); +} + static NMPObject * _nmp_object_new_from_class (const NMPClass *klass) { @@ -631,31 +749,35 @@ static const char * _vt_cmd_obj_to_string_link (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size) { const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj); - char buf2[sizeof (_nm_utils_to_string_buffer)]; - char buf3[sizeof (_nm_utils_to_string_buffer)]; + char *b = buf; switch (to_string_mode) { case NMP_OBJECT_TO_STRING_ID: return klass->cmd_plobj_to_string_id (&obj->object, buf, buf_size); case NMP_OBJECT_TO_STRING_ALL: - g_snprintf (buf, buf_size, - "[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; %s]", - klass->obj_type_name, obj, obj->parent._ref_count, - nmp_object_is_alive (obj) ? '+' : '-', - nmp_object_is_visible (obj) ? '+' : '-', - obj->_link.netlink.is_in_netlink ? '+' : '-', - obj->_link.udev.device, - nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof (buf2))); + nm_utils_strbuf_append (&b, &buf_size, + "[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; ", + klass->obj_type_name, obj, obj->parent._ref_count, + nmp_object_is_alive (obj) ? '+' : '-', + nmp_object_is_visible (obj) ? '+' : '-', + obj->_link.netlink.is_in_netlink ? '+' : '-', + obj->_link.udev.device); + NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, b, buf_size); + nm_utils_strbuf_seek_end (&b, &buf_size); + if (obj->_link.netlink.lnk) { + nm_utils_strbuf_append_str (&b, &buf_size, "; "); + nmp_object_to_string (obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_ALL, b, buf_size); + nm_utils_strbuf_seek_end (&b, &buf_size); + } + nm_utils_strbuf_append_c (&b, &buf_size, ']'); return buf; case NMP_OBJECT_TO_STRING_PUBLIC: + NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, b, buf_size); if (obj->_link.netlink.lnk) { - NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf2, sizeof (buf2)); - nmp_object_to_string (obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_PUBLIC, buf3, sizeof (buf3)); - g_snprintf (buf, buf_size, - "%s; %s", - buf2, buf3); - } else - NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf, buf_size); + nm_utils_strbuf_seek_end (&b, &buf_size); + nm_utils_strbuf_append_str (&b, &buf_size, "; "); + nmp_object_to_string (obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_PUBLIC, b, buf_size); + } return buf; default: g_return_val_if_reached ("ERROR"); @@ -720,6 +842,55 @@ _vt_cmd_obj_to_string_lnk_vlan (const NMPObject *obj, NMPObjectToStringMode to_s } } +static const char * +_vt_cmd_obj_to_string_lnk_wireguard (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size) +{ + const NMPClass *klass; + char buf2[sizeof (_nm_utils_to_string_buffer)]; + char *b; + guint i; + + klass = NMP_OBJECT_GET_CLASS (obj); + + switch (to_string_mode) { + case NMP_OBJECT_TO_STRING_ID: + g_snprintf (buf, buf_size, "%p", obj); + return buf; + case NMP_OBJECT_TO_STRING_ALL: + b = buf; + + nm_utils_strbuf_append (&b, &buf_size, + "[%s,%p,%u,%calive,%cvisible; %s" + "%s", + klass->obj_type_name, obj, obj->parent._ref_count, + nmp_object_is_alive (obj) ? '+' : '-', + nmp_object_is_visible (obj) ? '+' : '-', + nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof (buf2)), + obj->_lnk_wireguard.peers_len > 0 + ? " peers {" + : ""); + + for (i = 0; i < obj->_lnk_wireguard.peers_len; i++) { + const NMPWireGuardPeer *peer = &obj->_lnk_wireguard.peers[i]; + + nm_utils_strbuf_append_str (&b, &buf_size, " { "); + nm_platform_wireguard_peer_to_string (peer, b, buf_size); + nm_utils_strbuf_seek_end (&b, &buf_size); + nm_utils_strbuf_append_str (&b, &buf_size, " }"); + } + if (obj->_lnk_wireguard.peers_len) + nm_utils_strbuf_append_str (&b, &buf_size, " }"); + + return buf; + case NMP_OBJECT_TO_STRING_PUBLIC: + NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf, buf_size); + + return buf; + default: + g_return_val_if_reached ("ERROR"); + } +} + #define _vt_cmd_plobj_to_string_id(type, plat_type, ...) \ static const char * \ _vt_cmd_plobj_to_string_id_##type (const NMPlatformObject *_obj, char *buf, gsize buf_len) \ @@ -768,6 +939,7 @@ _vt_cmd_obj_hash_update_link (const NMPObject *obj, NMHashState *h) nm_platform_link_hash_update (&obj->link, h); nm_hash_update_vals (h, obj->_link.netlink.is_in_netlink, + obj->_link.wireguard_family_id, obj->_link.udev.device); if (obj->_link.netlink.lnk) nmp_object_hash_update (obj->_link.netlink.lnk, h); @@ -787,17 +959,26 @@ _vt_cmd_obj_hash_update_lnk_vlan (const NMPObject *obj, NMHashState *h) h); } +static void +_vt_cmd_obj_hash_update_lnk_wireguard (const NMPObject *obj, NMHashState *h) +{ + guint i; + + nm_assert (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LNK_WIREGUARD); + + nm_platform_lnk_wireguard_hash_update (&obj->lnk_wireguard, h); + + nm_hash_update_val (h, obj->_lnk_wireguard.peers_len); + for (i = 0; i < obj->_lnk_wireguard.peers_len; i++) + _wireguard_peer_hash_update (&obj->_lnk_wireguard.peers[i], h); +} + int nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2) { const NMPClass *klass1, *klass2; - if (obj1 == obj2) - return 0; - if (!obj1) - return -1; - if (!obj2) - return 1; + NM_CMP_SELF (obj1, obj2); g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj1), -1); g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj2), 1); @@ -818,16 +999,11 @@ nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2) static int _vt_cmd_obj_cmp_link (const NMPObject *obj1, const NMPObject *obj2) { - int i; + NM_CMP_RETURN (nm_platform_link_cmp (&obj1->link, &obj2->link)); + NM_CMP_DIRECT (obj1->_link.netlink.is_in_netlink, obj2->_link.netlink.is_in_netlink); + NM_CMP_RETURN (nmp_object_cmp (obj1->_link.netlink.lnk, obj2->_link.netlink.lnk)); + NM_CMP_DIRECT (obj1->_link.wireguard_family_id, obj2->_link.wireguard_family_id); - i = nm_platform_link_cmp (&obj1->link, &obj2->link); - if (i) - return i; - if (obj1->_link.netlink.is_in_netlink != obj2->_link.netlink.is_in_netlink) - return obj1->_link.netlink.is_in_netlink ? -1 : 1; - i = nmp_object_cmp (obj1->_link.netlink.lnk, obj2->_link.netlink.lnk); - if (i) - return i; if (obj1->_link.udev.device != obj2->_link.udev.device) { if (!obj1->_link.udev.device) return -1; @@ -840,6 +1016,7 @@ _vt_cmd_obj_cmp_link (const NMPObject *obj1, const NMPObject *obj2) * Have this check as very last. */ return (obj1->_link.udev.device < obj2->_link.udev.device) ? -1 : 1; } + return 0; } @@ -865,6 +1042,21 @@ _vt_cmd_obj_cmp_lnk_vlan (const NMPObject *obj1, const NMPObject *obj2) return c; } +static int +_vt_cmd_obj_cmp_lnk_wireguard (const NMPObject *obj1, const NMPObject *obj2) +{ + guint i; + + NM_CMP_RETURN (nm_platform_lnk_wireguard_cmp (&obj1->lnk_wireguard, &obj2->lnk_wireguard)); + + NM_CMP_FIELD (obj1, obj2, _lnk_wireguard.peers_len); + + for (i = 0; i < obj1->_lnk_wireguard.peers_len; i++) + NM_CMP_RETURN (_wireguard_peer_cmp (&obj1->_lnk_wireguard.peers[i], &obj2->_lnk_wireguard.peers[i])); + + return 0; +} + /* @src is a const object, which is not entirely correct for link types, where * we increase the ref count for src->_link.udev.device. * Hence, nmp_object_copy() can violate the const promise of @src. @@ -908,6 +1100,12 @@ _vt_cmd_obj_copy_link (NMPObject *dst, const NMPObject *src) nmp_object_unref (dst->_link.netlink.lnk); dst->_link.netlink.lnk = src->_link.netlink.lnk; } + if (dst->_link.ext_data != src->_link.ext_data) { + if (dst->_link.ext_data) + g_clear_object (&dst->_link.ext_data); + if (src->_link.ext_data) + dst->_link.ext_data = g_object_ref (src->_link.ext_data); + } dst->_link = src->_link; } @@ -925,6 +1123,41 @@ _vt_cmd_obj_copy_lnk_vlan (NMPObject *dst, const NMPObject *src) src->_lnk_vlan.egress_qos_map); } +static void +_vt_cmd_obj_copy_lnk_wireguard (NMPObject *dst, const NMPObject *src) +{ + guint i; + + nm_assert (dst != src); + + _wireguard_clear (&dst->_lnk_wireguard); + + dst->_lnk_wireguard = src->_lnk_wireguard; + + dst->_lnk_wireguard.peers = nm_memdup (dst->_lnk_wireguard.peers, + sizeof (NMPWireGuardPeer) * dst->_lnk_wireguard.peers_len); + dst->_lnk_wireguard._allowed_ips_buf = nm_memdup (dst->_lnk_wireguard._allowed_ips_buf, + sizeof (NMPWireGuardAllowedIP) * dst->_lnk_wireguard._allowed_ips_buf_len); + + /* all the peers' pointers point into the buffer. They need to be readjusted. */ + for (i = 0; i < dst->_lnk_wireguard.peers_len; i++) { + NMPWireGuardPeer *peer = (NMPWireGuardPeer *) &dst->_lnk_wireguard.peers[i]; + + if (peer->allowed_ips_len == 0) { + nm_assert (!peer->allowed_ips); + continue; + } + nm_assert (dst->_lnk_wireguard._allowed_ips_buf_len > 0); + nm_assert (src->_lnk_wireguard._allowed_ips_buf); + nm_assert (peer->allowed_ips >= src->_lnk_wireguard._allowed_ips_buf); + nm_assert (&peer->allowed_ips[peer->allowed_ips_len] <= &src->_lnk_wireguard._allowed_ips_buf[src->_lnk_wireguard._allowed_ips_buf_len]); + + peer->allowed_ips = &dst->_lnk_wireguard._allowed_ips_buf[peer->allowed_ips - src->_lnk_wireguard._allowed_ips_buf]; + } + + nm_assert (nmp_object_equal (src, dst)); +} + #define _vt_cmd_plobj_id_copy(type, plat_type, cmd) \ static void \ _vt_cmd_plobj_id_copy_##type (NMPlatformObject *_dst, const NMPlatformObject *_src) \ @@ -2702,6 +2935,17 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_gre_hash_update, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_gre_cmp, }, + [NMP_OBJECT_TYPE_LNK_GRETAP - 1] = { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_LNK_GRETAP, + .sizeof_data = sizeof (NMPObjectLnkGre), + .sizeof_public = sizeof (NMPlatformLnkGre), + .obj_type_name = "gretap", + .lnk_link_type = NM_LINK_TYPE_GRETAP, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_gre_to_string, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_gre_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_gre_cmp, + }, [NMP_OBJECT_TYPE_LNK_INFINIBAND - 1] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), .obj_type = NMP_OBJECT_TYPE_LNK_INFINIBAND, @@ -2724,6 +2968,28 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_ip6tnl_hash_update, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp, }, + [NMP_OBJECT_TYPE_LNK_IP6GRE - 1] = { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_LNK_IP6GRE, + .sizeof_data = sizeof (NMPObjectLnkIp6Tnl), + .sizeof_public = sizeof (NMPlatformLnkIp6Tnl), + .obj_type_name = "ip6gre", + .lnk_link_type = NM_LINK_TYPE_IP6GRE, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ip6tnl_to_string, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_ip6tnl_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp, + }, + [NMP_OBJECT_TYPE_LNK_IP6GRETAP - 1] = { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_LNK_IP6GRETAP, + .sizeof_data = sizeof (NMPObjectLnkIp6Tnl), + .sizeof_public = sizeof (NMPlatformLnkIp6Tnl), + .obj_type_name = "ip6gretap", + .lnk_link_type = NM_LINK_TYPE_IP6GRETAP, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ip6tnl_to_string, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_ip6tnl_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp, + }, [NMP_OBJECT_TYPE_LNK_IPIP - 1] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), .obj_type = NMP_OBJECT_TYPE_LNK_IPIP, @@ -2817,5 +3083,20 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_vxlan_hash_update, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vxlan_cmp, }, + [NMP_OBJECT_TYPE_LNK_WIREGUARD - 1] = { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_LNK_WIREGUARD, + .sizeof_data = sizeof (NMPObjectLnkWireGuard), + .sizeof_public = sizeof (NMPlatformLnkWireGuard), + .obj_type_name = "wireguard", + .lnk_link_type = NM_LINK_TYPE_WIREGUARD, + .cmd_obj_hash_update = _vt_cmd_obj_hash_update_lnk_wireguard, + .cmd_obj_cmp = _vt_cmd_obj_cmp_lnk_wireguard, + .cmd_obj_copy = _vt_cmd_obj_copy_lnk_wireguard, + .cmd_obj_dispose = _vt_cmd_obj_dispose_lnk_wireguard, + .cmd_obj_to_string = _vt_cmd_obj_to_string_lnk_wireguard, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_wireguard_to_string, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_vlan_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vlan_cmp, + }, }; - diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index f473f462..97be8321 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -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) 2015 - 2017 Red Hat, Inc. + * Copyright (C) 2015 - 2018 Red Hat, Inc. */ #ifndef __NMP_OBJECT_H__ @@ -27,6 +27,36 @@ struct udev_device; +/*****************************************************************************/ + +typedef struct { + NMIPAddr addr; + guint8 family; + guint8 mask; +} NMPWireGuardAllowedIP; + +typedef struct _NMPWireGuardPeer { + NMIPAddr endpoint_addr; + struct timespec last_handshake_time; + guint64 rx_bytes; + guint64 tx_bytes; + union { + const NMPWireGuardAllowedIP *allowed_ips; + guint _construct_idx_start; + }; + union { + guint allowed_ips_len; + guint _construct_idx_end; + }; + guint16 persistent_keepalive_interval; + guint16 endpoint_port; + guint8 public_key[NMP_WIREGUARD_PUBLIC_KEY_LEN]; + guint8 preshared_key[NMP_WIREGUARD_SYMMETRIC_KEY_LEN]; + guint8 endpoint_family; +} NMPWireGuardPeer; + +/*****************************************************************************/ + typedef enum { /*< skip >*/ NMP_OBJECT_TO_STRING_ID, NMP_OBJECT_TO_STRING_PUBLIC, @@ -164,6 +194,14 @@ typedef struct { */ struct udev_device *device; } udev; + + /* Auxiliary data object for Wi-Fi and WPAN */ + GObject *ext_data; + + /* FIXME: not every NMPObjectLink should pay the price for tracking + * the wireguard family id. This should be tracked via ext_data, which + * would be exactly the right place. */ + int wireguard_family_id; } NMPObjectLink; typedef struct { @@ -214,6 +252,14 @@ typedef struct { } NMPObjectLnkVxlan; typedef struct { + NMPlatformLnkWireGuard _public; + const NMPWireGuardPeer *peers; + const NMPWireGuardAllowedIP *_allowed_ips_buf; + guint peers_len; + guint _allowed_ips_buf_len; +} NMPObjectLnkWireGuard; + +typedef struct { NMPlatformIP4Address _public; } NMPObjectIP4Address; @@ -278,6 +324,9 @@ struct _NMPObject { NMPlatformLnkVxlan lnk_vxlan; NMPObjectLnkVxlan _lnk_vxlan; + NMPlatformLnkWireGuard lnk_wireguard; + NMPObjectLnkWireGuard _lnk_wireguard; + NMPlatformIPAddress ip_address; NMPlatformIPXAddress ipx_address; NMPlatformIP4Address ip4_address; diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index 8b8c87d8..12d91812 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -60,7 +60,7 @@ test_cleanup_internal (void) g_assert (ifindex > 0); /* wait for kernel to add the IPv6 link local address... it takes a bit. */ - NMTST_WAIT_ASSERT (100, { + NMTST_WAIT_ASSERT (300, { gs_unref_array GArray *addrs = NULL; const NMPlatformIP6Address *a; diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 42569d5b..3dedbd10 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -1243,21 +1243,29 @@ nmtstp_link_gre_add (NMPlatform *platform, const NMPlatformLink *pllink = NULL; gboolean success; char buffer[INET_ADDRSTRLEN]; + NMLinkType link_type; g_assert (nm_utils_is_valid_iface_name (name, NULL)); external_command = nmtstp_run_command_check_external (external_command); + link_type = lnk->is_tap ? NM_LINK_TYPE_GRETAP : NM_LINK_TYPE_GRE; _init_platform (&platform, external_command); if (external_command) { gs_free char *dev = NULL; + char *obj, *type; if (lnk->parent_ifindex) dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (platform, lnk->parent_ifindex)); - success = !nmtstp_run_command ("ip tunnel add %s mode gre %s local %s remote %s ttl %u tos %02x %s", + obj = lnk->is_tap ? "link" : "tunnel"; + type = lnk->is_tap ? "type gretap" : "mode gre"; + + success = !nmtstp_run_command ("ip %s add %s %s %s local %s remote %s ttl %u tos %02x %s", + obj, name, + type, dev ?: "", nm_utils_inet4_ntop (lnk->local, NULL), nm_utils_inet4_ntop (lnk->remote, buffer), @@ -1265,11 +1273,11 @@ nmtstp_link_gre_add (NMPlatform *platform, lnk->tos, lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); if (success) - pllink = nmtstp_assert_wait_for_link (platform, name, NM_LINK_TYPE_GRE, 100); + pllink = nmtstp_assert_wait_for_link (platform, name, link_type, 100); } else success = nm_platform_link_gre_add (platform, name, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS; - _assert_pllink (platform, success, pllink, name, NM_LINK_TYPE_GRE); + _assert_pllink (platform, success, pllink, name, link_type); return pllink; } @@ -1289,6 +1297,7 @@ nmtstp_link_ip6tnl_add (NMPlatform *platform, gboolean tclass_inherit; g_assert (nm_utils_is_valid_iface_name (name, NULL)); + g_assert (!lnk->is_gre); external_command = nmtstp_run_command_check_external (external_command); @@ -1336,6 +1345,56 @@ nmtstp_link_ip6tnl_add (NMPlatform *platform, } const NMPlatformLink * +nmtstp_link_ip6gre_add (NMPlatform *platform, + gboolean external_command, + const char *name, + const NMPlatformLnkIp6Tnl *lnk) +{ + const NMPlatformLink *pllink = NULL; + gboolean success; + char buffer[INET6_ADDRSTRLEN]; + char tclass[20]; + gboolean tclass_inherit; + + g_assert (nm_utils_is_valid_iface_name (name, NULL)); + g_assert (lnk->is_gre); + + external_command = nmtstp_run_command_check_external (external_command); + + _init_platform (&platform, external_command); + + if (external_command) { + gs_free char *dev = NULL; + + if (lnk->parent_ifindex) + dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (platform, lnk->parent_ifindex)); + + tclass_inherit = NM_FLAGS_HAS (lnk->flags, IP6_TNL_F_USE_ORIG_TCLASS); + + success = !nmtstp_run_command ("ip link add %s type %s %s local %s remote %s ttl %u tclass %s flowlabel %x", + name, + lnk->is_tap ? "ip6gretap" : "ip6gre", + dev, + nm_utils_inet6_ntop (&lnk->local, NULL), + nm_utils_inet6_ntop (&lnk->remote, buffer), + lnk->ttl, + tclass_inherit ? "inherit" : nm_sprintf_buf (tclass, "%02x", lnk->tclass), + lnk->flow_label); + if (success) { + pllink = nmtstp_assert_wait_for_link (platform, + name, + lnk->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE, + 100); + } + } else + success = nm_platform_link_ip6gre_add (platform, name, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS; + + _assert_pllink (platform, success, pllink, name, lnk->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE); + + return pllink; +} + +const NMPlatformLink * nmtstp_link_ipip_add (NMPlatform *platform, gboolean external_command, const char *name, diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index bd02b0d7..1baadfa1 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -80,7 +80,7 @@ typedef struct { gulong handler_id; const char *name; NMPlatformSignalChangeType change_type; - gint received_count; + int received_count; GMainLoop *loop; int ifindex; const char *ifname; @@ -297,6 +297,10 @@ const NMPlatformLink *nmtstp_link_ip6tnl_add (NMPlatform *platform, gboolean external_command, const char *name, const NMPlatformLnkIp6Tnl *lnk); +const NMPlatformLink *nmtstp_link_ip6gre_add (NMPlatform *platform, + gboolean external_command, + const char *name, + const NMPlatformLnkIp6Tnl *lnk); const NMPlatformLink *nmtstp_link_ipip_add (NMPlatform *platform, gboolean external_command, const char *name, diff --git a/src/platform/tests/test-general.c b/src/platform/tests/test-general.c index 8708c80f..eebc15d8 100644 --- a/src/platform/tests/test-general.c +++ b/src/platform/tests/test-general.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) 2015 Red Hat, Inc. + * Copyright (C) 2015 - 2018 Red Hat, Inc. */ #include "nm-default.h" @@ -57,7 +57,7 @@ NMTST_DEFINE (); int main (int argc, char **argv) { - nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); + nmtst_init_assert_logging (&argc, &argv, "WARN", "DEFAULT"); g_test_add_func ("/general/init_linux_platform", test_init_linux_platform); g_test_add_func ("/general/link_get_all", test_link_get_all); diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index cd5880e3..057490c4 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -25,6 +25,7 @@ #include <sys/types.h> #include <linux/if_tun.h> +#include "nm-utils/nm-io-utils.h" #include "platform/nmp-object.h" #include "platform/nmp-netns.h" #include "platform/nm-platform-utils.h" @@ -699,6 +700,7 @@ test_software_detect (gconstpointer user_data) guint i_step; const gboolean ext = test_data->external_command; NMPlatformLnkTun lnk_tun; + NMPlatformLnkGre lnk_gre = { }; nm_auto_close int tun_fd = -1; nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME); @@ -706,7 +708,6 @@ test_software_detect (gconstpointer user_data) switch (test_data->link_type) { case NM_LINK_TYPE_GRE: { - NMPlatformLnkGre lnk_gre = { }; gboolean gracefully_skip = FALSE; lnk_gre.local = nmtst_inet4_from_string ("192.168.233.204"); @@ -730,6 +731,31 @@ test_software_detect (gconstpointer user_data) } break; } + case NM_LINK_TYPE_GRETAP: { + gboolean gracefully_skip = FALSE; + + lnk_gre.local = nmtst_inet4_from_string ("192.168.1.133"); + lnk_gre.remote = nmtst_inet4_from_string ("172.168.101.2"); + lnk_gre.parent_ifindex = ifindex_parent; + lnk_gre.ttl = 39; + lnk_gre.tos = 12; + lnk_gre.path_mtu_discovery = FALSE; + lnk_gre.is_tap = TRUE; + + if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "gretap0")) { + /* Seems that the ip_gre module is not loaded... try to load it. */ + gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip_gre", NULL) != 0; + } + + if (!nmtstp_link_gre_add (NULL, ext, DEVICE_NAME, &lnk_gre)) { + if (gracefully_skip) { + g_test_skip ("Cannot create gretap tunnel because of missing ip_gre module (modprobe ip_gre)"); + goto out_delete_parent; + } + g_error ("Failed adding GRETAP tunnel"); + } + break; + } case NM_LINK_TYPE_IPIP: { NMPlatformLnkIpIp lnk_ipip = { }; gboolean gracefully_skip = FALSE; @@ -794,6 +820,58 @@ test_software_detect (gconstpointer user_data) } break; } + case NM_LINK_TYPE_IP6GRE: { + NMPlatformLnkIp6Tnl lnk_ip6tnl = { }; + gboolean gracefully_skip = FALSE; + + if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "ip6gre0")) { + /* Seems that the ip6_tunnel module is not loaded... try to load it. */ + gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip6_gre", NULL) != 0; + } + + lnk_ip6tnl.local = *nmtst_inet6_from_string ("fd01::42"); + lnk_ip6tnl.remote = *nmtst_inet6_from_string ("fd01::aaaa"); + lnk_ip6tnl.parent_ifindex = ifindex_parent; + lnk_ip6tnl.tclass = 21; + lnk_ip6tnl.flow_label = 1338; + lnk_ip6tnl.is_gre = TRUE; + + if (!nmtstp_link_ip6gre_add (NULL, ext, DEVICE_NAME, &lnk_ip6tnl)) { + if (gracefully_skip) { + g_test_skip ("Cannot create ip6gre tunnel because of missing ip6_gre module (modprobe ip6_gre)"); + goto out_delete_parent; + } + g_error ("Failed adding IP6GRE tunnel"); + } + break; + } + case NM_LINK_TYPE_IP6GRETAP: { + NMPlatformLnkIp6Tnl lnk_ip6tnl = { }; + gboolean gracefully_skip = FALSE; + + if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "ip6gre0")) { + /* Seems that the ip6_tunnel module is not loaded... try to load it. */ + gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip6_gre", NULL) != 0; + } + + lnk_ip6tnl.local = *nmtst_inet6_from_string ("fe80::abcd"); + lnk_ip6tnl.remote = *nmtst_inet6_from_string ("fc01::bbbb"); + lnk_ip6tnl.parent_ifindex = ifindex_parent; + lnk_ip6tnl.ttl = 10; + lnk_ip6tnl.tclass = 22; + lnk_ip6tnl.flow_label = 1339; + lnk_ip6tnl.is_gre = TRUE; + lnk_ip6tnl.is_tap = TRUE; + + if (!nmtstp_link_ip6gre_add (NULL, ext, DEVICE_NAME, &lnk_ip6tnl)) { + if (gracefully_skip) { + g_test_skip ("Cannot create ip6gretap tunnel because of missing ip6_gre module (modprobe ip6_gre)"); + goto out_delete_parent; + } + g_error ("Failed adding IP6GRETAP tunnel"); + } + break; + } case NM_LINK_TYPE_MACVLAN: { NMPlatformLnkMacvlan lnk_macvlan = { }; const NMPlatformLink *dummy; @@ -970,16 +1048,15 @@ test_software_detect (gconstpointer user_data) const NMPlatformLnkGre *plnk = &lnk->lnk_gre; g_assert (plnk == nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, ifindex, NULL)); - g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); - g_assert_cmpint (plnk->input_flags, ==, 0); - g_assert_cmpint (plnk->output_flags, ==, 0); - g_assert_cmpint (plnk->input_key, ==, 0); - g_assert_cmpint (plnk->output_key, ==, 0); - nmtst_assert_ip4_address (plnk->local, "192.168.233.204"); - nmtst_assert_ip4_address (plnk->remote, "172.168.10.25"); - g_assert_cmpint (plnk->ttl, ==, 174); - g_assert_cmpint (plnk->tos, ==, 37); - g_assert_cmpint (plnk->path_mtu_discovery, ==, TRUE); + g_assert (nm_platform_lnk_gre_cmp (plnk, &lnk_gre) == 0); + + break; + } + case NM_LINK_TYPE_GRETAP: { + const NMPlatformLnkGre *plnk = &lnk->lnk_gre; + + g_assert (plnk == nm_platform_link_get_lnk_gretap (NM_PLATFORM_GET, ifindex, NULL)); + g_assert (nm_platform_lnk_gre_cmp (plnk, &lnk_gre) == 0); break; } case NM_LINK_TYPE_IP6TNL: { @@ -1012,6 +1089,33 @@ test_software_detect (gconstpointer user_data) } break; } + case NM_LINK_TYPE_IP6GRE: { + const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl; + + g_assert (plnk == nm_platform_link_get_lnk_ip6gre (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); + nmtst_assert_ip6_address (&plnk->local, "fd01::42"); + nmtst_assert_ip6_address (&plnk->remote, "fd01::aaaa"); + g_assert_cmpint (plnk->tclass, ==, 21); + g_assert_cmpint (plnk->flow_label, ==, 1338); + g_assert_cmpint (plnk->is_gre, ==, TRUE); + g_assert_cmpint (plnk->is_tap, ==, FALSE); + break; + } + case NM_LINK_TYPE_IP6GRETAP: { + const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl; + + g_assert (plnk == nm_platform_link_get_lnk_ip6gretap (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); + nmtst_assert_ip6_address (&plnk->local, "fe80::abcd"); + nmtst_assert_ip6_address (&plnk->remote, "fc01::bbbb"); + g_assert_cmpint (plnk->ttl, ==, 10); + g_assert_cmpint (plnk->tclass, ==, 22); + g_assert_cmpint (plnk->flow_label, ==, 1339); + g_assert_cmpint (plnk->is_gre, ==, TRUE); + g_assert_cmpint (plnk->is_tap, ==, TRUE); + break; + } case NM_LINK_TYPE_IPIP: { const NMPlatformLnkIpIp *plnk = &lnk->lnk_ipip; @@ -1732,7 +1836,7 @@ test_create_many_links_do (guint n_devices) char name[64]; const NMPlatformLink *pllink; gs_unref_array GArray *ifindexes = g_array_sized_new (FALSE, FALSE, sizeof (int), n_devices); - const gint EX = ((int) (nmtst_get_rand_int () % 4)) - 1; + const int EX = ((int) (nmtst_get_rand_int () % 4)) - 1; g_assert (EX >= -1 && EX <= 2); @@ -2519,7 +2623,9 @@ test_sysctl_rename (void) case 0: { gs_free char *c = NULL; - if (nm_utils_file_get_contents (dirfd, "ifindex", 1*1024*1024, &c, NULL, NULL) < 0) + if (nm_utils_file_get_contents (dirfd, "ifindex", 1*1024*1024, + NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, + &c, NULL, NULL) < 0) g_assert_not_reached(); g_assert_cmpint (ifindex[0], ==, (int) _nm_utils_ascii_str_to_int64 (c, 10, 0, G_MAXINT, -1)); break; @@ -2583,7 +2689,9 @@ test_sysctl_netns_switch (void) { gs_free char *c = NULL; - if (nm_utils_file_get_contents (dirfd, "ifindex", 0, &c, NULL, NULL) < 0) + if (nm_utils_file_get_contents (dirfd, "ifindex", 0, + NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, + &c, NULL, NULL) < 0) g_assert_not_reached(); g_assert_cmpint (ifindex, ==, (int) _nm_utils_ascii_str_to_int64 (c, 10, 0, G_MAXINT, -1)); } @@ -2595,7 +2703,11 @@ test_sysctl_netns_switch (void) { gs_free char *c = NULL; - if (nm_utils_file_get_contents (-1, nm_sprintf_bufa (100, "/sys/class/net/%s/ifindex", IFNAME), 0, &c, NULL, NULL) < 0) + if (nm_utils_file_get_contents (-1, + nm_sprintf_bufa (100, "/sys/class/net/%s/ifindex", IFNAME), + 0, + NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, + &c, NULL, NULL) < 0) ifindex_tmp = -1; else ifindex_tmp = _nm_utils_ascii_str_to_int64 (c, 10, 0, G_MAXINT, -2); @@ -2610,6 +2722,102 @@ test_sysctl_netns_switch (void) /*****************************************************************************/ +static void +ethtool_features_dump (const NMEthtoolFeatureStates *features) +{ + guint i, j; + + g_assert (features); + + _LOGT (">>> %u features (%u ss-features)", features->n_states, features->n_ss_features); + + for (i = 0; i < features->n_states; i++) { + const NMEthtoolFeatureState *s = &features->states_list[i]; + + _LOGT (">>> feature-list[%3u]: %3d = %-32s (%3u) | %s %s %s %s", + i, + (int) s->info->ethtool_id, + s->info->kernel_names[s->idx_kernel_name], + s->idx_ss_features, + s->active ? "ACT" : "act", + s->available ? "AVA" : "ava", + s->never_changed ? "NCH" : "nch", + s->requested ? "REQ" : "req"); + } + for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++) { + _LOGT (">>> feature-idx [%3u]: %-32s = %u features", + i + (guint) _NM_ETHTOOL_ID_FEATURE_FIRST, + nm_ethtool_data[i + _NM_ETHTOOL_ID_FEATURE_FIRST]->optname, + (guint) NM_PTRARRAY_LEN (features->states_indexed[i])); + for (j = 0; features->states_indexed[i] && features->states_indexed[i][j]; j++) { + const NMEthtoolFeatureState *s = features->states_indexed[i][j]; + + _LOGT (">>> %3u: %-32s | %s %s %s %s", + j, + s->info->kernel_names[s->idx_kernel_name], + s->active ? "ACT" : "act", + s->available ? "AVA" : "ava", + s->never_changed ? "NCH" : "nch", + s->requested ? "REQ" : "req"); + } + } +} + +static void +test_ethtool_features_get (void) +{ + gs_unref_ptrarray GPtrArray *gfree_keeper = g_ptr_array_new_with_free_func (g_free); + const int IFINDEX = 1; + guint i; + guint i_run; + + for (i_run = 0; i_run < 5; i_run++) { + NMEthtoolFeatureStates *features; + NMTernary *requested; + gboolean do_set = TRUE; + + requested = g_new (NMTernary, _NM_ETHTOOL_ID_FEATURE_NUM); + for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++) + requested[i] = NM_TERNARY_DEFAULT; + g_ptr_array_add (gfree_keeper, requested); + + if (i_run == 0) { + requested[NM_ETHTOOL_ID_FEATURE_RX] = NM_TERNARY_FALSE; + requested[NM_ETHTOOL_ID_FEATURE_TSO] = NM_TERNARY_FALSE; + requested[NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION] = NM_TERNARY_FALSE; + } else if (i_run == 1) + do_set = FALSE; + else if (i_run == 2) { + requested[NM_ETHTOOL_ID_FEATURE_TSO] = NM_TERNARY_FALSE; + requested[NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION] = NM_TERNARY_TRUE; + } else if (i_run == 3) + do_set = FALSE; + + _LOGT (">>> ethtool-features-get RUN %u (do-set=%s", i_run, do_set ? "set" : "reset"); + + features = nmp_utils_ethtool_get_features (IFINDEX); + g_ptr_array_add (gfree_keeper, features); + + ethtool_features_dump (features); + + if (_LOGT_ENABLED ()) { + int ignore; + + ignore = system ("ethtool -k lo"); + (void) ignore; + } + + if (!do_set) { + requested = gfree_keeper->pdata[i_run * 2 - 2]; + features = gfree_keeper->pdata[i_run * 2 - 1]; + } + + nmp_utils_ethtool_set_features (IFINDEX, features, requested, do_set); + } +} + +/*****************************************************************************/ + NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP; void @@ -2641,8 +2849,11 @@ _nmtstp_setup_tests (void) g_test_add_func ("/link/external", test_external); test_software_detect_add ("/link/software/detect/gre", NM_LINK_TYPE_GRE, 0); + test_software_detect_add ("/link/software/detect/gretap", NM_LINK_TYPE_GRETAP, 0); test_software_detect_add ("/link/software/detect/ip6tnl/0", NM_LINK_TYPE_IP6TNL, 0); test_software_detect_add ("/link/software/detect/ip6tnl/1", NM_LINK_TYPE_IP6TNL, 1); + test_software_detect_add ("/link/software/detect/ip6gre", NM_LINK_TYPE_IP6GRE, 0); + test_software_detect_add ("/link/software/detect/ip6gretap", NM_LINK_TYPE_IP6GRETAP, 0); test_software_detect_add ("/link/software/detect/ipip", NM_LINK_TYPE_IPIP, 0); test_software_detect_add ("/link/software/detect/macvlan", NM_LINK_TYPE_MACVLAN, 0); test_software_detect_add ("/link/software/detect/macvtap", NM_LINK_TYPE_MACVTAP, 0); @@ -2668,5 +2879,7 @@ _nmtstp_setup_tests (void) g_test_add_func ("/general/sysctl/rename", test_sysctl_rename); g_test_add_func ("/general/sysctl/netns-switch", test_sysctl_netns_switch); + + g_test_add_func ("/link/ethtool/features/get", test_ethtool_features_get); } } diff --git a/src/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/nm-wifi-utils-nl80211.c index 6c2ff3f5..b3bb2bb6 100644 --- a/src/platform/wifi/wifi-utils-nl80211.c +++ b/src/platform/wifi/nm-wifi-utils-nl80211.c @@ -15,14 +15,14 @@ * 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 - 2011 Red Hat, Inc. + * Copyright (C) 2005 - 2018 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. * Copyright (C) 2011 Intel Corporation. All rights reserved. */ #include "nm-default.h" -#include "wifi-utils-nl80211.h" +#include "nm-wifi-utils-nl80211.h" #include <errno.h> #include <string.h> @@ -32,7 +32,7 @@ #include <linux/nl80211.h> #include "platform/nm-netlink.h" -#include "wifi-utils-private.h" +#include "nm-wifi-utils-private.h" #include "platform/nm-platform.h" #include "platform/nm-platform-utils.h" #include "nm-utils.h" @@ -47,14 +47,20 @@ } G_STMT_END typedef struct { - WifiData parent; + NMWifiUtils parent; struct nl_sock *nl_sock; guint32 *freqs; int id; int num_freqs; int phy; bool can_wowlan:1; -} WifiDataNl80211; +} NMWifiUtilsNl80211; + +typedef struct { + NMWifiUtilsClass parent; +} NMWifiUtilsNl80211Class; + +G_DEFINE_TYPE (NMWifiUtilsNl80211, nm_wifi_utils_nl80211, NM_TYPE_WIFI_UTILS) static int ack_handler (struct nl_msg *msg, void *arg) @@ -97,7 +103,7 @@ nla_put_failure: } static struct nl_msg * -nl80211_alloc_msg (WifiDataNl80211 *nl80211, guint32 cmd, guint32 flags) +nl80211_alloc_msg (NMWifiUtilsNl80211 *nl80211, guint32 cmd, guint32 flags) { return _nl80211_alloc_msg (nl80211->id, nl80211->parent.ifindex, nl80211->phy, cmd, flags); } @@ -154,7 +160,7 @@ _nl80211_send_and_recv (struct nl_sock *nl_sock, } static int -nl80211_send_and_recv (WifiDataNl80211 *nl80211, +nl80211_send_and_recv (NMWifiUtilsNl80211 *nl80211, struct nl_msg *msg, int (*valid_handler) (struct nl_msg *, void *), void *valid_data) @@ -164,13 +170,11 @@ nl80211_send_and_recv (WifiDataNl80211 *nl80211, } static void -wifi_nl80211_deinit (WifiData *parent) +dispose (GObject *object) { - WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) parent; + NMWifiUtilsNl80211 *nl80211 = NM_WIFI_UTILS_NL80211 (object); - if (nl80211->nl_sock) - nl_socket_free (nl80211->nl_sock); - g_free (nl80211->freqs); + g_clear_pointer (&nl80211->freqs, g_free); } struct nl80211_iface_info { @@ -207,9 +211,9 @@ nl80211_iface_info_handler (struct nl_msg *msg, void *arg) } static NM80211Mode -wifi_nl80211_get_mode (WifiData *data) +wifi_nl80211_get_mode (NMWifiUtils *data) { - WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data; struct nl80211_iface_info iface_info = { .mode = NM_802_11_MODE_UNKNOWN, }; @@ -225,9 +229,9 @@ wifi_nl80211_get_mode (WifiData *data) } static gboolean -wifi_nl80211_set_mode (WifiData *data, const NM80211Mode mode) +wifi_nl80211_set_mode (NMWifiUtils *data, const NM80211Mode mode) { - WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data; nm_auto_nlmsg struct nl_msg *msg = NULL; int err; @@ -255,9 +259,9 @@ nla_put_failure: } static gboolean -wifi_nl80211_set_powersave (WifiData *data, guint32 powersave) +wifi_nl80211_set_powersave (NMWifiUtils *data, guint32 powersave) { - WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data; nm_auto_nlmsg struct nl_msg *msg = NULL; int err; @@ -271,10 +275,64 @@ nla_put_failure: return FALSE; } +static int +nl80211_get_wake_on_wlan_handler (struct nl_msg *msg, void *arg) +{ + NMSettingWirelessWakeOnWLan *wowl = arg; + struct nlattr *attrs[NL80211_ATTR_MAX + 1]; + struct nlattr *trig[NUM_NL80211_WOWLAN_TRIG]; + struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); + + nla_parse (attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + if (!attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) + return NL_SKIP; + + nla_parse (trig, MAX_NL80211_WOWLAN_TRIG, + nla_data (attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), + nla_len (attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), + NULL); + + *wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE; + if (trig[NL80211_WOWLAN_TRIG_ANY]) + *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY; + if (trig[NL80211_WOWLAN_TRIG_DISCONNECT]) + *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT; + if (trig[NL80211_WOWLAN_TRIG_MAGIC_PKT]) + *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC; + if (trig[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) + *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE; + if (trig[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) + *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST; + if (trig[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) + *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE; + if (trig[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) + *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE; + if (trig[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) + *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP; + + return NL_SKIP; +} + +static NMSettingWirelessWakeOnWLan +wifi_nl80211_get_wake_on_wlan (NMWifiUtils *data) +{ + NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data; + NMSettingWirelessWakeOnWLan wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; + nm_auto_nlmsg struct nl_msg *msg = NULL; + + msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_WOWLAN, 0); + + nl80211_send_and_recv (nl80211, msg, nl80211_get_wake_on_wlan_handler, &wowl); + + return wowl; +} + static gboolean -wifi_nl80211_set_wake_on_wlan (WifiData *data, NMSettingWirelessWakeOnWLan wowl) +wifi_nl80211_set_wake_on_wlan (NMWifiUtils *data, NMSettingWirelessWakeOnWLan wowl) { - WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data; nm_auto_nlmsg struct nl_msg *msg = NULL; struct nlattr *triggers; int err; @@ -282,11 +340,11 @@ wifi_nl80211_set_wake_on_wlan (WifiData *data, NMSettingWirelessWakeOnWLan wowl) if (wowl == NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) return TRUE; - msg = nl80211_alloc_msg(nl80211, NL80211_CMD_SET_WOWLAN, 0); + msg = nl80211_alloc_msg (nl80211, NL80211_CMD_SET_WOWLAN, 0); if (!msg) return FALSE; - triggers = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); + triggers = nla_nest_start (msg, NL80211_ATTR_WOWLAN_TRIGGERS); if (NM_FLAGS_HAS (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY)) NLA_PUT_FLAG (msg, NL80211_WOWLAN_TRIG_ANY); @@ -306,7 +364,8 @@ wifi_nl80211_set_wake_on_wlan (WifiData *data, NMSettingWirelessWakeOnWLan wowl) nla_nest_end(msg, triggers); err = nl80211_send_and_recv (nl80211, msg, NULL, NULL); - return err ? FALSE : TRUE; + + return err >= 0; nla_put_failure: return FALSE; @@ -432,7 +491,7 @@ nl80211_bss_dump_handler (struct nl_msg *msg, void *arg) } static void -nl80211_get_bss_info (WifiDataNl80211 *nl80211, +nl80211_get_bss_info (NMWifiUtilsNl80211 *nl80211, struct nl80211_bss_info *bss_info) { nm_auto_nlmsg struct nl_msg *msg = NULL; @@ -445,9 +504,9 @@ nl80211_get_bss_info (WifiDataNl80211 *nl80211, } static guint32 -wifi_nl80211_get_freq (WifiData *data) +wifi_nl80211_get_freq (NMWifiUtils *data) { - WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data; struct nl80211_bss_info bss_info; nl80211_get_bss_info (nl80211, &bss_info); @@ -456,9 +515,9 @@ wifi_nl80211_get_freq (WifiData *data) } static guint32 -wifi_nl80211_find_freq (WifiData *data, const guint32 *freqs) +wifi_nl80211_find_freq (NMWifiUtils *data, const guint32 *freqs) { - WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data; int i; for (i = 0; i < nl80211->num_freqs; i++) { @@ -472,9 +531,9 @@ wifi_nl80211_find_freq (WifiData *data, const guint32 *freqs) } static gboolean -wifi_nl80211_get_bssid (WifiData *data, guint8 *out_bssid) +wifi_nl80211_get_bssid (NMWifiUtils *data, guint8 *out_bssid) { - WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data; struct nl80211_bss_info bss_info; nl80211_get_bss_info (nl80211, &bss_info); @@ -556,7 +615,7 @@ nl80211_station_handler (struct nl_msg *msg, void *arg) } static void -nl80211_get_ap_info (WifiDataNl80211 *nl80211, +nl80211_get_ap_info (NMWifiUtilsNl80211 *nl80211, struct nl80211_station_info *sta_info) { nm_auto_nlmsg struct nl_msg *msg = NULL; @@ -586,9 +645,9 @@ nla_put_failure: } static guint32 -wifi_nl80211_get_rate (WifiData *data) +wifi_nl80211_get_rate (NMWifiUtils *data) { - WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data; struct nl80211_station_info sta_info; nl80211_get_ap_info (nl80211, &sta_info); @@ -597,9 +656,9 @@ wifi_nl80211_get_rate (WifiData *data) } static int -wifi_nl80211_get_qual (WifiData *data) +wifi_nl80211_get_qual (NMWifiUtils *data) { - WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data; struct nl80211_station_info sta_info; nl80211_get_ap_info (nl80211, &sta_info); @@ -607,9 +666,9 @@ wifi_nl80211_get_qual (WifiData *data) } static gboolean -wifi_nl80211_indicate_addressing_running (WifiData *data, gboolean running) +wifi_nl80211_indicate_addressing_running (NMWifiUtils *data, gboolean running) { - WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + NMWifiUtilsNl80211 *nl80211 = (NMWifiUtilsNl80211 *) data; nm_auto_nlmsg struct nl_msg *msg = NULL; int err; @@ -638,44 +697,6 @@ nla_put_failure: return FALSE; } -struct nl80211_wowlan_info { - gboolean enabled; -}; - -static int -nl80211_wowlan_handler (struct nl_msg *msg, void *arg) -{ - struct nlattr *tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); - struct nl80211_wowlan_info *info = arg; - - info->enabled = FALSE; - - if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), - genlmsg_attrlen (gnlh, 0), NULL) < 0) - return NL_SKIP; - - if (tb[NL80211_ATTR_WOWLAN_TRIGGERS]) - info->enabled = TRUE; - - return NL_SKIP; -} - -static gboolean -wifi_nl80211_get_wowlan (WifiData *data) -{ - WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; - struct nl80211_wowlan_info info; - - if (!nl80211->can_wowlan) - return FALSE; - - msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_WOWLAN, 0); - nl80211_send_and_recv (nl80211, msg, nl80211_wowlan_handler, &info); - return info.enabled; -} - struct nl80211_device_info { int phy; guint32 *freqs; @@ -879,48 +900,58 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) return NL_SKIP; } -WifiData * -wifi_nl80211_init (int ifindex) +static void +nm_wifi_utils_nl80211_init (NMWifiUtilsNl80211 *self) { - static const WifiDataClass klass = { - .struct_size = sizeof (WifiDataNl80211), - .get_mode = wifi_nl80211_get_mode, - .set_mode = wifi_nl80211_set_mode, - .set_powersave = wifi_nl80211_set_powersave, - .set_wake_on_wlan = wifi_nl80211_set_wake_on_wlan, - .get_freq = wifi_nl80211_get_freq, - .find_freq = wifi_nl80211_find_freq, - .get_bssid = wifi_nl80211_get_bssid, - .get_rate = wifi_nl80211_get_rate, - .get_qual = wifi_nl80211_get_qual, - .get_wowlan = wifi_nl80211_get_wowlan, - .indicate_addressing_running = wifi_nl80211_indicate_addressing_running, - .deinit = wifi_nl80211_deinit, - }; - WifiDataNl80211 *nl80211; +} + +static void +nm_wifi_utils_nl80211_class_init (NMWifiUtilsNl80211Class *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMWifiUtilsClass *wifi_utils_class = NM_WIFI_UTILS_CLASS (klass); + + object_class->dispose = dispose; + + wifi_utils_class->get_mode = wifi_nl80211_get_mode; + wifi_utils_class->set_mode = wifi_nl80211_set_mode; + wifi_utils_class->set_powersave = wifi_nl80211_set_powersave; + wifi_utils_class->get_wake_on_wlan = wifi_nl80211_get_wake_on_wlan, + wifi_utils_class->set_wake_on_wlan = wifi_nl80211_set_wake_on_wlan, + wifi_utils_class->get_freq = wifi_nl80211_get_freq; + wifi_utils_class->find_freq = wifi_nl80211_find_freq; + wifi_utils_class->get_bssid = wifi_nl80211_get_bssid; + wifi_utils_class->get_rate = wifi_nl80211_get_rate; + wifi_utils_class->get_qual = wifi_nl80211_get_qual; + wifi_utils_class->indicate_addressing_running = wifi_nl80211_indicate_addressing_running; +} + +NMWifiUtils * +nm_wifi_utils_nl80211_new (int ifindex, struct nl_sock *genl) +{ + gs_unref_object NMWifiUtilsNl80211 *nl80211 = NULL; nm_auto_nlmsg struct nl_msg *msg = NULL; struct nl80211_device_info device_info = {}; char ifname[IFNAMSIZ]; + if (!genl) + return NULL; + if (!nmp_utils_if_indextoname (ifindex, ifname)) { _LOGW (LOGD_PLATFORM | LOGD_WIFI, "can't determine interface name for ifindex %d", ifindex); nm_sprintf_buf (ifname, "if %d", ifindex); } - nl80211 = wifi_data_new (&klass, ifindex); - - nl80211->nl_sock = nl_socket_alloc (); - if (nl80211->nl_sock == NULL) - goto error; + nl80211 = g_object_new (NM_TYPE_WIFI_UTILS_NL80211, NULL); - if (nl_connect (nl80211->nl_sock, NETLINK_GENERIC)) - goto error; + nl80211->parent.ifindex = ifindex; + nl80211->nl_sock = genl; nl80211->id = genl_ctrl_resolve (nl80211->nl_sock, "nl80211"); if (nl80211->id < 0) { _LOGD (LOGD_WIFI, "genl_ctrl_resolve: failed to resolve \"nl80211\""); - goto error; + return NULL; } nl80211->phy = -1; @@ -932,42 +963,42 @@ wifi_nl80211_init (int ifindex) _LOGD (LOGD_PLATFORM | LOGD_WIFI, "(%s): NL80211_CMD_GET_WIPHY request failed", ifname); - goto error; + return NULL; } if (!device_info.success) { _LOGD (LOGD_PLATFORM | LOGD_WIFI, "(%s): NL80211_CMD_GET_WIPHY request indicated failure", ifname); - goto error; + return NULL; } if (!device_info.supported) { _LOGD (LOGD_PLATFORM | LOGD_WIFI, "(%s): driver does not fully support nl80211, falling back to WEXT", ifname); - goto error; + return NULL; } if (!device_info.can_scan_ssid) { _LOGE (LOGD_PLATFORM | LOGD_WIFI, "(%s): driver does not support SSID scans", ifname); - goto error; + return NULL; } if (device_info.num_freqs == 0 || device_info.freqs == NULL) { nm_log_err (LOGD_PLATFORM | LOGD_WIFI, "(%s): driver reports no supported frequencies", ifname); - goto error; + return NULL; } if (device_info.caps == 0) { _LOGE (LOGD_PLATFORM | LOGD_WIFI, "(%s): driver doesn't report support of any encryption", ifname); - goto error; + return NULL; } nl80211->phy = device_info.phy; @@ -979,10 +1010,5 @@ wifi_nl80211_init (int ifindex) _LOGI (LOGD_PLATFORM | LOGD_WIFI, "(%s): using nl80211 for WiFi device control", ifname); - return (WifiData *) nl80211; - -error: - wifi_utils_unref ((WifiData *) nl80211); - return NULL; + return (NMWifiUtils *) g_steal_pointer (&nl80211); } - diff --git a/src/platform/wifi/wifi-utils-nl80211.h b/src/platform/wifi/nm-wifi-utils-nl80211.h index aff24555..27f67697 100644 --- a/src/platform/wifi/wifi-utils-nl80211.h +++ b/src/platform/wifi/nm-wifi-utils-nl80211.h @@ -16,13 +16,24 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2011 Intel Corporation. All rights reserved. + * Copyright (C) 2018 Red Hat, Inc. */ #ifndef __WIFI_UTILS_NL80211_H__ #define __WIFI_UTILS_NL80211_H__ -#include "wifi-utils.h" +#include "nm-wifi-utils.h" +#include "platform/nm-netlink.h" -WifiData *wifi_nl80211_init (int ifindex); +#define NM_TYPE_WIFI_UTILS_NL80211 (nm_wifi_utils_nl80211_get_type ()) +#define NM_WIFI_UTILS_NL80211(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WIFI_UTILS_NL80211, NMWifiUtilsNl80211)) +#define NM_WIFI_UTILS_NL80211_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_WIFI_UTILS_NL80211, NMWifiUtilsNl80211Class)) +#define NM_IS_WIFI_UTILS_NL80211(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_WIFI_UTILS_NL80211)) +#define NM_IS_WIFI_UTILS_NL80211_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_WIFI_UTILS_NL80211)) +#define NM_WIFI_UTILS_NL80211_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_WIFI_UTILS_NL80211, NMWifiUtilsNl80211Class)) + +GType nm_wifi_utils_nl80211_get_type (void); + +NMWifiUtils *nm_wifi_utils_nl80211_new (int ifindex, struct nl_sock *genl); #endif /* __WIFI_UTILS_NL80211_H__ */ diff --git a/src/platform/wifi/wifi-utils-private.h b/src/platform/wifi/nm-wifi-utils-private.h index 627108cb..bcbc1c51 100644 --- a/src/platform/wifi/wifi-utils-private.h +++ b/src/platform/wifi/nm-wifi-utils-private.h @@ -15,67 +15,65 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2011 Red Hat, Inc. + * Copyright (C) 2011 - 2018 Red Hat, Inc. */ #ifndef __WIFI_UTILS_PRIVATE_H__ #define __WIFI_UTILS_PRIVATE_H__ #include "nm-dbus-interface.h" -#include "wifi-utils.h" +#include "nm-wifi-utils.h" typedef struct { - gsize struct_size; + GObjectClass parent; - NM80211Mode (*get_mode) (WifiData *data); + NM80211Mode (*get_mode) (NMWifiUtils *data); - gboolean (*set_mode) (WifiData *data, const NM80211Mode mode); + gboolean (*set_mode) (NMWifiUtils *data, const NM80211Mode mode); /* Set power saving mode on an interface */ - gboolean (*set_powersave) (WifiData *data, guint32 powersave); + gboolean (*set_powersave) (NMWifiUtils *data, guint32 powersave); + + /* Get WakeOnWLAN configuration on an interface */ + NMSettingWirelessWakeOnWLan (*get_wake_on_wlan) (NMWifiUtils *data); /* Set WakeOnWLAN mode on an interface */ - gboolean (*set_wake_on_wlan) (WifiData *data, NMSettingWirelessWakeOnWLan wowl); + gboolean (*set_wake_on_wlan) (NMWifiUtils *data, NMSettingWirelessWakeOnWLan wowl); /* Return current frequency in MHz (really associated BSS frequency) */ - guint32 (*get_freq) (WifiData *data); + guint32 (*get_freq) (NMWifiUtils *data); /* Return first supported frequency in the zero-terminated list */ - guint32 (*find_freq) (WifiData *data, const guint32 *freqs); + guint32 (*find_freq) (NMWifiUtils *data, const guint32 *freqs); /* Return current bitrate in Kbps */ - guint32 (*get_rate) (WifiData *data); + guint32 (*get_rate) (NMWifiUtils *data); - gboolean (*get_bssid) (WifiData *data, guint8 *out_bssid); + gboolean (*get_bssid) (NMWifiUtils *data, guint8 *out_bssid); /* Return a signal strength percentage 0 - 100% for the current BSSID; * return -1 on errors or if not associated. */ - int (*get_qual) (WifiData *data); - - void (*deinit) (WifiData *data); - - gboolean (*get_wowlan) (WifiData *data); + int (*get_qual) (NMWifiUtils *data); /* OLPC Mesh-only functions */ - guint32 (*get_mesh_channel) (WifiData *data); + guint32 (*get_mesh_channel) (NMWifiUtils *data); /* channel == 0 means "auto channel" */ - gboolean (*set_mesh_channel) (WifiData *data, guint32 channel); + gboolean (*set_mesh_channel) (NMWifiUtils *data, guint32 channel); /* ssid == NULL means "auto SSID" */ - gboolean (*set_mesh_ssid) (WifiData *data, const guint8 *ssid, gsize len); + gboolean (*set_mesh_ssid) (NMWifiUtils *data, const guint8 *ssid, gsize len); - gboolean (*indicate_addressing_running) (WifiData *data, gboolean running); -} WifiDataClass; + gboolean (*indicate_addressing_running) (NMWifiUtils *data, gboolean running); +} NMWifiUtilsClass; + +struct NMWifiUtils { + GObject parent; -struct WifiData { - const WifiDataClass *klass; int ifindex; NMDeviceWifiCapabilities caps; }; -gpointer wifi_data_new (const WifiDataClass *klass, int ifindex); - #endif /* __WIFI_UTILS_PRIVATE_H__ */ diff --git a/src/platform/wifi/wifi-utils-wext.c b/src/platform/wifi/nm-wifi-utils-wext.c index c8744f79..e52ae5a3 100644 --- a/src/platform/wifi/wifi-utils-wext.c +++ b/src/platform/wifi/nm-wifi-utils-wext.c @@ -15,13 +15,13 @@ * 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 - 2011 Red Hat, Inc. + * Copyright (C) 2005 - 2018 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. */ #include "nm-default.h" -#include "wifi-utils-wext.h" +#include "nm-wifi-utils-wext.h" #include <errno.h> #include <string.h> @@ -38,17 +38,24 @@ #include <sys/socket.h> #include <linux/wireless.h> -#include "wifi-utils-private.h" +#include "nm-wifi-utils-private.h" #include "nm-utils.h" #include "platform/nm-platform-utils.h" +#include "nm-core-internal.h" typedef struct { - WifiData parent; + NMWifiUtils parent; int fd; struct iw_quality max_qual; gint8 num_freqs; guint32 freqs[IW_MAX_FREQUENCIES]; -} WifiDataWext; +} NMWifiUtilsWext; + +typedef struct { + NMWifiUtilsClass parent; +} NMWifiUtilsWextClass; + +G_DEFINE_TYPE (NMWifiUtilsWext, nm_wifi_utils_wext, NM_TYPE_WIFI_UTILS) /* Until a new wireless-tools comes out that has the defs and the structure, * need to copy them here. @@ -94,11 +101,11 @@ iw_freq_to_uint32 (const struct iw_freq *freq) } static void -wifi_wext_deinit (WifiData *parent) +dispose (GObject *object) { - WifiDataWext *wext = (WifiDataWext *) parent; + NMWifiUtilsWext *wext = NM_WIFI_UTILS_WEXT (object); - nm_close (wext->fd); + wext->fd = nm_close (wext->fd); } static gboolean @@ -118,9 +125,9 @@ get_ifname (int ifindex, char *buffer, const char *op) } static NM80211Mode -wifi_wext_get_mode_ifname (WifiData *data, const char *ifname) +wifi_wext_get_mode_ifname (NMWifiUtils *data, const char *ifname) { - WifiDataWext *wext = (WifiDataWext *) data; + NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); @@ -150,7 +157,7 @@ wifi_wext_get_mode_ifname (WifiData *data, const char *ifname) } static NM80211Mode -wifi_wext_get_mode (WifiData *data) +wifi_wext_get_mode (NMWifiUtils *data) { char ifname[IFNAMSIZ]; @@ -161,9 +168,9 @@ wifi_wext_get_mode (WifiData *data) } static gboolean -wifi_wext_set_mode (WifiData *data, const NM80211Mode mode) +wifi_wext_set_mode (NMWifiUtils *data, const NM80211Mode mode) { - WifiDataWext *wext = (WifiDataWext *) data; + NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; struct iwreq wrq; char ifname[IFNAMSIZ]; @@ -203,9 +210,9 @@ wifi_wext_set_mode (WifiData *data, const NM80211Mode mode) } static gboolean -wifi_wext_set_powersave (WifiData *data, guint32 powersave) +wifi_wext_set_powersave (NMWifiUtils *data, guint32 powersave) { - WifiDataWext *wext = (WifiDataWext *) data; + NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; struct iwreq wrq; char ifname[IFNAMSIZ]; @@ -232,9 +239,9 @@ wifi_wext_set_powersave (WifiData *data, guint32 powersave) } static guint32 -wifi_wext_get_freq (WifiData *data) +wifi_wext_get_freq (NMWifiUtils *data) { - WifiDataWext *wext = (WifiDataWext *) data; + NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; struct iwreq wrq; char ifname[IFNAMSIZ]; @@ -254,9 +261,9 @@ wifi_wext_get_freq (WifiData *data) } static guint32 -wifi_wext_find_freq (WifiData *data, const guint32 *freqs) +wifi_wext_find_freq (NMWifiUtils *data, const guint32 *freqs) { - WifiDataWext *wext = (WifiDataWext *) data; + NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; int i; for (i = 0; i < wext->num_freqs; i++) { @@ -270,9 +277,9 @@ wifi_wext_find_freq (WifiData *data, const guint32 *freqs) } static gboolean -wifi_wext_get_bssid (WifiData *data, guint8 *out_bssid) +wifi_wext_get_bssid (NMWifiUtils *data, guint8 *out_bssid) { - WifiDataWext *wext = (WifiDataWext *) data; + NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; struct iwreq wrq; char ifname[IFNAMSIZ]; @@ -292,9 +299,9 @@ wifi_wext_get_bssid (WifiData *data, guint8 *out_bssid) } static guint32 -wifi_wext_get_rate (WifiData *data) +wifi_wext_get_rate (NMWifiUtils *data) { - WifiDataWext *wext = (WifiDataWext *) data; + NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; struct iwreq wrq; int err; char ifname[IFNAMSIZ]; @@ -403,9 +410,9 @@ wext_qual_to_percent (const struct iw_quality *qual, } static int -wifi_wext_get_qual (WifiData *data) +wifi_wext_get_qual (NMWifiUtils *data) { - WifiDataWext *wext = (WifiDataWext *) data; + NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; struct iwreq wrq; struct iw_statistics stats; char ifname[IFNAMSIZ]; @@ -433,13 +440,13 @@ wifi_wext_get_qual (WifiData *data) /* OLPC Mesh-only functions */ static guint32 -wifi_wext_get_mesh_channel (WifiData *data) +wifi_wext_get_mesh_channel (NMWifiUtils *data) { - WifiDataWext *wext = (WifiDataWext *) data; + NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; guint32 freq; int i; - freq = wifi_utils_get_freq (data); + freq = nm_wifi_utils_get_freq (data); for (i = 0; i < wext->num_freqs; i++) { if (freq == wext->freqs[i]) return i + 1; @@ -448,9 +455,9 @@ wifi_wext_get_mesh_channel (WifiData *data) } static gboolean -wifi_wext_set_mesh_channel (WifiData *data, guint32 channel) +wifi_wext_set_mesh_channel (NMWifiUtils *data, guint32 channel) { - WifiDataWext *wext = (WifiDataWext *) data; + NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; struct iwreq wrq; char ifname[IFNAMSIZ]; @@ -477,9 +484,9 @@ wifi_wext_set_mesh_channel (WifiData *data, guint32 channel) } static gboolean -wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len) +wifi_wext_set_mesh_ssid (NMWifiUtils *data, const guint8 *ssid, gsize len) { - WifiDataWext *wext = (WifiDataWext *) data; + NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; struct iwreq wrq; char buf[IW_ESSID_MAX_SIZE + 1]; char ifname[IFNAMSIZ]; @@ -500,11 +507,13 @@ wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len) return TRUE; if (errno != ENODEV) { + gs_free char *ssid_str = NULL; + errsv = errno; _LOGE (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC, "(%s): error setting SSID to '%s': %s", ifname, - ssid ? nm_utils_escape_ssid (ssid, len) : "(null)", + (ssid_str = _nm_utils_ssid_to_string_arr (ssid, len)), strerror (errsv)); } @@ -514,7 +523,7 @@ wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len) /*****************************************************************************/ static gboolean -wext_can_scan_ifname (WifiDataWext *wext, const char *ifname) +wext_can_scan_ifname (NMWifiUtilsWext *wext, const char *ifname) { struct iwreq wrq; @@ -528,7 +537,7 @@ wext_can_scan_ifname (WifiDataWext *wext, const char *ifname) } static gboolean -wext_get_range_ifname (WifiDataWext *wext, +wext_get_range_ifname (NMWifiUtilsWext *wext, const char *ifname, struct iw_range *range, guint32 *response_len) @@ -577,7 +586,7 @@ wext_get_range_ifname (WifiDataWext *wext, NM_WIFI_DEVICE_CAP_RSN) static guint32 -wext_get_caps (WifiDataWext *wext, const char *ifname, struct iw_range *range) +wext_get_caps (NMWifiUtilsWext *wext, const char *ifname, struct iw_range *range) { guint32 caps = NM_WIFI_DEVICE_CAP_NONE; @@ -626,25 +635,38 @@ wext_get_caps (WifiDataWext *wext, const char *ifname, struct iw_range *range) return caps; } -WifiData * -wifi_wext_init (int ifindex, gboolean check_scan) +/*****************************************************************************/ + +static void +nm_wifi_utils_wext_init (NMWifiUtilsWext *self) +{ +} + +static void +nm_wifi_utils_wext_class_init (NMWifiUtilsWextClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMWifiUtilsClass *wifi_utils_class = NM_WIFI_UTILS_CLASS (klass); + + object_class->dispose = dispose; + + wifi_utils_class->get_mode = wifi_wext_get_mode; + wifi_utils_class->set_mode = wifi_wext_set_mode; + wifi_utils_class->set_powersave = wifi_wext_set_powersave; + wifi_utils_class->get_freq = wifi_wext_get_freq; + wifi_utils_class->find_freq = wifi_wext_find_freq; + wifi_utils_class->get_bssid = wifi_wext_get_bssid; + wifi_utils_class->get_rate = wifi_wext_get_rate; + wifi_utils_class->get_qual = wifi_wext_get_qual; + wifi_utils_class->get_mesh_channel = wifi_wext_get_mesh_channel; + wifi_utils_class->set_mesh_channel = wifi_wext_set_mesh_channel; + wifi_utils_class->set_mesh_ssid = wifi_wext_set_mesh_ssid; +} + +NMWifiUtils * +nm_wifi_utils_wext_new (int ifindex, gboolean check_scan) { - static const WifiDataClass klass = { - .struct_size = sizeof (WifiDataWext), - .get_mode = wifi_wext_get_mode, - .set_mode = wifi_wext_set_mode, - .set_powersave = wifi_wext_set_powersave, - .get_freq = wifi_wext_get_freq, - .find_freq = wifi_wext_find_freq, - .get_bssid = wifi_wext_get_bssid, - .get_rate = wifi_wext_get_rate, - .get_qual = wifi_wext_get_qual, - .deinit = wifi_wext_deinit, - .get_mesh_channel = wifi_wext_get_mesh_channel, - .set_mesh_channel = wifi_wext_set_mesh_channel, - .set_mesh_ssid = wifi_wext_set_mesh_ssid, - }; - WifiDataWext *wext; + NMWifiUtilsWext *wext; struct iw_range range; guint32 response_len = 0; struct iw_range_with_scan_capa *scan_capa_range; @@ -658,8 +680,9 @@ wifi_wext_init (int ifindex, gboolean check_scan) return NULL; } - wext = wifi_data_new (&klass, ifindex); + wext = g_object_new (NM_TYPE_WIFI_UTILS_WEXT, NULL); + wext->parent.ifindex = ifindex; wext->fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (wext->fd < 0) goto error; @@ -731,15 +754,15 @@ wifi_wext_init (int ifindex, gboolean check_scan) "(%s): using WEXT for WiFi device control", ifname); - return (WifiData *) wext; + return (NMWifiUtils *) wext; error: - wifi_utils_unref ((WifiData *) wext); + g_object_unref (wext); return NULL; } gboolean -wifi_wext_is_wifi (const char *iface) +nm_wifi_utils_wext_is_wifi (const char *iface) { int fd; struct iwreq iwr; diff --git a/src/platform/wifi/wifi-utils-wext.h b/src/platform/wifi/nm-wifi-utils-wext.h index 3ef5a173..44b11afb 100644 --- a/src/platform/wifi/wifi-utils-wext.h +++ b/src/platform/wifi/nm-wifi-utils-wext.h @@ -15,16 +15,25 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2011 Red Hat, Inc. + * Copyright (C) 2011 - 2018 Red Hat, Inc. */ #ifndef __WIFI_UTILS_WEXT_H__ #define __WIFI_UTILS_WEXT_H__ -#include "wifi-utils.h" +#include "nm-wifi-utils.h" -WifiData *wifi_wext_init (int ifindex, gboolean check_scan); +#define NM_TYPE_WIFI_UTILS_WEXT (nm_wifi_utils_wext_get_type ()) +#define NM_WIFI_UTILS_WEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WIFI_UTILS_WEXT, NMWifiUtilsWext)) +#define NM_WIFI_UTILS_WEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_WIFI_UTILS_WEXT, NMWifiUtilsWextClass)) +#define NM_IS_WIFI_UTILS_WEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_WIFI_UTILS_WEXT)) +#define NM_IS_WIFI_UTILS_WEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_WIFI_UTILS_WEXT)) +#define NM_WIFI_UTILS_WEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_WIFI_UTILS_WEXT, NMWifiUtilsWextClass)) -gboolean wifi_wext_is_wifi (const char *iface); +GType nm_wifi_utils_wext_get_type (void); + +NMWifiUtils *nm_wifi_utils_wext_new (int ifindex, gboolean check_scan); + +gboolean nm_wifi_utils_wext_is_wifi (const char *iface); #endif /* __WIFI_UTILS_WEXT_H__ */ diff --git a/src/platform/wifi/nm-wifi-utils.c b/src/platform/wifi/nm-wifi-utils.c new file mode 100644 index 00000000..25d71c6a --- /dev/null +++ b/src/platform/wifi/nm-wifi-utils.c @@ -0,0 +1,240 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* 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 (C) 2005 - 2018 Red Hat, Inc. + * Copyright (C) 2006 - 2008 Novell, Inc. + */ + +#include "nm-default.h" + +#include "nm-wifi-utils.h" + +#include <sys/stat.h> +#include <stdio.h> +#include <string.h> +#include <fcntl.h> + +#include "nm-wifi-utils-private.h" +#include "nm-wifi-utils-nl80211.h" +#if HAVE_WEXT +#include "nm-wifi-utils-wext.h" +#endif +#include "nm-core-utils.h" + +#include "platform/nm-platform-utils.h" + +G_DEFINE_ABSTRACT_TYPE (NMWifiUtils, nm_wifi_utils, G_TYPE_OBJECT) + +/*****************************************************************************/ + +static void +nm_wifi_utils_init (NMWifiUtils *self) +{ +} + +static void +nm_wifi_utils_class_init (NMWifiUtilsClass *klass) +{ +} + +NMWifiUtils * +nm_wifi_utils_new (int ifindex, struct nl_sock *genl, gboolean check_scan) +{ + NMWifiUtils *ret; + + g_return_val_if_fail (ifindex > 0, NULL); + + ret = nm_wifi_utils_nl80211_new (ifindex, genl); + +#if HAVE_WEXT + if (ret == NULL) + ret = nm_wifi_utils_wext_new (ifindex, check_scan); +#endif + + return ret; +} + +NMDeviceWifiCapabilities +nm_wifi_utils_get_caps (NMWifiUtils *data) +{ + g_return_val_if_fail (data != NULL, NM_WIFI_DEVICE_CAP_NONE); + + return data->caps; +} + +NM80211Mode +nm_wifi_utils_get_mode (NMWifiUtils *data) +{ + g_return_val_if_fail (data != NULL, NM_802_11_MODE_UNKNOWN); + return NM_WIFI_UTILS_GET_CLASS (data)->get_mode (data); +} + +gboolean +nm_wifi_utils_set_mode (NMWifiUtils *data, const NM80211Mode mode) +{ + NMWifiUtilsClass *klass; + + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail ( (mode == NM_802_11_MODE_INFRA) + || (mode == NM_802_11_MODE_AP) + || (mode == NM_802_11_MODE_ADHOC), FALSE); + + klass = NM_WIFI_UTILS_GET_CLASS (data); + + /* nl80211 probably doesn't need this */ + return klass->set_mode ? klass->set_mode (data, mode) : TRUE; +} + +gboolean +nm_wifi_utils_set_powersave (NMWifiUtils *data, guint32 powersave) +{ + NMWifiUtilsClass *klass; + + g_return_val_if_fail (data != NULL, FALSE); + + klass = NM_WIFI_UTILS_GET_CLASS (data); + return klass->set_powersave ? klass->set_powersave (data, powersave) : TRUE; +} + +NMSettingWirelessWakeOnWLan +nm_wifi_utils_get_wake_on_wlan (NMWifiUtils *data) +{ + NMWifiUtilsClass *klass; + + g_return_val_if_fail (data != NULL, NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE); + + klass = NM_WIFI_UTILS_GET_CLASS (data); + + return klass->get_wake_on_wlan ? klass->get_wake_on_wlan (data) : NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; +} + +gboolean +nm_wifi_utils_set_wake_on_wlan (NMWifiUtils *data, NMSettingWirelessWakeOnWLan wowl) +{ + NMWifiUtilsClass *klass; + + g_return_val_if_fail (data != NULL, FALSE); + + klass = NM_WIFI_UTILS_GET_CLASS (data); + return klass->set_wake_on_wlan ? klass->set_wake_on_wlan (data, wowl) : FALSE; +} + +guint32 +nm_wifi_utils_get_freq (NMWifiUtils *data) +{ + g_return_val_if_fail (data != NULL, 0); + return NM_WIFI_UTILS_GET_CLASS (data)->get_freq (data); +} + +guint32 +nm_wifi_utils_find_freq (NMWifiUtils *data, const guint32 *freqs) +{ + g_return_val_if_fail (data != NULL, 0); + g_return_val_if_fail (freqs != NULL, 0); + return NM_WIFI_UTILS_GET_CLASS (data)->find_freq (data, freqs); +} + +gboolean +nm_wifi_utils_get_bssid (NMWifiUtils *data, guint8 *out_bssid) +{ + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (out_bssid != NULL, FALSE); + + memset (out_bssid, 0, ETH_ALEN); + return NM_WIFI_UTILS_GET_CLASS (data)->get_bssid (data, out_bssid); +} + +guint32 +nm_wifi_utils_get_rate (NMWifiUtils *data) +{ + g_return_val_if_fail (data != NULL, 0); + return NM_WIFI_UTILS_GET_CLASS (data)->get_rate (data); +} + +int +nm_wifi_utils_get_qual (NMWifiUtils *data) +{ + g_return_val_if_fail (data != NULL, 0); + return NM_WIFI_UTILS_GET_CLASS (data)->get_qual (data); +} + +gboolean +nm_wifi_utils_is_wifi (int dirfd, const char *ifname) +{ + g_return_val_if_fail (dirfd >= 0, FALSE); + + if (faccessat (dirfd, "phy80211", F_OK, 0) == 0) + return TRUE; +#if HAVE_WEXT + if (nm_wifi_utils_wext_is_wifi (ifname)) + return TRUE; +#endif + return FALSE; +} + +/* OLPC Mesh-only functions */ + +guint32 +nm_wifi_utils_get_mesh_channel (NMWifiUtils *data) +{ + NMWifiUtilsClass *klass; + + g_return_val_if_fail (data != NULL, FALSE); + + klass = NM_WIFI_UTILS_GET_CLASS (data); + g_return_val_if_fail (klass->get_mesh_channel != NULL, FALSE); + + return klass->get_mesh_channel (data); +} + +gboolean +nm_wifi_utils_set_mesh_channel (NMWifiUtils *data, guint32 channel) +{ + NMWifiUtilsClass *klass; + + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (channel <= 13, FALSE); + + klass = NM_WIFI_UTILS_GET_CLASS (data); + g_return_val_if_fail (klass->set_mesh_channel != NULL, FALSE); + + return klass->set_mesh_channel (data, channel); +} + +gboolean +nm_wifi_utils_set_mesh_ssid (NMWifiUtils *data, const guint8 *ssid, gsize len) +{ + NMWifiUtilsClass *klass; + + g_return_val_if_fail (data != NULL, FALSE); + + klass = NM_WIFI_UTILS_GET_CLASS (data); + g_return_val_if_fail (klass->set_mesh_ssid != NULL, FALSE); + + return klass->set_mesh_ssid (data, ssid, len); +} + +gboolean +nm_wifi_utils_indicate_addressing_running (NMWifiUtils *data, gboolean running) +{ + NMWifiUtilsClass *klass; + + g_return_val_if_fail (data != NULL, FALSE); + + klass = NM_WIFI_UTILS_GET_CLASS (data); + return klass->indicate_addressing_running ? klass->indicate_addressing_running (data, running) : FALSE; +} diff --git a/src/platform/wifi/nm-wifi-utils.h b/src/platform/wifi/nm-wifi-utils.h new file mode 100644 index 00000000..6cd178bd --- /dev/null +++ b/src/platform/wifi/nm-wifi-utils.h @@ -0,0 +1,84 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* 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 (C) 2005 - 2018 Red Hat, Inc. + * Copyright (C) 2006 - 2008 Novell, Inc. + */ + +#ifndef __WIFI_UTILS_H__ +#define __WIFI_UTILS_H__ + +#include <net/ethernet.h> + +#include "nm-dbus-interface.h" +#include "nm-setting-wireless.h" +#include "platform/nm-netlink.h" + +typedef struct NMWifiUtils NMWifiUtils; + +#define NM_TYPE_WIFI_UTILS (nm_wifi_utils_get_type ()) +#define NM_WIFI_UTILS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WIFI_UTILS, NMWifiUtils)) +#define NM_WIFI_UTILS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_WIFI_UTILS, NMWifiUtilsClass)) +#define NM_IS_WIFI_UTILS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_WIFI_UTILS)) +#define NM_IS_WIFI_UTILS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_WIFI_UTILS)) +#define NM_WIFI_UTILS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_WIFI_UTILS, NMWifiUtilsClass)) + +GType nm_wifi_utils_get_type (void); + +gboolean nm_wifi_utils_is_wifi (int dirfd, const char *ifname); + +NMWifiUtils *nm_wifi_utils_new (int ifindex, struct nl_sock *genl, gboolean check_scan); + +NMDeviceWifiCapabilities nm_wifi_utils_get_caps (NMWifiUtils *data); + +NM80211Mode nm_wifi_utils_get_mode (NMWifiUtils *data); + +gboolean nm_wifi_utils_set_mode (NMWifiUtils *data, const NM80211Mode mode); + +/* Returns frequency in MHz */ +guint32 nm_wifi_utils_get_freq (NMWifiUtils *data); + +/* Return the first supported frequency in the zero-terminated list. + * Frequencies are specified in MHz. */ +guint32 nm_wifi_utils_find_freq (NMWifiUtils *data, const guint32 *freqs); + +/* out_bssid must be ETH_ALEN bytes */ +gboolean nm_wifi_utils_get_bssid (NMWifiUtils *data, guint8 *out_bssid); + +/* Returns current bitrate in Kbps */ +guint32 nm_wifi_utils_get_rate (NMWifiUtils *data); + +/* Returns quality 0 - 100% on succes, or -1 on error */ +int nm_wifi_utils_get_qual (NMWifiUtils *data); + +/* Tells the driver DHCP or SLAAC is running */ +gboolean nm_wifi_utils_indicate_addressing_running (NMWifiUtils *data, gboolean running); + +gboolean nm_wifi_utils_set_powersave (NMWifiUtils *data, guint32 powersave); + +NMSettingWirelessWakeOnWLan nm_wifi_utils_get_wake_on_wlan (NMWifiUtils *data); + +gboolean nm_wifi_utils_set_wake_on_wlan (NMWifiUtils *data, NMSettingWirelessWakeOnWLan wowl); + +/* OLPC Mesh-only functions */ +guint32 nm_wifi_utils_get_mesh_channel (NMWifiUtils *data); + +gboolean nm_wifi_utils_set_mesh_channel (NMWifiUtils *data, guint32 channel); + +gboolean nm_wifi_utils_set_mesh_ssid (NMWifiUtils *data, const guint8 *ssid, gsize len); + +#endif /* __WIFI_UTILS_H__ */ diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c deleted file mode 100644 index b3dd92ba..00000000 --- a/src/platform/wifi/wifi-utils.c +++ /dev/null @@ -1,231 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* 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 (C) 2005 - 2011 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#include "nm-default.h" - -#include "wifi-utils.h" - -#include <sys/stat.h> -#include <stdio.h> -#include <string.h> -#include <fcntl.h> - -#include "wifi-utils-private.h" -#include "wifi-utils-nl80211.h" -#if HAVE_WEXT -#include "wifi-utils-wext.h" -#endif -#include "nm-core-utils.h" - -#include "platform/nm-platform-utils.h" - -gpointer -wifi_data_new (const WifiDataClass *klass, int ifindex) -{ - WifiData *data; - - nm_assert (klass); - nm_assert (klass->struct_size > sizeof (WifiData)); - - data = g_malloc0 (klass->struct_size); - data->klass = klass; - data->ifindex = ifindex; - return data; -} - -/*****************************************************************************/ - -WifiData * -wifi_utils_init (int ifindex, gboolean check_scan) -{ - WifiData *ret; - - g_return_val_if_fail (ifindex > 0, NULL); - - ret = wifi_nl80211_init (ifindex); - if (ret == NULL) { -#if HAVE_WEXT - ret = wifi_wext_init (ifindex, check_scan); -#endif - } - return ret; -} - -int -wifi_utils_get_ifindex (WifiData *data) -{ - g_return_val_if_fail (data != NULL, -1); - - return data->ifindex; -} - -NMDeviceWifiCapabilities -wifi_utils_get_caps (WifiData *data) -{ - g_return_val_if_fail (data != NULL, NM_WIFI_DEVICE_CAP_NONE); - - return data->caps; -} - -NM80211Mode -wifi_utils_get_mode (WifiData *data) -{ - g_return_val_if_fail (data != NULL, NM_802_11_MODE_UNKNOWN); - return data->klass->get_mode (data); -} - -gboolean -wifi_utils_set_mode (WifiData *data, const NM80211Mode mode) -{ - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail ( (mode == NM_802_11_MODE_INFRA) - || (mode == NM_802_11_MODE_AP) - || (mode == NM_802_11_MODE_ADHOC), FALSE); - - /* nl80211 probably doesn't need this */ - return data->klass->set_mode ? data->klass->set_mode (data, mode) : TRUE; -} - -gboolean -wifi_utils_set_powersave (WifiData *data, guint32 powersave) -{ - g_return_val_if_fail (data != NULL, FALSE); - - return data->klass->set_powersave ? data->klass->set_powersave (data, powersave) : TRUE; -} - -gboolean -wifi_utils_set_wake_on_wlan (WifiData *data, NMSettingWirelessWakeOnWLan wowl) -{ - g_return_val_if_fail (data != NULL, FALSE); - - return data->klass->set_wake_on_wlan ? - data->klass->set_wake_on_wlan (data, wowl) : FALSE; -} - -guint32 -wifi_utils_get_freq (WifiData *data) -{ - g_return_val_if_fail (data != NULL, 0); - return data->klass->get_freq (data); -} - -guint32 -wifi_utils_find_freq (WifiData *data, const guint32 *freqs) -{ - g_return_val_if_fail (data != NULL, 0); - g_return_val_if_fail (freqs != NULL, 0); - return data->klass->find_freq (data, freqs); -} - -gboolean -wifi_utils_get_bssid (WifiData *data, guint8 *out_bssid) -{ - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (out_bssid != NULL, FALSE); - - memset (out_bssid, 0, ETH_ALEN); - return data->klass->get_bssid (data, out_bssid); -} - -guint32 -wifi_utils_get_rate (WifiData *data) -{ - g_return_val_if_fail (data != NULL, 0); - return data->klass->get_rate (data); -} - -int -wifi_utils_get_qual (WifiData *data) -{ - g_return_val_if_fail (data != NULL, 0); - return data->klass->get_qual (data); -} - -gboolean -wifi_utils_get_wowlan (WifiData *data) -{ - g_return_val_if_fail (data != NULL, 0); - - if (!data->klass->get_wowlan) - return FALSE; - return data->klass->get_wowlan (data); -} - -void -wifi_utils_unref (WifiData *data) -{ - g_return_if_fail (data != NULL); - - data->klass->deinit (data); - g_free (data); -} - -gboolean -wifi_utils_is_wifi (int dirfd, const char *ifname) -{ - g_return_val_if_fail (dirfd >= 0, FALSE); - - if (faccessat (dirfd, "phy80211", F_OK, 0) == 0) - return TRUE; -#if HAVE_WEXT - if (wifi_wext_is_wifi (ifname)) - return TRUE; -#endif - return FALSE; -} - -/* OLPC Mesh-only functions */ - -guint32 -wifi_utils_get_mesh_channel (WifiData *data) -{ - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (data->klass->get_mesh_channel != NULL, FALSE); - return data->klass->get_mesh_channel (data); -} - -gboolean -wifi_utils_set_mesh_channel (WifiData *data, guint32 channel) -{ - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (channel <= 13, FALSE); - g_return_val_if_fail (data->klass->set_mesh_channel != NULL, FALSE); - return data->klass->set_mesh_channel (data, channel); -} - -gboolean -wifi_utils_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len) -{ - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (data->klass->set_mesh_ssid != NULL, FALSE); - return data->klass->set_mesh_ssid (data, ssid, len); -} - -gboolean -wifi_utils_indicate_addressing_running (WifiData *data, gboolean running) -{ - g_return_val_if_fail (data != NULL, FALSE); - if (data->klass->indicate_addressing_running) - return data->klass->indicate_addressing_running (data, running); - return FALSE; -} - diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h deleted file mode 100644 index c69561de..00000000 --- a/src/platform/wifi/wifi-utils.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* 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 (C) 2005 - 2011 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#ifndef __WIFI_UTILS_H__ -#define __WIFI_UTILS_H__ - -#include <net/ethernet.h> - -#include "nm-dbus-interface.h" -#include "nm-setting-wireless.h" - -typedef struct WifiData WifiData; - -gboolean wifi_utils_is_wifi (int dirfd, const char *ifname); - -WifiData *wifi_utils_init (int ifindex, gboolean check_scan); - -int wifi_utils_get_ifindex (WifiData *data); - -void wifi_utils_unref (WifiData *data); - -NMDeviceWifiCapabilities wifi_utils_get_caps (WifiData *data); - -NM80211Mode wifi_utils_get_mode (WifiData *data); - -gboolean wifi_utils_set_mode (WifiData *data, const NM80211Mode mode); - -/* Returns frequency in MHz */ -guint32 wifi_utils_get_freq (WifiData *data); - -/* Return the first supported frequency in the zero-terminated list. - * Frequencies are specified in MHz. */ -guint32 wifi_utils_find_freq (WifiData *data, const guint32 *freqs); - -/* out_bssid must be ETH_ALEN bytes */ -gboolean wifi_utils_get_bssid (WifiData *data, guint8 *out_bssid); - -/* Returns current bitrate in Kbps */ -guint32 wifi_utils_get_rate (WifiData *data); - -/* Returns quality 0 - 100% on succes, or -1 on error */ -int wifi_utils_get_qual (WifiData *data); - -/* Tells the driver DHCP or SLAAC is running */ -gboolean wifi_utils_indicate_addressing_running (WifiData *data, gboolean running); - -/* Returns true if WoWLAN is enabled on device */ -gboolean wifi_utils_get_wowlan (WifiData *data); - -gboolean wifi_utils_set_powersave (WifiData *data, guint32 powersave); - -gboolean wifi_utils_set_wake_on_wlan (WifiData *data, NMSettingWirelessWakeOnWLan wowl); - -/* OLPC Mesh-only functions */ -guint32 wifi_utils_get_mesh_channel (WifiData *data); - -gboolean wifi_utils_set_mesh_channel (WifiData *data, guint32 channel); - -gboolean wifi_utils_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len); - -#endif /* __WIFI_UTILS_H__ */ diff --git a/src/platform/wpan/nm-wpan-utils.c b/src/platform/wpan/nm-wpan-utils.c new file mode 100644 index 00000000..0544539a --- /dev/null +++ b/src/platform/wpan/nm-wpan-utils.c @@ -0,0 +1,286 @@ +/* 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 (C) 2018 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-wpan-utils.h" + +#include "platform/linux/nl802154.h" +#include "platform/nm-netlink.h" + +#define _NMLOG_PREFIX_NAME "wpan-nl802154" +#define _NMLOG(level, domain, ...) \ + G_STMT_START { \ + nm_log ((level), (domain), NULL, NULL, \ + "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + _NMLOG_PREFIX_NAME \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } G_STMT_END + +/*****************************************************************************/ + +struct NMWpanUtils { + GObject parent; + int ifindex; + struct nl_sock *nl_sock; + int id; +}; + +typedef struct { + GObjectClass parent; +} NMWpanUtilsClass; + +G_DEFINE_TYPE (NMWpanUtils, nm_wpan_utils, G_TYPE_OBJECT) + +/*****************************************************************************/ + +static int +ack_handler (struct nl_msg *msg, void *arg) +{ + int *done = arg; + *done = 1; + return NL_STOP; +} + +static int +finish_handler (struct nl_msg *msg, void *arg) +{ + int *done = arg; + *done = 1; + return NL_SKIP; +} + +static int +error_handler (struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) +{ + int *done = arg; + *done = err->error; + return NL_SKIP; +} + +static struct nl_msg * +_nl802154_alloc_msg (int id, int ifindex, guint32 cmd, guint32 flags) +{ + nm_auto_nlmsg struct nl_msg *msg = NULL; + + msg = nlmsg_alloc (); + genlmsg_put (msg, 0, 0, id, 0, flags, cmd, 0); + NLA_PUT_U32 (msg, NL802154_ATTR_IFINDEX, ifindex); + return g_steal_pointer (&msg); + +nla_put_failure: + return NULL; +} + +static struct nl_msg * +nl802154_alloc_msg (NMWpanUtils *self, guint32 cmd, guint32 flags) +{ + return _nl802154_alloc_msg (self->id, self->ifindex, cmd, flags); +} + +static int +_nl802154_send_and_recv (struct nl_sock *nl_sock, + struct nl_msg *msg, + int (*valid_handler) (struct nl_msg *, void *), + void *valid_data) +{ + int err; + int done = 0; + const struct nl_cb cb = { + .err_cb = error_handler, + .err_arg = &done, + .finish_cb = finish_handler, + .finish_arg = &done, + .ack_cb = ack_handler, + .ack_arg = &done, + .valid_cb = valid_handler, + .valid_arg = valid_data, + }; + + g_return_val_if_fail (msg != NULL, -ENOMEM); + + err = nl_send_auto (nl_sock, msg); + if (err < 0) + return err; + + /* Loop until one of our NL callbacks says we're done; on success + * done will be 1, on error it will be < 0. + */ + while (!done) { + err = nl_recvmsgs (nl_sock, &cb); + if (err < 0 && err != -EAGAIN) { + _LOGW (LOGD_PLATFORM, "nl_recvmsgs() error: (%d) %s", + err, nl_geterror (err)); + break; + } + } + + if (err >= 0 && done < 0) + err = done; + return err; +} + +static int +nl802154_send_and_recv (NMWpanUtils *self, + struct nl_msg *msg, + int (*valid_handler) (struct nl_msg *, void *), + void *valid_data) +{ + return _nl802154_send_and_recv (self->nl_sock, msg, + valid_handler, valid_data); +} + +struct nl802154_interface { + guint16 pan_id; + guint16 short_addr; + + gboolean valid; +}; + +static int +nl802154_get_interface_handler (struct nl_msg *msg, void *arg) +{ + struct nl802154_interface *info = arg; + struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg)); + struct nlattr *tb[NL802154_ATTR_MAX + 1] = { 0, }; + static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX + 1] = { + [NL802154_ATTR_PAN_ID] = { .type = NLA_U16 }, + [NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16 }, + }; + + if (nla_parse (tb, NL802154_ATTR_MAX, genlmsg_attrdata (gnlh, 0), + genlmsg_attrlen (gnlh, 0), nl802154_policy) < 0) + return NL_SKIP; + + if (tb[NL802154_ATTR_PAN_ID]) + info->pan_id = le16toh (nla_get_u16 (tb[NL802154_ATTR_PAN_ID])); + + if (tb[NL802154_ATTR_SHORT_ADDR]) + info->short_addr = le16toh (nla_get_u16 (tb[NL802154_ATTR_SHORT_ADDR])); + + info->valid = TRUE; + + return NL_SKIP; +} + +static void +nl802154_get_interface (NMWpanUtils *self, + struct nl802154_interface *interface) +{ + nm_auto_nlmsg struct nl_msg *msg = NULL; + + memset (interface, 0, sizeof (*interface)); + + msg = nl802154_alloc_msg (self, NL802154_CMD_GET_INTERFACE, 0); + + nl802154_send_and_recv (self, msg, nl802154_get_interface_handler, interface); +} + +/*****************************************************************************/ + +guint16 +nm_wpan_utils_get_pan_id (NMWpanUtils *self) +{ + struct nl802154_interface interface; + + nl802154_get_interface (self, &interface); + + return interface.pan_id; +} + +gboolean +nm_wpan_utils_set_pan_id (NMWpanUtils *self, guint16 pan_id) +{ + nm_auto_nlmsg struct nl_msg *msg = NULL; + int err; + + g_return_val_if_fail (self != NULL, FALSE); + + msg = nl802154_alloc_msg (self, NL802154_CMD_SET_PAN_ID, 0); + NLA_PUT_U16 (msg, NL802154_ATTR_PAN_ID, htole16 (pan_id)); + err = nl802154_send_and_recv (self, msg, NULL, NULL); + return err >= 0; + +nla_put_failure: + return FALSE; +} + +guint16 +nm_wpan_utils_get_short_addr (NMWpanUtils *self) +{ + struct nl802154_interface interface; + + nl802154_get_interface (self, &interface); + + return interface.short_addr; +} + +gboolean +nm_wpan_utils_set_short_addr (NMWpanUtils *self, guint16 short_addr) +{ + nm_auto_nlmsg struct nl_msg *msg = NULL; + int err; + + g_return_val_if_fail (self != NULL, FALSE); + + msg = nl802154_alloc_msg (self, NL802154_CMD_SET_SHORT_ADDR, 0); + NLA_PUT_U16 (msg, NL802154_ATTR_SHORT_ADDR, htole16 (short_addr)); + err = nl802154_send_and_recv (self, msg, NULL, NULL); + return err >= 0; + +nla_put_failure: + return FALSE; +} + +/*****************************************************************************/ + +static void +nm_wpan_utils_init (NMWpanUtils *self) +{ +} + +static void +nm_wpan_utils_class_init (NMWpanUtilsClass *klass) +{ +} + +NMWpanUtils * +nm_wpan_utils_new (int ifindex, struct nl_sock *genl, gboolean check_scan) +{ + NMWpanUtils *self; + int id; + + g_return_val_if_fail (ifindex > 0, NULL); + + if (!genl) + return NULL; + + id = genl_ctrl_resolve (genl, "nl802154"); + if (id < 0) { + _LOGD (LOGD_PLATFORM, "genl_ctrl_resolve: failed to resolve \"nl802154\""); + return NULL; + } + + self = g_object_new (NM_TYPE_WPAN_UTILS, NULL); + self->ifindex = ifindex; + self->nl_sock = genl; + self->id = id; + + return self; +} diff --git a/src/platform/wpan/nm-wpan-utils.h b/src/platform/wpan/nm-wpan-utils.h new file mode 100644 index 00000000..f7d0c03e --- /dev/null +++ b/src/platform/wpan/nm-wpan-utils.h @@ -0,0 +1,47 @@ +/* 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 (C) 2018 Red Hat, Inc. + */ + +#ifndef __WPAN_UTILS_H__ +#define __WPAN_UTILS_H__ + +#include <net/ethernet.h> + +#include "nm-dbus-interface.h" +#include "platform/nm-netlink.h" + +typedef struct NMWpanUtils NMWpanUtils; + +#define NM_TYPE_WPAN_UTILS (nm_wpan_utils_get_type ()) +#define NM_WPAN_UTILS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WPAN_UTILS, NMWpanUtils)) +#define NM_WPAN_UTILS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_WPAN_UTILS, NMWpanUtilsClass)) +#define NM_IS_WPAN_UTILS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_WPAN_UTILS)) +#define NM_IS_WPAN_UTILS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_WPAN_UTILS)) +#define NM_WPAN_UTILS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_WPAN_UTILS, NMWpanUtilsClass)) + +GType nm_wpan_utils_get_type (void); + +NMWpanUtils *nm_wpan_utils_new (int ifindex, struct nl_sock *genl, gboolean check_scan); + +guint16 nm_wpan_utils_get_pan_id (NMWpanUtils *self); +gboolean nm_wpan_utils_set_pan_id (NMWpanUtils *self, guint16 pan_id); + +guint16 nm_wpan_utils_get_short_addr (NMWpanUtils *self); +gboolean nm_wpan_utils_set_short_addr (NMWpanUtils *self, guint16 short_addr); + +#endif /* __WPAN_UTILS_H__ */ diff --git a/src/ppp/meson.build b/src/ppp/meson.build index 38f9a0f1..20ed64ed 100644 --- a/src/ppp/meson.build +++ b/src/ppp/meson.build @@ -31,7 +31,6 @@ core_plugins += shared_module( name, sources: 'nm-ppp-manager.c', dependencies: deps, - c_args: '-DPPPD_PLUGIN_DIR="@0@"'.format(pppd_plugin_dir), link_args: [ '-Wl,--version-script,@0@'.format(linker_script), ], diff --git a/src/ppp/nm-ppp-manager.c b/src/ppp/nm-ppp-manager.c index 40bdea64..b231ff20 100644 --- a/src/ppp/nm-ppp-manager.c +++ b/src/ppp/nm-ppp-manager.c @@ -438,10 +438,11 @@ impl_ppp_manager_set_ifindex (NMDBusObject *obj, g_variant_get (parameters, "(i)", &ifindex); - _LOGD ("set-ifindex %d", (int) ifindex); - if (priv->ifindex >= 0) { - _LOGW ("can't change the ifindex from %d to %d", priv->ifindex, (int) ifindex); + if (priv->ifindex == ifindex) + _LOGD ("set-ifindex: ignore repeated calls setting ifindex to %d", (int) ifindex); + else + _LOGW ("set-ifindex: can't change the ifindex from %d to %d", priv->ifindex, (int) ifindex); goto out; } @@ -454,14 +455,15 @@ impl_ppp_manager_set_ifindex (NMDBusObject *obj, } if (!plink) { - _LOGW ("unknown interface with ifindex %d", ifindex); + _LOGW ("set-ifindex: unknown interface with ifindex %d", ifindex); ifindex = 0; + } else { + obj_keep_alive = nmp_object_ref (NMP_OBJECT_UP_CAST (plink)); + _LOGD ("set-ifindex: %d, name \"%s\"", (int) ifindex, plink->name); } priv->ifindex = ifindex; - obj_keep_alive = nmp_object_ref (NMP_OBJECT_UP_CAST (plink)); - g_signal_emit (self, signals[IFINDEX_SET], 0, @@ -701,7 +703,7 @@ nm_cmd_line_to_str (NMCmdLine *cmd) char *str; g_ptr_array_add (cmd->array, NULL); - str = g_strjoinv (" ", (gchar **) cmd->array->pdata); + str = g_strjoinv (" ", (char **) cmd->array->pdata); g_ptr_array_remove_index (cmd->array, cmd->array->len - 1); return str; @@ -880,13 +882,13 @@ create_pppd_cmd_line (NMPPPManager *self, nm_cmd_line_add_string (cmd, pppoe_service); } } else if (adsl) { - const gchar *protocol = nm_setting_adsl_get_protocol (adsl); + const char *protocol = nm_setting_adsl_get_protocol (adsl); if (!strcmp (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOA)) { guint32 vpi = nm_setting_adsl_get_vpi (adsl); guint32 vci = nm_setting_adsl_get_vci (adsl); const char *encaps = nm_setting_adsl_get_encapsulation (adsl); - gchar *vpivci; + char *vpivci; nm_cmd_line_add_string (cmd, "plugin"); nm_cmd_line_add_string (cmd, "pppoatm.so"); diff --git a/src/ppp/nm-pppd-plugin.c b/src/ppp/nm-pppd-plugin.c index 989f7433..09196340 100644 --- a/src/ppp/nm-pppd-plugin.c +++ b/src/ppp/nm-pppd-plugin.c @@ -147,7 +147,7 @@ nm_phasechange (void *data, int arg) if ( if_indextoname (index, new_name) && !nm_streq0 (ifname, new_name)) { g_message ("nm-ppp-plugin: interface name changed from '%s' to '%s'", ifname, new_name); - strncpy (ifname, new_name, IF_NAMESIZE); + g_strlcpy (ifname, new_name, IF_NAMESIZE); } } } diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index 453136e4..953d3ce4 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -349,7 +349,7 @@ agent_register_permissions_done (NMAuthChain *chain, priv->agent_version_id += 1; sender = nm_secret_agent_get_dbus_owner (agent); g_hash_table_insert (priv->agents, g_strdup (sender), agent); - _LOGD (agent, "agent registered"); + _LOGI (agent, "agent registered"); g_dbus_method_invocation_return_value (context, NULL); /* Signal an agent was registered */ @@ -642,7 +642,7 @@ req_complete_error (Request *req, GError *error) req_complete (req, NULL, NULL, NULL, error); } -static gint +static int agent_compare_func (gconstpointer aa, gconstpointer bb, gpointer user_data) { NMSecretAgent *a = (NMSecretAgent *)aa; @@ -651,12 +651,14 @@ agent_compare_func (gconstpointer aa, gconstpointer bb, gpointer user_data) NMSessionMonitor *sm; gboolean a_active, b_active; gulong a_pid, b_pid, requester; + guint64 a_start, b_start; + + a_pid = nm_secret_agent_get_pid (a); + b_pid = nm_secret_agent_get_pid (b); /* Prefer agents in the process the request came from */ if (nm_auth_subject_is_unix_process (req->subject)) { requester = nm_auth_subject_get_unix_process_pid (req->subject); - a_pid = nm_secret_agent_get_pid (a); - b_pid = nm_secret_agent_get_pid (b); if (a_pid != b_pid) { if (a_pid == requester) @@ -672,11 +674,17 @@ agent_compare_func (gconstpointer aa, gconstpointer bb, gpointer user_data) b_active = nm_session_monitor_session_exists (sm, nm_secret_agent_get_owner_uid (b), TRUE); if (a_active && !b_active) return -1; - else if (a_active == b_active) - return 0; else if (!a_active && b_active) return 1; + /* Prefer agents launched later (this is essentially to ease agent debugging) */ + a_start = nm_utils_get_start_time_for_pid (a_pid, NULL, NULL); + b_start = nm_utils_get_start_time_for_pid (b_pid, NULL, NULL); + if (a_start > b_start) + return -1; + else if (a_start < b_start) + return 1; + return 0; } diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c index af6d7017..836ab21d 100644 --- a/src/settings/nm-secret-agent.c +++ b/src/settings/nm-secret-agent.c @@ -648,10 +648,10 @@ _on_disconnected_private_connection (NMDBusManager *mgr, static void _on_disconnected_name_owner_changed (GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, + const char *sender_name, + const char *object_path, + const char *interface_name, + const char *signal_name, GVariant *parameters, gpointer user_data) { diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index c09f6804..4c25d0e9 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -49,7 +49,26 @@ /*****************************************************************************/ -static void nm_settings_connection_connection_interface_init (NMConnectionInterface *iface); +NMConnection ** +nm_settings_connections_array_to_connections (NMSettingsConnection *const*connections, + gssize n_connections) +{ + NMConnection **arr; + gssize i; + + if (n_connections < 0) + n_connections = NM_PTRARRAY_LEN (connections); + if (n_connections == 0) + return NULL; + + arr = g_new (NMConnection *, n_connections + 1); + for (i = 0; i < n_connections; i++) + arr[i] = nm_settings_connection_get_connection (connections[i]); + arr[i] = NULL; + return arr; +} + +/*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE (NMSettingsConnection, PROP_UNSAVED, @@ -87,6 +106,8 @@ typedef struct _NMSettingsConnectionPrivate { CList call_ids_lst_head; /* in-progress secrets requests */ + NMConnection *connection; + /* Caches secrets from on-disk connections; were they not cached any * call to nm_connection_clear_secrets() wipes them out and we'd have * to re-read them from disk which defeats the purpose of having the @@ -115,9 +136,7 @@ typedef struct _NMSettingsConnectionPrivate { } NMSettingsConnectionPrivate; -G_DEFINE_TYPE_WITH_CODE (NMSettingsConnection, nm_settings_connection, NM_TYPE_DBUS_OBJECT, - G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION, nm_settings_connection_connection_interface_init) - ) +G_DEFINE_TYPE (NMSettingsConnection, nm_settings_connection, NM_TYPE_DBUS_OBJECT) #define NM_SETTINGS_CONNECTION_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR (self, NMSettingsConnection, NM_IS_SETTINGS_CONNECTION) @@ -152,6 +171,16 @@ static const NMDBusInterfaceInfoExtended interface_info_settings_connection; /*****************************************************************************/ +NMConnection * +nm_settings_connection_get_connection (NMSettingsConnection *self) +{ + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NULL); + + return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->connection; +} + +/*****************************************************************************/ + gboolean nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection *self, NMConnection *applied_connection, @@ -163,7 +192,8 @@ nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection * /* for convenience, we *always* ignore certain settings. */ compare_flags |= NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS | NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP; - return nm_connection_compare (NM_CONNECTION (self), applied_connection, compare_flags); + return nm_connection_compare (nm_settings_connection_get_connection (self), + applied_connection, compare_flags); } /*****************************************************************************/ @@ -332,8 +362,7 @@ nm_settings_connection_recheck_visibility (NMSettingsConnection *self) priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - s_con = nm_connection_get_setting_connection (NM_CONNECTION (self)); - g_assert (s_con); + s_con = nm_connection_get_setting_connection (nm_settings_connection_get_connection (self)); /* Check every user in the ACL for a session */ num = nm_setting_connection_get_num_permissions (s_con); @@ -362,9 +391,9 @@ nm_settings_connection_recheck_visibility (NMSettingsConnection *self) } static void -session_changed_cb (NMSessionMonitor *self, gpointer user_data) +session_changed_cb (NMSessionMonitor *self, NMSettingsConnection *sett_conn) { - nm_settings_connection_recheck_visibility (NM_SETTINGS_CONNECTION (user_data)); + nm_settings_connection_recheck_visibility (sett_conn); } /*****************************************************************************/ @@ -390,8 +419,7 @@ nm_settings_connection_check_permission (NMSettingsConnection *self, NM_SETTINGS_CONNECTION_INT_FLAGS_VISIBLE)) return FALSE; - s_con = nm_connection_get_setting_connection (NM_CONNECTION (self)); - g_assert (s_con); + s_con = nm_connection_get_setting_connection (nm_settings_connection_get_connection (self)); /* Check every user in the ACL for a session */ num = nm_setting_connection_get_num_permissions (s_con); @@ -447,7 +475,7 @@ update_system_secrets_cache (NMSettingsConnection *self) if (priv->system_secrets) g_object_unref (priv->system_secrets); - priv->system_secrets = nm_simple_connection_new_clone (NM_CONNECTION (self)); + priv->system_secrets = nm_simple_connection_new_clone (nm_settings_connection_get_connection (self)); /* Clear out non-system-owned and not-saved secrets */ nm_connection_clear_secrets_with_flags (priv->system_secrets, @@ -463,7 +491,8 @@ update_agent_secrets_cache (NMSettingsConnection *self, NMConnection *new) if (priv->agent_secrets) g_object_unref (priv->agent_secrets); - priv->agent_secrets = nm_simple_connection_new_clone (new ?: NM_CONNECTION(self)); + priv->agent_secrets = nm_simple_connection_new_clone ( new + ?: nm_settings_connection_get_connection (self)); /* Clear out non-system-owned secrets */ nm_connection_clear_secrets_with_flags (priv->agent_secrets, @@ -472,7 +501,7 @@ update_agent_secrets_cache (NMSettingsConnection *self, NMConnection *new) } static void -secrets_cleared_cb (NMSettingsConnection *self) +secrets_cleared_cb (NMConnection *connection, NMSettingsConnection *self) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); @@ -533,7 +562,7 @@ _emit_updated (NMSettingsConnection *self, gboolean by_user) } static void -connection_changed_cb (NMSettingsConnection *self, gpointer unused) +connection_changed_cb (NMConnection *connection, NMSettingsConnection *self) { set_persist_mode (self, NM_SETTINGS_CONNECTION_PERSIST_MODE_UNSAVED); _emit_updated (self, FALSE); @@ -636,7 +665,7 @@ nm_settings_connection_update (NMSettingsConnection *self, if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK) { if (!klass->commit_changes (self, - new_connection ?: NM_CONNECTION (self), + new_connection ?: nm_settings_connection_get_connection (self), commit_reason, &reread_connection, &logmsg_change, @@ -655,30 +684,30 @@ nm_settings_connection_update (NMSettingsConnection *self, /* Disconnect the changed signal to ensure we don't set Unsaved when * it's not required. */ - g_signal_handlers_block_by_func (self, G_CALLBACK (connection_changed_cb), NULL); + g_signal_handlers_block_by_func (priv->connection, G_CALLBACK (connection_changed_cb), self); /* Do nothing if there's nothing to update */ if ( replace_connection - && !nm_connection_compare (NM_CONNECTION (self), + && !nm_connection_compare (nm_settings_connection_get_connection (self), replace_connection, NM_SETTING_COMPARE_FLAG_EXACT)) { gs_unref_object NMConnection *simple = NULL; if (log_diff_name) { - nm_utils_log_connection_diff (replace_connection, NM_CONNECTION (self), LOGL_DEBUG, LOGD_CORE, log_diff_name, "++ ", + nm_utils_log_connection_diff (replace_connection, nm_settings_connection_get_connection (self), LOGL_DEBUG, LOGD_CORE, log_diff_name, "++ ", nm_dbus_object_get_path (NM_DBUS_OBJECT (self))); } /* Make a copy of agent-owned secrets because they won't be present in * the connection returned by plugins, as plugins return only what was * reread from the file. */ - simple = nm_simple_connection_new_clone (NM_CONNECTION (self)); + simple = nm_simple_connection_new_clone (nm_settings_connection_get_connection (self)); nm_connection_clear_secrets_with_flags (simple, secrets_filter_cb, GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED)); con_agent_secrets = nm_connection_to_dbus (simple, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); - nm_connection_replace_settings_from_connection (NM_CONNECTION (self), replace_connection); + nm_connection_replace_settings_from_connection (nm_settings_connection_get_connection (self), replace_connection); replaced = TRUE; } @@ -701,12 +730,12 @@ nm_settings_connection_update (NMSettingsConnection *self, dict = nm_connection_to_dbus (priv->agent_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); if (dict) { - (void) nm_connection_update_secrets (NM_CONNECTION (self), NULL, dict, NULL); + (void) nm_connection_update_secrets (nm_settings_connection_get_connection (self), NULL, dict, NULL); g_variant_unref (dict); } } if (con_agent_secrets) - (void) nm_connection_update_secrets (NM_CONNECTION (self), NULL, con_agent_secrets, NULL); + (void) nm_connection_update_secrets (nm_settings_connection_get_connection (self), NULL, con_agent_secrets, NULL); } nm_settings_connection_recheck_visibility (self); @@ -724,7 +753,7 @@ nm_settings_connection_update (NMSettingsConnection *self, NM_SETTINGS_CONNECTION_PERSIST_MODE_VOLATILE_DETACHED)) nm_settings_connection_set_filename (self, NULL); - g_signal_handlers_unblock_by_func (self, G_CALLBACK (connection_changed_cb), NULL); + g_signal_handlers_unblock_by_func (priv->connection, G_CALLBACK (connection_changed_cb), self); _emit_updated (self, TRUE); @@ -800,7 +829,7 @@ nm_settings_connection_delete (NMSettingsConnection *self, set_visible (self, FALSE); /* Tell agents to remove secrets for this connection */ - for_agents = nm_simple_connection_new_clone (NM_CONNECTION (self)); + for_agents = nm_simple_connection_new_clone (nm_settings_connection_get_connection (self)); nm_connection_clear_secrets (for_agents); nm_agent_manager_delete_secrets (priv->agent_mgr, nm_dbus_object_get_path (NM_DBUS_OBJECT (self)), @@ -920,7 +949,7 @@ get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ gboolean *agent_had_system, ForEachSecretFlags *cmp_flags) { - gboolean is_self = (((NMConnection *) self) == connection); + gboolean is_self = (nm_settings_connection_get_connection (self) == connection); g_return_if_fail (secrets); @@ -1001,7 +1030,7 @@ nm_settings_connection_new_secrets (NMSettingsConnection *self, return FALSE; } - if (!nm_connection_update_secrets (NM_CONNECTION (self), setting_name, secrets, error)) + if (!nm_connection_update_secrets (nm_settings_connection_get_connection (self), setting_name, secrets, error)) return FALSE; update_system_secrets_cache (self); @@ -1073,7 +1102,7 @@ get_secrets_done_cb (NMAgentManager *manager, goto out; } - if (!nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name)) { + if (!nm_connection_get_setting_by_name (nm_settings_connection_get_connection (self), setting_name)) { g_set_error (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, "Connection didn't have requested setting '%s'.", setting_name); @@ -1083,7 +1112,7 @@ get_secrets_done_cb (NMAgentManager *manager, get_cmp_flags (self, call_id, - NM_CONNECTION (self), + nm_settings_connection_get_connection (self), agent_dbus_owner, agent_has_modify, setting_name, @@ -1100,8 +1129,8 @@ get_secrets_done_cb (NMAgentManager *manager, dict = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); /* Update the connection with our existing secrets from backing storage */ - nm_connection_clear_secrets (NM_CONNECTION (self)); - if (!dict || nm_connection_update_secrets (NM_CONNECTION (self), setting_name, dict, &local)) { + nm_connection_clear_secrets (nm_settings_connection_get_connection (self)); + if (!dict || nm_connection_update_secrets (nm_settings_connection_get_connection (self), setting_name, dict, &local)) { GVariant *filtered_secrets; /* Update the connection with the agent's secrets; by this point if any @@ -1109,8 +1138,8 @@ get_secrets_done_cb (NMAgentManager *manager, * will have been authenticated, so those secrets can replace the existing * system secrets. */ - filtered_secrets = for_each_secret (NM_CONNECTION (self), secrets, TRUE, validate_secret_flags, &cmp_flags); - if (nm_connection_update_secrets (NM_CONNECTION (self), setting_name, filtered_secrets, &local)) { + filtered_secrets = for_each_secret (nm_settings_connection_get_connection (self), secrets, TRUE, validate_secret_flags, &cmp_flags); + if (nm_connection_update_secrets (nm_settings_connection_get_connection (self), setting_name, filtered_secrets, &local)) { /* Now that all secrets are updated, copy and cache new secrets, * then save them to backing storage. */ @@ -1250,7 +1279,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NULL); g_return_val_if_fail ( !applied_connection || ( NM_IS_CONNECTION (applied_connection) - && (((NMConnection *) self) != applied_connection)), NULL); + && (nm_settings_connection_get_connection (self) != applied_connection)), NULL); call_id = g_slice_new0 (NMSettingsConnectionCallId); call_id->self = self; @@ -1264,7 +1293,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, c_list_link_tail (&priv->call_ids_lst_head, &call_id->call_ids_lst); /* Make sure the request actually requests something we can return */ - if (!nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name)) { + if (!nm_connection_get_setting_by_name (nm_settings_connection_get_connection (self), setting_name)) { g_set_error (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, "Connection didn't have requested setting '%s'.", setting_name); @@ -1295,7 +1324,7 @@ nm_settings_connection_get_secrets (NMSettingsConnection *self, call_id_a = nm_agent_manager_get_secrets (priv->agent_mgr, nm_dbus_object_get_path (NM_DBUS_OBJECT (self)), - NM_CONNECTION (self), + nm_settings_connection_get_connection (self), subject, existing_secrets, setting_name, @@ -1465,7 +1494,7 @@ auth_start (NMSettingsConnection *self, nm_assert (G_IS_DBUS_METHOD_INVOCATION (invocation)); nm_assert (NM_IS_AUTH_SUBJECT (subject)); - if (!nm_auth_is_subject_in_acl_set_error (NM_CONNECTION (self), + if (!nm_auth_is_subject_in_acl_set_error (nm_settings_connection_get_connection (self), subject, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, @@ -1539,15 +1568,14 @@ get_settings_auth_cb (NMSettingsConnection *self, if (error) g_dbus_method_invocation_return_gerror (context, error); else { + gs_unref_object NMConnection *dupl_con = NULL; GVariant *settings; - NMConnection *dupl_con; NMSettingConnection *s_con; NMSettingWireless *s_wifi; guint64 timestamp = 0; - char **bssids; + gs_free char **bssids = NULL; - dupl_con = nm_simple_connection_new_clone (NM_CONNECTION (self)); - g_assert (dupl_con); + dupl_con = nm_simple_connection_new_clone (nm_settings_connection_get_connection (self)); /* Timestamp is not updated in connection's 'timestamp' property, * because it would force updating the connection and in turn @@ -1557,8 +1585,7 @@ get_settings_auth_cb (NMSettingsConnection *self, */ nm_settings_connection_get_timestamp (self, ×tamp); if (timestamp) { - s_con = nm_connection_get_setting_connection (NM_CONNECTION (dupl_con)); - g_assert (s_con); + s_con = nm_connection_get_setting_connection (dupl_con); g_object_set (s_con, NM_SETTING_CONNECTION_TIMESTAMP, timestamp, NULL); } /* Seen BSSIDs are not updated in 802-11-wireless 'seen-bssids' property @@ -1566,20 +1593,17 @@ get_settings_auth_cb (NMSettingsConnection *self, * return settings too. */ bssids = nm_settings_connection_get_seen_bssids (self); - s_wifi = nm_connection_get_setting_wireless (NM_CONNECTION (dupl_con)); + s_wifi = nm_connection_get_setting_wireless (dupl_con); if (bssids && bssids[0] && s_wifi) g_object_set (s_wifi, NM_SETTING_WIRELESS_SEEN_BSSIDS, bssids, NULL); - g_free (bssids); /* Secrets should *never* be returned by the GetSettings method, they * get returned by the GetSecrets method which can be better * protected against leakage of secrets to unprivileged callers. */ - settings = nm_connection_to_dbus (NM_CONNECTION (dupl_con), NM_CONNECTION_SERIALIZE_NO_SECRETS); - g_assert (settings); + settings = nm_connection_to_dbus (dupl_con, NM_CONNECTION_SERIALIZE_NO_SECRETS); g_dbus_method_invocation_return_value (context, g_variant_new ("(@a{sa{sv}})", settings)); - g_object_unref (dupl_con); } } @@ -1734,7 +1758,7 @@ update_auth_cb (NMSettingsConnection *self, gs_unref_hashtable GHashTable *diff = NULL; gboolean same; - same = nm_connection_diff (NM_CONNECTION (self), info->new_settings, + same = nm_connection_diff (nm_settings_connection_get_connection (self), info->new_settings, NM_SETTING_COMPARE_FLAG_EXACT | NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT, &diff); @@ -1745,7 +1769,7 @@ update_auth_cb (NMSettingsConnection *self, commit_reason = NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION; if ( info->new_settings - && !nm_streq0 (nm_connection_get_id (NM_CONNECTION (self)), + && !nm_streq0 (nm_connection_get_id (nm_settings_connection_get_connection (self)), nm_connection_get_id (info->new_settings))) commit_reason |= NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED; @@ -1791,7 +1815,7 @@ update_auth_cb (NMSettingsConnection *self, * as agent-owned secrets are the only ones we send back be saved. * Only send secrets to agents of the same UID that called update too. */ - for_agent = nm_simple_connection_new_clone (NM_CONNECTION (self)); + for_agent = nm_simple_connection_new_clone (nm_settings_connection_get_connection (self)); nm_connection_clear_secrets_with_flags (for_agent, secrets_filter_cb, GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED)); @@ -1811,11 +1835,9 @@ get_update_modify_permission (NMConnection *old, NMConnection *new) guint32 orig_num = 0, new_num = 0; s_con = nm_connection_get_setting_connection (old); - g_assert (s_con); orig_num = nm_setting_connection_get_num_permissions (s_con); s_con = nm_connection_get_setting_connection (new); - g_assert (s_con); new_num = nm_setting_connection_get_num_permissions (s_con); /* If the caller is the only user in either connection's permissions, then @@ -1848,7 +1870,7 @@ settings_connection_update (NMSettingsConnection *self, * the problem (ex a system settings plugin that can't write connections out) * instead of over D-Bus. */ - if (!check_writable (NM_CONNECTION (self), &error)) + if (!check_writable (nm_settings_connection_get_connection (self), &error)) goto error; /* Check if the settings are valid first */ @@ -1879,7 +1901,7 @@ settings_connection_update (NMSettingsConnection *self, * that's sending the update request. You can't make a connection * invisible to yourself. */ - if (!nm_auth_is_subject_in_acl_set_error (tmp ?: NM_CONNECTION(self), + if (!nm_auth_is_subject_in_acl_set_error (tmp ?: nm_settings_connection_get_connection (self), subject, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, @@ -1894,8 +1916,8 @@ settings_connection_update (NMSettingsConnection *self, info->flags = flags; info->new_settings = tmp; - permission = get_update_modify_permission (NM_CONNECTION (self), - tmp ?: NM_CONNECTION(self)); + permission = get_update_modify_permission (nm_settings_connection_get_connection (self), + tmp ?: nm_settings_connection_get_connection (self)); auth_start (self, context, subject, permission, update_auth_cb, info); return; @@ -2066,8 +2088,7 @@ get_modify_permission_basic (NMSettingsConnection *self) * we use the 'modify.own' permission instead of 'modify.system'. If the * request affects more than just the caller, require 'modify.system'. */ - s_con = nm_connection_get_setting_connection (NM_CONNECTION (self)); - nm_assert (s_con); + s_con = nm_connection_get_setting_connection (nm_settings_connection_get_connection (self)); if (nm_setting_connection_get_num_permissions (s_con) == 1) return NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN; @@ -2087,7 +2108,7 @@ impl_settings_connection_delete (NMDBusObject *obj, gs_unref_object NMAuthSubject *subject = NULL; GError *error = NULL; - if (!check_writable (NM_CONNECTION (self), &error)) + if (!check_writable (nm_settings_connection_get_connection (self), &error)) goto err; subject = _new_auth_subject (invocation, &error); @@ -2122,7 +2143,7 @@ dbus_get_agent_secrets_cb (NMSettingsConnection *self, * secrets from backing storage and those returned from the agent * by the time we get here. */ - dict = nm_connection_to_dbus (NM_CONNECTION (self), NM_CONNECTION_SERIALIZE_ONLY_SECRETS); + dict = nm_connection_to_dbus (nm_settings_connection_get_connection (self), NM_CONNECTION_SERIALIZE_ONLY_SECRETS); if (!dict) dict = g_variant_new_array (G_VARIANT_TYPE ("{sa{sv}}"), NULL, 0); g_dbus_method_invocation_return_value (context, g_variant_new ("(@a{sa{sv}})", dict)); @@ -2204,7 +2225,7 @@ dbus_clear_secrets_auth_cb (NMSettingsConnection *self, } /* Clear secrets in connection and caches */ - nm_connection_clear_secrets (NM_CONNECTION (self)); + nm_connection_clear_secrets (nm_settings_connection_get_connection (self)); if (priv->system_secrets) nm_connection_clear_secrets (priv->system_secrets); if (priv->agent_secrets) @@ -2213,7 +2234,7 @@ dbus_clear_secrets_auth_cb (NMSettingsConnection *self, /* Tell agents to remove secrets for this connection */ nm_agent_manager_delete_secrets (priv->agent_mgr, nm_dbus_object_get_path (NM_DBUS_OBJECT (self)), - NM_CONNECTION (self)); + nm_settings_connection_get_connection (self)); nm_settings_connection_update (self, NULL, @@ -2388,15 +2409,8 @@ _cmp_timestamp (NMSettingsConnection *a, NMSettingsConnection *b) static int _cmp_last_resort (NMSettingsConnection *a, NMSettingsConnection *b) { - int c; - - nm_assert (NM_IS_SETTINGS_CONNECTION (a)); - nm_assert (NM_IS_SETTINGS_CONNECTION (b)); - - c = g_strcmp0 (nm_connection_get_uuid (NM_CONNECTION (a)), - nm_connection_get_uuid (NM_CONNECTION (b))); - if (c) - return c; + NM_CMP_DIRECT_STRCMP0 (nm_settings_connection_get_uuid (a), + nm_settings_connection_get_uuid (b)); /* hm, same UUID. Use their pointer value to give them a stable * order. */ @@ -2411,19 +2425,11 @@ _cmp_last_resort (NMSettingsConnection *a, NMSettingsConnection *b) int nm_settings_connection_cmp_timestamp (NMSettingsConnection *a, NMSettingsConnection *b) { - int c; + NM_CMP_SELF (a, b); - if (a == b) - return 0; - if (!a) - return 1; - if (!b) - return -1; - - if ((c = _cmp_timestamp (a, b))) - return c; - if ((c = nm_utils_cmp_connection_by_autoconnect_priority (NM_CONNECTION (a), NM_CONNECTION (b)))) - return c; + NM_CMP_RETURN (_cmp_timestamp (a, b)); + NM_CMP_RETURN (nm_utils_cmp_connection_by_autoconnect_priority (nm_settings_connection_get_connection (a), + nm_settings_connection_get_connection (b))); return _cmp_last_resort (a, b); } @@ -2437,14 +2443,11 @@ nm_settings_connection_cmp_timestamp_p_with_data (gconstpointer pa, gconstpointe int nm_settings_connection_cmp_autoconnect_priority (NMSettingsConnection *a, NMSettingsConnection *b) { - int c; - if (a == b) return 0; - if ((c = nm_utils_cmp_connection_by_autoconnect_priority (NM_CONNECTION (a), NM_CONNECTION (b)))) - return c; - if ((c = _cmp_timestamp (a, b))) - return c; + NM_CMP_RETURN (nm_utils_cmp_connection_by_autoconnect_priority (nm_settings_connection_get_connection (a), + nm_settings_connection_get_connection (b))); + NM_CMP_RETURN (_cmp_timestamp (a, b)); return _cmp_last_resort (a, b); } @@ -2507,6 +2510,8 @@ nm_settings_connection_update_timestamp (NMSettingsConnection *self, if (flush_to_disk == FALSE) return; + if (nm_config_get_configure_and_quit (nm_config_get ()) == NM_CONFIG_CONFIGURE_AND_QUIT_INITRD) + return; /* Save timestamp to timestamps database file */ timestamps_file = g_key_file_new (); @@ -2727,7 +2732,7 @@ nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *self) * seen-bssids list from the deprecated seen-bssids property of the * wifi setting. */ - s_wifi = nm_connection_get_setting_wireless (NM_CONNECTION (self)); + s_wifi = nm_connection_get_setting_wireless (nm_settings_connection_get_connection (self)); if (s_wifi) { len = nm_setting_wireless_get_num_seen_bssids (s_wifi); for (i = 0; i < len; i++) { @@ -2747,7 +2752,7 @@ _autoconnect_retries_initial (NMSettingsConnection *self) NMSettingConnection *s_con; int retries = -1; - s_con = nm_connection_get_setting_connection ((NMConnection *) self); + s_con = nm_connection_get_setting_connection (nm_settings_connection_get_connection (self)); if (s_con) retries = nm_setting_connection_get_autoconnect_retries (s_con); @@ -2959,13 +2964,19 @@ nm_settings_connection_get_filename (NMSettingsConnection *self) const char * nm_settings_connection_get_id (NMSettingsConnection *self) { - return nm_connection_get_id (NM_CONNECTION (self)); + return nm_connection_get_id (nm_settings_connection_get_connection (self)); } const char * nm_settings_connection_get_uuid (NMSettingsConnection *self) { - return nm_connection_get_uuid (NM_CONNECTION (self)); + return nm_connection_get_uuid (nm_settings_connection_get_connection (self)); +} + +const char * +nm_settings_connection_get_connection_type (NMSettingsConnection *self) +{ + return nm_connection_get_connection_type (nm_settings_connection_get_connection (self)); } /*****************************************************************************/ @@ -2995,8 +3006,10 @@ nm_settings_connection_init (NMSettingsConnection *self) priv->autoconnect_retries = AUTOCONNECT_RETRIES_UNSET; - g_signal_connect (self, NM_CONNECTION_SECRETS_CLEARED, G_CALLBACK (secrets_cleared_cb), NULL); - g_signal_connect (self, NM_CONNECTION_CHANGED, G_CALLBACK (connection_changed_cb), NULL); + priv->connection = nm_simple_connection_new (); + + g_signal_connect (priv->connection, NM_CONNECTION_SECRETS_CLEARED, G_CALLBACK (secrets_cleared_cb), self); + g_signal_connect (priv->connection, NM_CONNECTION_CHANGED, G_CALLBACK (connection_changed_cb), self); } static void @@ -3027,26 +3040,32 @@ dispose (GObject *object) _get_secrets_cancel (self, call_id, TRUE); } - /* Disconnect handlers. - * connection_changed_cb() has to be disconnected *before* nm_connection_clear_secrets(), - * because nm_connection_clear_secrets() emits NM_CONNECTION_CHANGED signal. - */ - g_signal_handlers_disconnect_by_func (self, G_CALLBACK (secrets_cleared_cb), NULL); - g_signal_handlers_disconnect_by_func (self, G_CALLBACK (connection_changed_cb), NULL); + set_visible (self, FALSE); + + if (priv->connection) { + /* Disconnect handlers. + * connection_changed_cb() has to be disconnected *before* nm_connection_clear_secrets(), + * because nm_connection_clear_secrets() emits NM_CONNECTION_CHANGED signal. + */ + g_signal_handlers_disconnect_by_func (priv->connection, G_CALLBACK (secrets_cleared_cb), self); + g_signal_handlers_disconnect_by_func (priv->connection, G_CALLBACK (connection_changed_cb), self); + + /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */ + nm_connection_clear_secrets (priv->connection); + } - nm_connection_clear_secrets (NM_CONNECTION (self)); g_clear_object (&priv->system_secrets); g_clear_object (&priv->agent_secrets); g_clear_pointer (&priv->seen_bssids, g_hash_table_destroy); - set_visible (self, FALSE); - nm_clear_g_signal_handler (priv->session_monitor, &priv->session_changed_id); g_clear_object (&priv->session_monitor); g_clear_object (&priv->agent_mgr); + g_clear_object (&priv->connection); + g_clear_pointer (&priv->filename, g_free); G_OBJECT_CLASS (nm_settings_connection_parent_class)->dispose (object); @@ -3264,9 +3283,3 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *klass) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } - -static void -nm_settings_connection_connection_interface_init (NMConnectionInterface *iface) -{ -} - diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h index cd64f976..e796b716 100644 --- a/src/settings/nm-settings-connection.h +++ b/src/settings/nm-settings-connection.h @@ -139,6 +139,8 @@ struct _NMSettingsConnectionClass { GType nm_settings_connection_get_type (void); +NMConnection *nm_settings_connection_get_connection (NMSettingsConnection *self); + guint64 nm_settings_connection_get_last_secret_agent_version_id (NMSettingsConnection *self); gboolean nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection *self, @@ -268,7 +270,13 @@ void nm_settings_connection_set_filename (NMSettingsConnection *self, const char *filename); const char *nm_settings_connection_get_filename (NMSettingsConnection *self); -const char *nm_settings_connection_get_id (NMSettingsConnection *connection); -const char *nm_settings_connection_get_uuid (NMSettingsConnection *connection); +const char *nm_settings_connection_get_id (NMSettingsConnection *connection); +const char *nm_settings_connection_get_uuid (NMSettingsConnection *connection); +const char *nm_settings_connection_get_connection_type (NMSettingsConnection *connection); + +/*****************************************************************************/ + +NMConnection **nm_settings_connections_array_to_connections (NMSettingsConnection *const*connections, + gssize n_connections); #endif /* __NETWORKMANAGER_SETTINGS_CONNECTION_H__ */ diff --git a/src/settings/nm-settings-plugin.c b/src/settings/nm-settings-plugin.c index f6dd2cfb..e7275631 100644 --- a/src/settings/nm-settings-plugin.c +++ b/src/settings/nm-settings-plugin.c @@ -15,117 +15,94 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2007 - 2011 Red Hat, Inc. + * Copyright (C) 2007 - 2018 Red Hat, Inc. * Copyright (C) 2008 Novell, Inc. */ #include "nm-default.h" #include "nm-settings-plugin.h" + #include "nm-settings-connection.h" -G_DEFINE_INTERFACE (NMSettingsPlugin, nm_settings_plugin, G_TYPE_OBJECT) +/*****************************************************************************/ -static void -nm_settings_plugin_default_init (NMSettingsPluginInterface *g_iface) -{ - GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); - static gboolean initialized = FALSE; - - if (initialized) - return; - - /* Signals */ - g_signal_new (NM_SETTINGS_PLUGIN_CONNECTION_ADDED, - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSettingsPluginInterface, connection_added), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - NM_TYPE_SETTINGS_CONNECTION); - - g_signal_new (NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED, - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSettingsPluginInterface, unmanaged_specs_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - g_signal_new (NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED, - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSettingsPluginInterface, unrecognized_specs_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - initialized = TRUE; -} +enum { + CONNECTION_ADDED, + UNMANAGED_SPECS_CHANGED, + UNRECOGNIZED_SPECS_CHANGED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (NMSettingsPlugin, nm_settings_plugin, G_TYPE_OBJECT) + +/*****************************************************************************/ void -nm_settings_plugin_init (NMSettingsPlugin *config) +nm_settings_plugin_initialize (NMSettingsPlugin *self) { - g_return_if_fail (config != NULL); + g_return_if_fail (NM_IS_SETTINGS_PLUGIN (self)); - if (NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->init) - NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->init (config); + if (NM_SETTINGS_PLUGIN_GET_CLASS (self)->initialize) + NM_SETTINGS_PLUGIN_GET_CLASS (self)->initialize (self); } GSList * -nm_settings_plugin_get_connections (NMSettingsPlugin *config) +nm_settings_plugin_get_connections (NMSettingsPlugin *self) { - g_return_val_if_fail (config != NULL, NULL); + g_return_val_if_fail (NM_IS_SETTINGS_PLUGIN (self), NULL); - if (NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->get_connections) - return NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->get_connections (config); + if (NM_SETTINGS_PLUGIN_GET_CLASS (self)->get_connections) + return NM_SETTINGS_PLUGIN_GET_CLASS (self)->get_connections (self); return NULL; } gboolean -nm_settings_plugin_load_connection (NMSettingsPlugin *config, +nm_settings_plugin_load_connection (NMSettingsPlugin *self, const char *filename) { - g_return_val_if_fail (config != NULL, FALSE); + g_return_val_if_fail (NM_IS_SETTINGS_PLUGIN (self), FALSE); - if (NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->load_connection) - return NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->load_connection (config, filename); + if (NM_SETTINGS_PLUGIN_GET_CLASS (self)->load_connection) + return NM_SETTINGS_PLUGIN_GET_CLASS (self)->load_connection (self, filename); return FALSE; } void -nm_settings_plugin_reload_connections (NMSettingsPlugin *config) +nm_settings_plugin_reload_connections (NMSettingsPlugin *self) { - g_return_if_fail (config != NULL); + g_return_if_fail (NM_IS_SETTINGS_PLUGIN (self)); - if (NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->reload_connections) - NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->reload_connections (config); + if (NM_SETTINGS_PLUGIN_GET_CLASS (self)->reload_connections) + NM_SETTINGS_PLUGIN_GET_CLASS (self)->reload_connections (self); } GSList * -nm_settings_plugin_get_unmanaged_specs (NMSettingsPlugin *config) +nm_settings_plugin_get_unmanaged_specs (NMSettingsPlugin *self) { - g_return_val_if_fail (config != NULL, NULL); + g_return_val_if_fail (NM_IS_SETTINGS_PLUGIN (self), NULL); - if (NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->get_unmanaged_specs) - return NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->get_unmanaged_specs (config); + if (NM_SETTINGS_PLUGIN_GET_CLASS (self)->get_unmanaged_specs) + return NM_SETTINGS_PLUGIN_GET_CLASS (self)->get_unmanaged_specs (self); return NULL; } GSList * -nm_settings_plugin_get_unrecognized_specs (NMSettingsPlugin *config) +nm_settings_plugin_get_unrecognized_specs (NMSettingsPlugin *self) { - g_return_val_if_fail (config != NULL, NULL); + g_return_val_if_fail (NM_IS_SETTINGS_PLUGIN (self), NULL); - if (NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->get_unrecognized_specs) - return NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->get_unrecognized_specs (config); + if (NM_SETTINGS_PLUGIN_GET_CLASS (self)->get_unrecognized_specs) + return NM_SETTINGS_PLUGIN_GET_CLASS (self)->get_unrecognized_specs (self); return NULL; } /** * nm_settings_plugin_add_connection: - * @config: the #NMSettingsPlugin + * @self: the #NMSettingsPlugin * @connection: the source connection to create a plugin-specific * #NMSettingsConnection from * @save_to_disk: %TRUE to save the connection to disk immediately, %FALSE to @@ -140,22 +117,88 @@ nm_settings_plugin_get_unrecognized_specs (NMSettingsPlugin *config) * Returns: the new #NMSettingsConnection or %NULL */ NMSettingsConnection * -nm_settings_plugin_add_connection (NMSettingsPlugin *config, +nm_settings_plugin_add_connection (NMSettingsPlugin *self, NMConnection *connection, gboolean save_to_disk, GError **error) { - NMSettingsPluginInterface *config_interface; + NMSettingsPluginClass *klass; - g_return_val_if_fail (config != NULL, NULL); + g_return_val_if_fail (NM_IS_SETTINGS_PLUGIN (self), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - config_interface = NM_SETTINGS_PLUGIN_GET_INTERFACE (config); - if (!config_interface->add_connection) { + klass = NM_SETTINGS_PLUGIN_GET_CLASS (self); + if (!klass->add_connection) { g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_NOT_SUPPORTED, "Plugin does not support adding connections"); return NULL; } - return config_interface->add_connection (config, connection, save_to_disk, error); + return klass->add_connection (self, connection, save_to_disk, error); +} + +/*****************************************************************************/ + +void +_nm_settings_plugin_emit_signal_connection_added (NMSettingsPlugin *self, + NMSettingsConnection *sett_conn) +{ + nm_assert (NM_IS_SETTINGS_PLUGIN (self)); + nm_assert (NM_IS_SETTINGS_CONNECTION (sett_conn)); + + g_signal_emit (self, signals[CONNECTION_ADDED], 0, sett_conn); +} + +void +_nm_settings_plugin_emit_signal_unmanaged_specs_changed (NMSettingsPlugin *self) +{ + nm_assert (NM_IS_SETTINGS_PLUGIN (self)); + + g_signal_emit (self, signals[UNMANAGED_SPECS_CHANGED], 0); +} + +void +_nm_settings_plugin_emit_signal_unrecognized_specs_changed (NMSettingsPlugin *self) +{ + nm_assert (NM_IS_SETTINGS_PLUGIN (self)); + + g_signal_emit (self, signals[UNRECOGNIZED_SPECS_CHANGED], 0); +} + +/*****************************************************************************/ + +static void +nm_settings_plugin_init (NMSettingsPlugin *self) +{ +} + +static void +nm_settings_plugin_class_init (NMSettingsPluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + signals[CONNECTION_ADDED] = + g_signal_new (NM_SETTINGS_PLUGIN_CONNECTION_ADDED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + NM_TYPE_SETTINGS_CONNECTION); + + signals[UNMANAGED_SPECS_CHANGED] = + g_signal_new (NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[UNRECOGNIZED_SPECS_CHANGED] = + g_signal_new (NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } diff --git a/src/settings/nm-settings-plugin.h b/src/settings/nm-settings-plugin.h index 6fba25e7..fdd48f2b 100644 --- a/src/settings/nm-settings-plugin.h +++ b/src/settings/nm-settings-plugin.h @@ -15,53 +15,52 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2007 - 2011 Red Hat, Inc. + * Copyright (C) 2007 - 2018 Red Hat, Inc. * Copyright (C) 2008 Novell, Inc. */ -#ifndef __NETWORKMANAGER_SETTINGS_PLUGIN_H__ -#define __NETWORKMANAGER_SETTINGS_PLUGIN_H__ +#ifndef __NM_SETTINGS_PLUGIN_H__ +#define __NM_SETTINGS_PLUGIN_H__ #include "nm-connection.h" -/* Plugin's factory function that returns a GObject that implements - * NMSettingsPlugin. - */ -GObject * nm_settings_plugin_factory (void); - #define NM_TYPE_SETTINGS_PLUGIN (nm_settings_plugin_get_type ()) #define NM_SETTINGS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTINGS_PLUGIN, NMSettingsPlugin)) +#define NM_SETTINGS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTINGS_PLUGIN, NMSettingsPluginClass)) #define NM_IS_SETTINGS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTINGS_PLUGIN)) -#define NM_SETTINGS_PLUGIN_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_SETTINGS_PLUGIN, NMSettingsPluginInterface)) +#define NM_IS_SETTINGS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTINGS_PLUGIN)) +#define NM_SETTINGS_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTINGS_PLUGIN, NMSettingsPluginClass)) -#define NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED "unmanaged-specs-changed" +#define NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED "unmanaged-specs-changed" #define NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED "unrecognized-specs-changed" -#define NM_SETTINGS_PLUGIN_CONNECTION_ADDED "connection-added" +#define NM_SETTINGS_PLUGIN_CONNECTION_ADDED "connection-added" -typedef struct _NMSettingsPlugin NMSettingsPlugin; +typedef struct { + GObject parent; +} NMSettingsPlugin; typedef struct { - GTypeInterface g_iface; + GObjectClass parent; /* Called when the plugin is loaded to initialize it */ - void (*init) (NMSettingsPlugin *config); + void (*initialize) (NMSettingsPlugin *plugin); /* Returns a GSList of NMSettingsConnection objects that represent * connections the plugin knows about. The returned list is freed by the * system settings service. */ - GSList * (*get_connections) (NMSettingsPlugin *config); + GSList * (*get_connections) (NMSettingsPlugin *plugin); /* Requests that the plugin load/reload a single connection, if it * recognizes the filename. Returns success or failure. */ - gboolean (*load_connection) (NMSettingsPlugin *config, + gboolean (*load_connection) (NMSettingsPlugin *plugin, const char *filename); /* Requests that the plugin reload all connection files from disk, * and emit signals reflecting new, changed, and removed connections. */ - void (*reload_connections) (NMSettingsPlugin *config); + void (*reload_connections) (NMSettingsPlugin *plugin); /* * Return a string list of specifications of devices which NetworkManager @@ -72,7 +71,7 @@ typedef struct { * Each string in the list must be in one of the formats recognized by * nm_device_spec_match_list(). */ - GSList * (*get_unmanaged_specs) (NMSettingsPlugin *config); + GSList * (*get_unmanaged_specs) (NMSettingsPlugin *plugin); /* * Return a string list of specifications of devices for which at least @@ -84,7 +83,7 @@ typedef struct { * Each string in the list must be in one of the formats recognized by * nm_device_spec_match_list(). */ - GSList * (*get_unrecognized_specs) (NMSettingsPlugin *config); + GSList * (*get_unrecognized_specs) (NMSettingsPlugin *plugin); /* * Initialize the plugin-specific connection and return a new @@ -93,40 +92,42 @@ typedef struct { * storage if @save_to_disk is TRUE. The returned object is owned by the * plugin and must be referenced by the owner if necessary. */ - NMSettingsConnection * (*add_connection) (NMSettingsPlugin *config, + NMSettingsConnection * (*add_connection) (NMSettingsPlugin *plugin, NMConnection *connection, gboolean save_to_disk, GError **error); +} NMSettingsPluginClass; - /* Signals */ - - /* Emitted when a new connection has been found by the plugin */ - void (*connection_added) (NMSettingsPlugin *config, - NMSettingsConnection *connection); +GType nm_settings_plugin_get_type (void); - /* Emitted when the list of unmanaged device specifications changes */ - void (*unmanaged_specs_changed) (NMSettingsPlugin *config); +typedef NMSettingsPlugin *(*NMSettingsPluginFactoryFunc) (void); - /* Emitted when the list of devices with unrecognized connections changes */ - void (*unrecognized_specs_changed) (NMSettingsPlugin *config); -} NMSettingsPluginInterface; +/* Plugin's factory function that returns a #NMSettingsPlugin */ +NMSettingsPlugin *nm_settings_plugin_factory (void); -GType nm_settings_plugin_get_type (void); +void nm_settings_plugin_initialize (NMSettingsPlugin *config); -void nm_settings_plugin_init (NMSettingsPlugin *config); +GSList *nm_settings_plugin_get_connections (NMSettingsPlugin *plugin); -GSList *nm_settings_plugin_get_connections (NMSettingsPlugin *config); - -gboolean nm_settings_plugin_load_connection (NMSettingsPlugin *config, +gboolean nm_settings_plugin_load_connection (NMSettingsPlugin *plugin, const char *filename); -void nm_settings_plugin_reload_connections (NMSettingsPlugin *config); +void nm_settings_plugin_reload_connections (NMSettingsPlugin *plugin); -GSList *nm_settings_plugin_get_unmanaged_specs (NMSettingsPlugin *config); -GSList *nm_settings_plugin_get_unrecognized_specs (NMSettingsPlugin *config); +GSList *nm_settings_plugin_get_unmanaged_specs (NMSettingsPlugin *plugin); +GSList *nm_settings_plugin_get_unrecognized_specs (NMSettingsPlugin *plugin); -NMSettingsConnection *nm_settings_plugin_add_connection (NMSettingsPlugin *config, +NMSettingsConnection *nm_settings_plugin_add_connection (NMSettingsPlugin *plugin, NMConnection *connection, gboolean save_to_disk, GError **error); -#endif /* __NETWORKMANAGER_SETTINGS_PLUGIN_H__ */ +/* internal API */ + +void _nm_settings_plugin_emit_signal_connection_added (NMSettingsPlugin *plugin, + NMSettingsConnection *sett_conn); + +void _nm_settings_plugin_emit_signal_unmanaged_specs_changed (NMSettingsPlugin *plugin); + +void _nm_settings_plugin_emit_signal_unrecognized_specs_changed (NMSettingsPlugin *plugin); + +#endif /* __NM_SETTINGS_PLUGIN_H__ */ diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 5bb629dc..2253d56a 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -214,9 +214,9 @@ connection_ready_changed (NMSettingsConnection *conn, static void plugin_connection_added (NMSettingsPlugin *config, NMSettingsConnection *connection, - gpointer user_data) + NMSettings *self) { - claim_connection (NM_SETTINGS (user_data), connection); + claim_connection (self, connection); } static void @@ -237,7 +237,7 @@ load_connections (NMSettings *self) // priority plugin. for (elt = plugin_connections; elt; elt = g_slist_next (elt)) - claim_connection (self, NM_SETTINGS_CONNECTION (elt->data)); + claim_connection (self, elt->data); g_slist_free (plugin_connections); @@ -306,15 +306,15 @@ impl_settings_get_connection_by_uuid (NMDBusObject *obj, GVariant *parameters) { NMSettings *self = NM_SETTINGS (obj); - NMSettingsConnection *connection = NULL; + NMSettingsConnection *sett_conn; gs_unref_object NMAuthSubject *subject = NULL; GError *error = NULL; const char *uuid; g_variant_get (parameters, "(&s)", &uuid); - connection = nm_settings_get_connection_by_uuid (self, uuid); - if (!connection) { + sett_conn = nm_settings_get_connection_by_uuid (self, uuid); + if (!sett_conn) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "No connection with the UUID was found."); @@ -329,7 +329,7 @@ impl_settings_get_connection_by_uuid (NMDBusObject *obj, goto error; } - if (!nm_auth_is_subject_in_acl_set_error (NM_CONNECTION (connection), + if (!nm_auth_is_subject_in_acl_set_error (nm_settings_connection_get_connection (sett_conn), subject, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, @@ -338,7 +338,7 @@ impl_settings_get_connection_by_uuid (NMDBusObject *obj, g_dbus_method_invocation_return_value (invocation, g_variant_new ("(o)", - nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)))); + nm_dbus_object_get_path (NM_DBUS_OBJECT (sett_conn)))); return; error: @@ -362,6 +362,7 @@ _clear_connections_cached_list (NMSettingsPrivate *priv) 0xdeaddead, sizeof (NMSettingsConnection *) * (priv->connections_len + 1)); #endif + nm_clear_g_free (&priv->connections_cached_list); } @@ -480,8 +481,8 @@ nm_settings_get_connection_by_path (NMSettings *self, const char *path) priv = NM_SETTINGS_GET_PRIVATE (self); - connection = (NMSettingsConnection *) nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), - path); + connection = nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (self)), + path); if ( !connection || !NM_IS_SETTINGS_CONNECTION (connection)) return NULL; @@ -525,28 +526,6 @@ nm_settings_get_unmanaged_specs (NMSettings *self) return priv->unmanaged_specs; } -static NMSettingsPlugin * -get_plugin (NMSettings *self, gboolean has_add_connection) -{ - NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - GSList *iter; - - g_return_val_if_fail (self != NULL, NULL); - - /* Do any of the plugins support the given capability? */ - for (iter = priv->plugins; iter; iter = iter->next) { - NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); - - if (!has_add_connection) - return plugin; - - if (NM_SETTINGS_PLUGIN_GET_INTERFACE (iter->data)->add_connection != NULL) - return plugin; - } - - return NULL; -} - static gboolean find_spec (GSList *spec_list, const char *spec) { @@ -607,67 +586,49 @@ unrecognized_specs_changed (NMSettingsPlugin *config, nm_settings_plugin_get_unrecognized_specs); } -static gboolean -add_plugin (NMSettings *self, NMSettingsPlugin *plugin) +static void +add_plugin (NMSettings *self, NMSettingsPlugin *plugin, const char *path) { NMSettingsPrivate *priv; - const char *path; - g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE); - g_return_val_if_fail (NM_IS_SETTINGS_PLUGIN (plugin), FALSE); + nm_assert (NM_IS_SETTINGS (self)); + nm_assert (NM_IS_SETTINGS_PLUGIN (plugin)); priv = NM_SETTINGS_GET_PRIVATE (self); - if (g_slist_find (priv->plugins, plugin)) { - /* don't add duplicates. */ - return FALSE; - } + nm_assert (!g_slist_find (priv->plugins, plugin)); priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin)); - nm_settings_plugin_init (plugin); - - - path = g_object_get_qdata (G_OBJECT (plugin), plugin_module_path_quark ()); - - _LOGI ("Loaded settings plugin: %s (%s)", G_OBJECT_TYPE_NAME (plugin), path ?: "internal"); - - return TRUE; -} - -static gboolean -plugin_loaded (GSList *list, const char *path) -{ - GSList *iter; - g_return_val_if_fail (path != NULL, TRUE); + nm_settings_plugin_initialize (plugin); - for (iter = list; iter; iter = g_slist_next (iter)) { - const char *list_path = g_object_get_qdata (G_OBJECT (iter->data), - plugin_module_path_quark ()); - - if (g_strcmp0 (path, list_path) == 0) - return TRUE; - } - - return FALSE; + _LOGI ("Loaded settings plugin: %s (%s%s%s)", + G_OBJECT_TYPE_NAME (plugin), + NM_PRINT_FMT_QUOTED (path, "\"", path, "\"", "internal")); } static gboolean -load_plugin (NMSettings *self, GSList **list, const char *pname, GError **error) +add_plugin_load_file (NMSettings *self, const char *pname, GError **error) { + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); gs_free char *full_name = NULL; gs_free char *path = NULL; - gs_unref_object GObject *obj = NULL; - GModule *plugin; - GObject * (*factory_func) (void); + gs_unref_object NMSettingsPlugin *plugin = NULL; + GModule *module; + NMSettingsPluginFactoryFunc factory_func; + GSList *iter; struct stat st; int errsv; full_name = g_strdup_printf ("nm-settings-plugin-%s", pname); path = g_module_build_path (NMPLUGINDIR, full_name); - if (plugin_loaded (*list, path)) - return TRUE; + for (iter = priv->plugins; iter; iter = iter->next) { + if (nm_streq0 (path, + g_object_get_qdata (iter->data, + plugin_module_path_quark ()))) + return TRUE; + } if (stat (path, &st) != 0) { errsv = errno; @@ -687,8 +648,8 @@ load_plugin (NMSettings *self, GSList **list, const char *pname, GError **error) return TRUE; } - plugin = g_module_open (path, G_MODULE_BIND_LOCAL); - if (!plugin) { + module = g_module_open (path, G_MODULE_BIND_LOCAL); + if (!module) { _LOGW ("could not load plugin '%s' from file '%s': %s", pname, path, g_module_error ()); return TRUE; @@ -696,48 +657,46 @@ load_plugin (NMSettings *self, GSList **list, const char *pname, GError **error) /* errors after this point are fatal, because we loaded the shared library already. */ - if (!g_module_symbol (plugin, "nm_settings_plugin_factory", (gpointer) (&factory_func))) { + if (!g_module_symbol (module, "nm_settings_plugin_factory", (gpointer) (&factory_func))) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Could not find plugin '%s' factory function.", pname); - g_module_close (plugin); + g_module_close (module); return FALSE; } /* after accessing the plugin we cannot unload it anymore, because the glib * types cannot be properly unregistered. */ - g_module_make_resident (plugin); + g_module_make_resident (module); - obj = (*factory_func) (); - if (!obj || !NM_IS_SETTINGS_PLUGIN (obj)) { + plugin = (*factory_func) (); + if (!NM_IS_SETTINGS_PLUGIN (plugin)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "Plugin '%s' returned invalid system config object.", + "plugin '%s' returned invalid settings plugin", pname); return FALSE; } - g_object_set_qdata_full (obj, plugin_module_path_quark (), path, g_free); - path = NULL; - if (add_plugin (self, NM_SETTINGS_PLUGIN (obj))) - *list = g_slist_append (*list, g_steal_pointer (&obj)); - + add_plugin (self, NM_SETTINGS_PLUGIN (plugin), path); + g_object_set_qdata_full (G_OBJECT (plugin), + plugin_module_path_quark (), + g_steal_pointer (&path), + g_free); return TRUE; } static void -add_keyfile_plugin (NMSettings *self) +add_plugin_keyfile (NMSettings *self) { gs_unref_object NMSKeyfilePlugin *keyfile_plugin = NULL; keyfile_plugin = nms_keyfile_plugin_new (); - if (!add_plugin (self, NM_SETTINGS_PLUGIN (keyfile_plugin))) - g_return_if_reached (); + add_plugin (self, NM_SETTINGS_PLUGIN (keyfile_plugin), NULL); } static gboolean load_plugins (NMSettings *self, const char **plugins, GError **error) { - GSList *list = NULL; const char **iter; gboolean keyfile_added = FALSE; gboolean success = TRUE; @@ -765,15 +724,15 @@ load_plugins (NMSettings *self, const char **plugins, GError **error) continue; } - if (!strcmp (pname, "no-ibft")) + if (nm_streq (pname, "no-ibft")) continue; - if (has_no_ibft && !strcmp (pname, "ibft")) + if (has_no_ibft && nm_streq (pname, "ibft")) continue; /* keyfile plugin is built-in now */ - if (strcmp (pname, "keyfile") == 0) { + if (nm_streq (pname, "keyfile")) { if (!keyfile_added) { - add_keyfile_plugin (self); + add_plugin_keyfile (self); keyfile_added = TRUE; } continue; @@ -787,27 +746,25 @@ load_plugins (NMSettings *self, const char **plugins, GError **error) continue; } - success = load_plugin (self, &list, pname, error); + success = add_plugin_load_file (self, pname, error); if (!success) break; - if (add_ibft && !strcmp (pname, "ifcfg-rh")) { + if (add_ibft && nm_streq (pname, "ifcfg-rh")) { /* The plugin ibft is not explicitly mentioned but we just enabled "ifcfg-rh". * Enable "ibft" by default after "ifcfg-rh". */ pname = "ibft"; add_ibft = FALSE; - success = load_plugin (self, &list, "ibft", error); + success = add_plugin_load_file (self, "ibft", error); if (!success) break; } } /* If keyfile plugin was not among configured plugins, add it as the last one */ - if (!keyfile_added) - add_keyfile_plugin (self); - - g_slist_free_full (list, g_object_unref); + if (!keyfile_added && success) + add_plugin_keyfile (self); return success; } @@ -931,29 +888,33 @@ openconnect_migrate_hack (NMConnection *connection) } static void -claim_connection (NMSettings *self, NMSettingsConnection *connection) +claim_connection (NMSettings *self, NMSettingsConnection *sett_conn) { - NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + NMSettingsPrivate *priv; GError *error = NULL; const char *path; NMSettingsConnection *existing; - g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); - g_return_if_fail (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (connection))); + g_return_if_fail (NM_IS_SETTINGS (self)); + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (sett_conn)); + g_return_if_fail (!nm_dbus_object_is_exported (NM_DBUS_OBJECT (sett_conn))); + + priv = NM_SETTINGS_GET_PRIVATE (self); /* prevent duplicates */ - if (!c_list_is_empty (&connection->_connections_lst)) { - nm_assert (c_list_contains (&priv->connections_lst_head, &connection->_connections_lst)); + if (!c_list_is_empty (&sett_conn->_connections_lst)) { + nm_assert (c_list_contains (&priv->connections_lst_head, &sett_conn->_connections_lst)); return; } - if (!nm_connection_normalize (NM_CONNECTION (connection), NULL, NULL, &error)) { + /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */ + if (!nm_connection_normalize (nm_settings_connection_get_connection (sett_conn), NULL, NULL, &error)) { _LOGW ("plugin provided invalid connection: %s", error->message); g_error_free (error); return; } - existing = nm_settings_get_connection_by_uuid (self, nm_settings_connection_get_uuid (connection)); + existing = nm_settings_get_connection_by_uuid (self, nm_settings_connection_get_uuid (sett_conn)); if (existing) { /* Cannot add duplicate connections per UUID. Just return without action and * log a warning. @@ -966,51 +927,56 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) * error out. That should not happen unless the admin misconfigured the system * to create conflicting connections. */ _LOGW ("plugin provided duplicate connection with UUID %s", - nm_settings_connection_get_uuid (connection)); + nm_settings_connection_get_uuid (sett_conn)); return; } /* Read timestamp from look-aside file and put it into the connection's data */ - nm_settings_connection_read_and_fill_timestamp (connection); + nm_settings_connection_read_and_fill_timestamp (sett_conn); /* Read seen-bssids from look-aside file and put it into the connection's data */ - nm_settings_connection_read_and_fill_seen_bssids (connection); + nm_settings_connection_read_and_fill_seen_bssids (sett_conn); /* Ensure its initial visibility is up-to-date */ - nm_settings_connection_recheck_visibility (connection); + nm_settings_connection_recheck_visibility (sett_conn); /* Evil openconnect migration hack */ - openconnect_migrate_hack (NM_CONNECTION (connection)); + /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */ + openconnect_migrate_hack (nm_settings_connection_get_connection (sett_conn)); /* This one unexports the connection, it needs to run late to give the active * connection a chance to deal with its reference to this settings connection. */ - g_signal_connect_after (connection, NM_SETTINGS_CONNECTION_REMOVED, + g_signal_connect_after (sett_conn, NM_SETTINGS_CONNECTION_REMOVED, G_CALLBACK (connection_removed), self); - g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, + g_signal_connect (sett_conn, NM_SETTINGS_CONNECTION_UPDATED_INTERNAL, G_CALLBACK (connection_updated), self); - g_signal_connect (connection, NM_SETTINGS_CONNECTION_FLAGS_CHANGED, + g_signal_connect (sett_conn, NM_SETTINGS_CONNECTION_FLAGS_CHANGED, G_CALLBACK (connection_flags_changed), self); if (!priv->startup_complete) { - g_signal_connect (connection, "notify::" NM_SETTINGS_CONNECTION_READY, + g_signal_connect (sett_conn, "notify::" NM_SETTINGS_CONNECTION_READY, G_CALLBACK (connection_ready_changed), self); } _clear_connections_cached_list (priv); - g_object_ref (connection); + g_object_ref (sett_conn); /* FIXME(shutdown): The NMSettings instance can't be disposed * while there is any exported connection. Ideally we should * unexport all connections on NMSettings' disposal, but for now * leak @self on termination when there are connections alive. */ g_object_ref (self); priv->connections_len++; - c_list_link_tail (&priv->connections_lst_head, &connection->_connections_lst); + c_list_link_tail (&priv->connections_lst_head, &sett_conn->_connections_lst); - path = nm_dbus_object_export (NM_DBUS_OBJECT (connection)); + path = nm_dbus_object_export (NM_DBUS_OBJECT (sett_conn)); - nm_utils_log_connection_diff (NM_CONNECTION (connection), NULL, LOGL_DEBUG, LOGD_CORE, "new connection", "++ ", + nm_utils_log_connection_diff (nm_settings_connection_get_connection (sett_conn), + NULL, + LOGL_DEBUG, + LOGD_CORE, + "new connection", "++ ", path); /* Only emit the individual connection-added signal after connections @@ -1021,13 +987,13 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) &interface_info_settings, &signal_info_new_connection, "(o)", - nm_dbus_object_get_path (NM_DBUS_OBJECT (connection))); + nm_dbus_object_get_path (NM_DBUS_OBJECT (sett_conn))); - g_signal_emit (self, signals[CONNECTION_ADDED], 0, connection); + g_signal_emit (self, signals[CONNECTION_ADDED], 0, sett_conn); _notify (self, PROP_CONNECTIONS); } - nm_settings_connection_added (connection); + nm_settings_connection_added (sett_conn); } static gboolean @@ -1079,7 +1045,7 @@ nm_settings_add_connection (NMSettings *self, /* Make sure a connection with this UUID doesn't already exist */ c_list_for_each_entry (candidate, &priv->connections_lst_head, _connections_lst) { - if (nm_streq0 (uuid, nm_connection_get_uuid (NM_CONNECTION (candidate)))) { + if (nm_streq0 (uuid, nm_settings_connection_get_uuid (candidate))) { g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_UUID_EXISTS, @@ -1113,8 +1079,13 @@ nm_settings_add_connection (NMSettings *self, added = nm_settings_plugin_add_connection (plugin, connection, save_to_disk, &add_error); if (added) { - if (secrets) - nm_connection_update_secrets (NM_CONNECTION (added), NULL, secrets, NULL); + if (secrets) { + /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */ + nm_connection_update_secrets (nm_settings_connection_get_connection (added), + NULL, + secrets, + NULL); + } claim_connection (self, added); return added; } @@ -1132,7 +1103,7 @@ nm_settings_add_connection (NMSettings *self, static void send_agent_owned_secrets (NMSettings *self, - NMSettingsConnection *connection, + NMSettingsConnection *sett_conn, NMAuthSubject *subject) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); @@ -1142,12 +1113,12 @@ send_agent_owned_secrets (NMSettings *self, * as agent-owned secrets are the only ones we send back to be saved. * Only send secrets to agents of the same UID that called update too. */ - for_agent = nm_simple_connection_new_clone (NM_CONNECTION (connection)); + for_agent = nm_simple_connection_new_clone (nm_settings_connection_get_connection (sett_conn)); nm_connection_clear_secrets_with_flags (for_agent, secrets_filter_cb, GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED)); nm_agent_manager_save_secrets (priv->agent_mgr, - nm_dbus_object_get_path (NM_DBUS_OBJECT (connection)), + nm_dbus_object_get_path (NM_DBUS_OBJECT (sett_conn)), for_agent, subject); } @@ -1190,7 +1161,8 @@ pk_add_cb (NMAuthChain *chain, } else { /* Authorized */ connection = nm_auth_chain_get_data (chain, "connection"); - g_assert (connection); + nm_assert (connection); + save_to_disk = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "save-to-disk")); added = nm_settings_add_connection (self, connection, save_to_disk, &error); } @@ -1281,14 +1253,6 @@ nm_settings_add_connection_dbus (NMSettings *self, goto done; } - /* Do any of the plugins support adding? */ - if (!get_plugin (self, TRUE)) { - error = g_error_new_literal (NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_NOT_SUPPORTED, - "None of the registered plugins support add."); - goto done; - } - if (!nm_auth_is_subject_in_acl_set_error (connection, subject, NM_SETTINGS_ERROR, @@ -1612,20 +1576,21 @@ have_connection_for_device (NMSettings *self, NMDevice *device) NMSettingWired *s_wired; const char *setting_hwaddr; const char *perm_hw_addr; - NMSettingsConnection *connection; + NMSettingsConnection *sett_conn; g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE); perm_hw_addr = nm_device_get_permanent_hw_address (device); /* Find a wired connection locked to the given MAC address, if any */ - c_list_for_each_entry (connection, &priv->connections_lst_head, _connections_lst) { + c_list_for_each_entry (sett_conn, &priv->connections_lst_head, _connections_lst) { + NMConnection *connection = nm_settings_connection_get_connection (sett_conn); const char *ctype, *iface; - if (!nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) + if (!nm_device_check_connection_compatible (device, connection, NULL)) continue; - s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); + s_con = nm_connection_get_setting_connection (connection); iface = nm_setting_connection_get_interface_name (s_con); if (iface && strcmp (iface, nm_device_get_iface (device)) != 0) @@ -1636,14 +1601,15 @@ have_connection_for_device (NMSettings *self, NMDevice *device) && strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME)) continue; - s_wired = nm_connection_get_setting_wired (NM_CONNECTION (connection)); + s_wired = nm_connection_get_setting_wired (connection); - if (!s_wired && !strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME)) { + if ( !s_wired + && nm_streq (ctype, NM_SETTING_PPPOE_SETTING_NAME)) { /* No wired setting; therefore the PPPoE connection applies to any device */ return TRUE; } - g_assert (s_wired != NULL); + nm_assert (s_wired); setting_hwaddr = nm_setting_wired_get_mac_address (s_wired); if (setting_hwaddr) { @@ -1687,11 +1653,11 @@ default_wired_clear_tag (NMSettings *self, NMSettingsConnection *connection, gboolean add_to_no_auto_default) { - g_return_if_fail (NM_IS_SETTINGS (self)); - g_return_if_fail (NM_IS_DEVICE (device)); - g_return_if_fail (NM_IS_CONNECTION (connection)); - g_return_if_fail (device == g_object_get_qdata (G_OBJECT (connection), _default_wired_device_quark ())); - g_return_if_fail (connection == g_object_get_qdata (G_OBJECT (device), _default_wired_connection_quark ())); + nm_assert (NM_IS_SETTINGS (self)); + nm_assert (NM_IS_DEVICE (device)); + nm_assert (NM_IS_SETTINGS_CONNECTION (connection)); + nm_assert (device == g_object_get_qdata (G_OBJECT (connection), _default_wired_device_quark ())); + nm_assert (connection == g_object_get_qdata (G_OBJECT (device), _default_wired_connection_quark ())); g_object_set_qdata (G_OBJECT (connection), _default_wired_device_quark (), NULL); g_object_set_qdata (G_OBJECT (device), _default_wired_connection_quark (), NULL); @@ -1866,7 +1832,7 @@ get_property (GObject *object, guint prop_id, : NULL); break; case PROP_CAN_MODIFY: - g_value_set_boolean (value, !!get_plugin (self, TRUE)); + g_value_set_boolean (value, TRUE); break; case PROP_CONNECTIONS: if (priv->connections_loaded) { @@ -1930,6 +1896,7 @@ finalize (GObject *object) { NMSettings *self = NM_SETTINGS (object); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GSList *iter; _clear_connections_cached_list (priv); @@ -1938,7 +1905,12 @@ finalize (GObject *object) g_slist_free_full (priv->unmanaged_specs, g_free); g_slist_free_full (priv->unrecognized_specs, g_free); - g_slist_free_full (priv->plugins, g_object_unref); + while ((iter = priv->plugins)) { + gs_unref_object NMSettingsPlugin *plugin = iter->data; + + priv->plugins = g_slist_delete_link (priv->plugins, iter); + g_signal_handlers_disconnect_by_data (plugin, self); + } g_clear_object (&priv->agent_mgr); diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index 021512fd..38d8ad4e 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -85,7 +85,7 @@ void nm_settings_add_connection_dbus (NMSettings *self, NMSettingsAddCallback callback, gpointer user_data); -NMSettingsConnection *const* nm_settings_get_connections (NMSettings *settings, guint *out_len); +NMSettingsConnection *const*nm_settings_get_connections (NMSettings *settings, guint *out_len); NMSettingsConnection **nm_settings_get_connections_clone (NMSettings *self, guint *out_len, diff --git a/src/settings/plugins/ibft/meson.build b/src/settings/plugins/ibft/meson.build index 1b6ff28a..c7dbe459 100644 --- a/src/settings/plugins/ibft/meson.build +++ b/src/settings/plugins/ibft/meson.build @@ -1,15 +1,9 @@ name = 'nm-settings-plugin-ibft' -cflags = [ - '-DSBINDIR="@0@"'.format(nm_sbindir), - '-DSYSCONFDIR="@0@"'.format(nm_sysconfdir) -] - libnms_ibft_core = static_library( 'nms-ibft-core', 'nms-ibft-reader.c', dependencies: nm_dep, - c_args: cflags ) sources = files( @@ -21,7 +15,6 @@ libnm_settings_plugin_ibft = shared_module( name, sources: sources, dependencies: nm_dep, - c_args: cflags, link_with: libnms_ibft_core, link_args: ldflags_linker_script_settings, link_depends: linker_script_settings, diff --git a/src/settings/plugins/ibft/nms-ibft-plugin.c b/src/settings/plugins/ibft/nms-ibft-plugin.c index 77ce208f..69dd3733 100644 --- a/src/settings/plugins/ibft/nms-ibft-plugin.c +++ b/src/settings/plugins/ibft/nms-ibft-plugin.c @@ -42,19 +42,15 @@ typedef struct { } NMSIbftPluginPrivate; struct _NMSIbftPlugin { - GObject parent; + NMSettingsPlugin parent; NMSIbftPluginPrivate _priv; }; struct _NMSIbftPluginClass { - GObjectClass parent; + NMSettingsPluginClass parent; }; -static void settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface); - -G_DEFINE_TYPE_EXTENDED (NMSIbftPlugin, nms_ibft_plugin, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN, - settings_plugin_interface_init)) +G_DEFINE_TYPE (NMSIbftPlugin, nms_ibft_plugin, NM_TYPE_SETTINGS_PLUGIN); #define NMS_IBFT_PLUGIN_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSIbftPlugin, NMS_IS_IBFT_PLUGIN) @@ -84,9 +80,9 @@ read_connections (NMSIbftPlugin *self) connection = nms_ibft_connection_new (iter->data, &error); if (connection) { nm_log_info (LOGD_SETTINGS, "ibft: read connection '%s'", - nm_connection_get_id (NM_CONNECTION (connection))); + nm_settings_connection_get_id (NM_SETTINGS_CONNECTION (connection))); g_hash_table_insert (priv->connections, - g_strdup (nm_connection_get_uuid (NM_CONNECTION (connection))), + g_strdup (nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (connection))), connection); } else { nm_log_warn (LOGD_SETTINGS, "ibft: failed to read iscsiadm record: %s", error->message); @@ -121,11 +117,6 @@ get_connections (NMSettingsPlugin *config) /*****************************************************************************/ static void -init (NMSettingsPlugin *config) -{ -} - -static void nms_ibft_plugin_init (NMSIbftPlugin *self) { NMSIbftPluginPrivate *priv = NMS_IBFT_PLUGIN_GET_PRIVATE (self); @@ -148,24 +139,20 @@ dispose (GObject *object) } static void -nms_ibft_plugin_class_init (NMSIbftPluginClass *req_class) +nms_ibft_plugin_class_init (NMSIbftPluginClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (req_class); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMSettingsPluginClass *plugin_class = NM_SETTINGS_PLUGIN_CLASS (klass); object_class->dispose = dispose; -} -static void -settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) -{ - plugin_iface->get_connections = get_connections; - plugin_iface->init = init; + plugin_class->get_connections = get_connections; } /*****************************************************************************/ -G_MODULE_EXPORT GObject * +G_MODULE_EXPORT NMSettingsPlugin * nm_settings_plugin_factory (void) { - return G_OBJECT (g_object_ref (nms_ibft_plugin_get ())); + return NM_SETTINGS_PLUGIN (g_object_ref (nms_ibft_plugin_get ())); } diff --git a/src/settings/plugins/ibft/nms-ibft-reader.c b/src/settings/plugins/ibft/nms-ibft-reader.c index cf849e28..ac5824a1 100644 --- a/src/settings/plugins/ibft/nms-ibft-reader.c +++ b/src/settings/plugins/ibft/nms-ibft-reader.c @@ -98,7 +98,7 @@ nms_ibft_reader_load_blocks (const char *iscsiadm_path, const char *envp[1] = { NULL }; GSList *blocks = NULL; char *out = NULL, *err = NULL; - gint status = 0; + int status = 0; char **lines = NULL, **iter; GPtrArray *block_lines = NULL; gboolean success = FALSE; diff --git a/src/settings/plugins/ibft/tests/iscsiadm-test-bad-dns1 b/src/settings/plugins/ibft/tests/iscsiadm-test-bad-dns1 deleted file mode 100755 index 54f02da6..00000000 --- a/src/settings/plugins/ibft/tests/iscsiadm-test-bad-dns1 +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -cat << EOF -# BEGIN RECORD -iface.initiatorname = iqn.pjones6 -iface.hwaddress = 00:33:21:98:b9:f0 -iface.bootproto = STATIC -iface.ipaddress = 192.168.32.72 -iface.subnet_mask = 255.255.252.0 -iface.gateway = 192.168.35.254 -iface.primary_dns = 10000.500.250.1 -iface.secondary_dns = 10.16.255.3 -iface.vlan_id = 0 -iface.net_ifacename = eth0 -node.name = iqn.0.2008-11.com.blahblah:iscsi0 -node.conn[0].address = 10.16.52.16 -node.conn[0].port = 3260 -node.boot_lun = 00000000 -# END RECORD -EOF - diff --git a/src/settings/plugins/ibft/tests/iscsiadm-test-bad-dns2 b/src/settings/plugins/ibft/tests/iscsiadm-test-bad-dns2 deleted file mode 100755 index ebd7a9ca..00000000 --- a/src/settings/plugins/ibft/tests/iscsiadm-test-bad-dns2 +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -cat << EOF -# BEGIN RECORD -iface.initiatorname = iqn.pjones6 -iface.hwaddress = 00:33:21:98:b9:f0 -iface.bootproto = STATIC -iface.ipaddress = 192.168.32.72 -iface.subnet_mask = 255.255.252.0 -iface.gateway = 192.168.35.254 -iface.primary_dns = 10.16.255.2 -iface.secondary_dns = blah.foo.bar.baz -iface.vlan_id = 0 -iface.net_ifacename = eth0 -node.name = iqn.0.2008-11.com.blahblah:iscsi0 -node.conn[0].address = 10.16.52.16 -node.conn[0].port = 3260 -node.boot_lun = 00000000 -# END RECORD -EOF - diff --git a/src/settings/plugins/ibft/tests/iscsiadm-test-bad-entry b/src/settings/plugins/ibft/tests/iscsiadm-test-bad-entry deleted file mode 100755 index 4e326048..00000000 --- a/src/settings/plugins/ibft/tests/iscsiadm-test-bad-entry +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -cat << EOF -# BEGIN RECORD -iface.initiatorname = iqn.pjones6 -iface.hwaddress = 00:33:21:98:b9:f0 -iface.bootproto = STATIC -iface.ipaddress 192.168.32.72 -iface.subnet_mask = 255.255.252.0 -iface.gateway = 192.168.35.254 -iface.primary_dns = 10.16.255.2 -iface.secondary_dns = 10.16.255.3 -iface.vlan_id = 0 -iface.net_ifacename = eth0 -node.name = iqn.0.2008-11.com.blahblah:iscsi0 -node.conn[0].address = 10.16.52.16 -node.conn[0].port = 3260 -node.boot_lun = 00000000 -# END RECORD - diff --git a/src/settings/plugins/ibft/tests/iscsiadm-test-bad-gateway b/src/settings/plugins/ibft/tests/iscsiadm-test-bad-gateway deleted file mode 100755 index 5390a6c3..00000000 --- a/src/settings/plugins/ibft/tests/iscsiadm-test-bad-gateway +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -cat << EOF -# BEGIN RECORD -iface.initiatorname = iqn.pjones6 -iface.hwaddress = 00:33:21:98:b9:f0 -iface.bootproto = STATIC -iface.ipaddress = 192.168.32.72 -iface.subnet_mask = 255.255.252.0 -iface.gateway = bb.cc.dd.ee -iface.primary_dns = 10.16.255.2 -iface.secondary_dns = 10.16.255.3 -iface.vlan_id = 0 -iface.net_ifacename = eth0 -node.name = iqn.0.2008-11.com.blahblah:iscsi0 -node.conn[0].address = 10.16.52.16 -node.conn[0].port = 3260 -node.boot_lun = 00000000 -# END RECORD -EOF - diff --git a/src/settings/plugins/ibft/tests/iscsiadm-test-bad-ipaddr b/src/settings/plugins/ibft/tests/iscsiadm-test-bad-ipaddr deleted file mode 100755 index b41cd1f1..00000000 --- a/src/settings/plugins/ibft/tests/iscsiadm-test-bad-ipaddr +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -cat << EOF -# BEGIN RECORD -iface.initiatorname = iqn.pjones6 -iface.hwaddress = 00:33:21:98:b9:f0 -iface.bootproto = STATIC -iface.ipaddress = aa.bb.cc.dd -iface.subnet_mask = 255.255.252.0 -iface.gateway = 192.168.35.254 -iface.primary_dns = 10.16.255.2 -iface.secondary_dns = 10.16.255.3 -iface.vlan_id = 0 -iface.net_ifacename = eth0 -node.name = iqn.0.2008-11.com.blahblah:iscsi0 -node.conn[0].address = 10.16.52.16 -node.conn[0].port = 3260 -node.boot_lun = 00000000 -# END RECORD -EOF - diff --git a/src/settings/plugins/ibft/tests/iscsiadm-test-bad-record b/src/settings/plugins/ibft/tests/iscsiadm-test-bad-record deleted file mode 100755 index 22b34e6f..00000000 --- a/src/settings/plugins/ibft/tests/iscsiadm-test-bad-record +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -cat << EOF -# BEGIN RECORD -iface.initiatorname = iqn.pjones6 -iface.hwaddress = 00:33:21:98:b9:f0 -iface.bootproto = DHCP -iface.gateway = 10.16.52.254 -iface.primary_dns = 10.16.255.2 -iface.secondary_dns = 10.16.255.3 -iface.vlan_id = 0 -iface.net_ifacename = eth0 -node.name = iqn.0.2008-11.com.blahblah:iscsi0 -node.conn[0].address = 10.16.52.16 -node.conn[0].port = 3260 -node.boot_lun = 00000000 -EOF - diff --git a/src/settings/plugins/ibft/tests/iscsiadm-test-dhcp b/src/settings/plugins/ibft/tests/iscsiadm-test-dhcp deleted file mode 100755 index 556b0586..00000000 --- a/src/settings/plugins/ibft/tests/iscsiadm-test-dhcp +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -cat << EOF -# BEGIN RECORD -iface.initiatorname = iqn.pjones6 -iface.hwaddress = 00:33:21:98:b9:f0 -iface.bootproto = DHCP -iface.gateway = 10.16.52.254 -iface.primary_dns = 10.16.255.2 -iface.secondary_dns = 10.16.255.3 -iface.vlan_id = 0 -iface.net_ifacename = eth0 -node.name = iqn.0.2008-11.com.blahblah:iscsi0 -node.conn[0].address = 10.16.52.16 -node.conn[0].port = 3260 -node.boot_lun = 00000000 -# END RECORD -# BEGIN RECORD -iface.initiatorname = iqn.pjones6 -iface.hwaddress = 00:33:21:98:b9:f1 -iface.bootproto = DHCP -iface.gateway = 10.16.52.254 -iface.primary_dns = 10.16.255.2 -iface.secondary_dns = 10.16.255.3 -iface.vlan_id = 0 -iface.net_ifacename = eth1 -node.name = iqn.1.2008-11.com.blahblah:iscsi1 -node.conn[0].address = 10.16.52.16 -node.conn[0].port = 3260 -node.boot_lun = 00000000 -# END RECORD -EOF - diff --git a/src/settings/plugins/ibft/tests/iscsiadm-test-static b/src/settings/plugins/ibft/tests/iscsiadm-test-static deleted file mode 100755 index 51711480..00000000 --- a/src/settings/plugins/ibft/tests/iscsiadm-test-static +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -cat << EOF -# BEGIN RECORD -iface.initiatorname = iqn.pjones6 -iface.hwaddress = 00:33:21:98:b9:f0 -iface.bootproto = STATIC -iface.ipaddress = 192.168.32.72 -iface.subnet_mask = 255.255.252.0 -iface.gateway = 192.168.35.254 -iface.primary_dns = 10.16.255.2 -iface.secondary_dns = 10.16.255.3 -iface.vlan_id = 0 -iface.net_ifacename = eth0 -node.name = iqn.0.2008-11.com.blahblah:iscsi0 -node.conn[0].address = 10.16.52.16 -node.conn[0].port = 3260 -node.boot_lun = 00000000 -# END RECORD -# BEGIN RECORD -iface.initiatorname = iqn.pjones6 -iface.hwaddress = 00:33:21:98:b9:f1 -iface.bootproto = DHCP -iface.gateway = 10.16.52.254 -iface.primary_dns = 10.16.255.2 -iface.secondary_dns = 10.16.255.3 -iface.vlan_id = 0 -iface.net_ifacename = eth1 -node.name = iqn.1.2008-11.com.blahblah:iscsi1 -node.conn[0].address = 10.16.52.16 -node.conn[0].port = 3260 -node.boot_lun = 00000000 -# END RECORD -EOF - diff --git a/src/settings/plugins/ibft/tests/iscsiadm-test-vlan b/src/settings/plugins/ibft/tests/iscsiadm-test-vlan deleted file mode 100755 index 59b80bd0..00000000 --- a/src/settings/plugins/ibft/tests/iscsiadm-test-vlan +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -cat << EOF -# BEGIN RECORD 6.2.0.873-21 -iface.initiatorname = iqn.2010-04.org.ipxe:d05faa97-c4be-44f6-a723-efde9aa399a0 -iface.transport_name = tcp -iface.hwaddress = 00:33:21:98:b9:f0 -iface.bootproto = STATIC -iface.ipaddress = 192.168.6.200 -iface.subnet_mask = 255.255.255.0 -iface.vlan_id = 123 -iface.net_ifacename = eth0 -node.name = iqn.2003-01.org.x:disk1 -node.conn[0].address = 192.168.6.32 -node.conn[0].port = 3260 -node.boot_lun = 01000000 -# END RECORD -EOF - diff --git a/src/settings/plugins/ibft/tests/meson.build b/src/settings/plugins/ibft/tests/meson.build index 59f49c31..8b5e143a 100644 --- a/src/settings/plugins/ibft/tests/meson.build +++ b/src/settings/plugins/ibft/tests/meson.build @@ -6,7 +6,6 @@ exe = executable( test_unit, test_unit + '.c', dependencies: test_nm_dep, - c_args: nm_build_cflags, link_with: libnms_ibft_core ) diff --git a/src/settings/plugins/ifcfg-rh/meson.build b/src/settings/plugins/ifcfg-rh/meson.build index 964ce22d..e84ae80c 100644 --- a/src/settings/plugins/ifcfg-rh/meson.build +++ b/src/settings/plugins/ifcfg-rh/meson.build @@ -3,11 +3,6 @@ install_data( install_dir: dbus_conf_dir ) -cflags = [ - '-DSBINDIR="@0@"'.format(nm_sbindir), - '-DSYSCONFDIR="@0@"'.format(nm_sysconfdir) -] - name = 'nmdbus-ifcfg-rh' dbus_sources = gnome.gdbus_codegen( @@ -21,10 +16,9 @@ libnmdbus_ifcfg_rh = static_library( name, sources: dbus_sources, dependencies: glib_dep, - c_args: cflags ) -sources = files( +core_sources = files( 'nm-inotify-helper.c', 'nms-ifcfg-rh-reader.c', 'nms-ifcfg-rh-utils.c', @@ -33,24 +27,21 @@ sources = files( ) deps = [ - crypto_dep, nm_dep ] libnms_ifcfg_rh_core = static_library( 'nms-ifcfg-rh-core', - sources: sources, + sources: core_sources, dependencies: deps, - c_args: cflags ) -sources = [dbus_sources] + files('nms-ifcfg-rh-connection.c') +sources = [dbus_sources] + core_sources + files('nms-ifcfg-rh-connection.c', 'nms-ifcfg-rh-plugin.c') libnm_settings_plugin_ifcfg_rh = shared_module( 'nm-settings-plugin-ifcfg-rh', sources: sources, dependencies: deps, - c_args: cflags, link_with: [libnms_ifcfg_rh_core], link_args: ldflags_linker_script_settings, link_depends: linker_script_settings, @@ -72,6 +63,15 @@ check-local-symbols-settings-ifcfg-rh: src/settings/plugins/ifcfg-rh/libnm-setti $(call check_so_symbols,$(builddir)/src/settings/plugins/ifcfg-rh/.libs/libnm-settings-plugin-ifcfg-rh.so) ''' +install_data( + ['nm-ifup', 'nm-ifdown'], + install_dir: nm_libexecdir, + install_mode: 'rwxr-xr-x', +) + +meson.add_install_script('sh', '-c', + 'mkdir -p $DESTDIR/@0@/sysconfig/network-scripts'.format(nm_sysconfdir)) + if enable_tests subdir('tests') endif diff --git a/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c index 2863df64..e7a74a1a 100644 --- a/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c +++ b/src/settings/plugins/ifcfg-rh/nm-inotify-helper.c @@ -120,8 +120,8 @@ inotify_event_handler (GIOChannel *channel, GIOCondition cond, gpointer user_dat struct inotify_event evt; /* read the notifications from the watch descriptor */ - while (g_io_channel_read_chars (channel, (gchar *) &evt, sizeof (struct inotify_event), NULL, NULL) == G_IO_STATUS_NORMAL) { - gchar filename[PATH_MAX + 1]; + while (g_io_channel_read_chars (channel, (char *) &evt, sizeof (struct inotify_event), NULL, NULL) == G_IO_STATUS_NORMAL) { + char filename[PATH_MAX + 1]; filename[0] = '\0'; if (evt.len > 0) { diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c index 6979fdaa..ca319ddc 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-connection.c @@ -143,7 +143,7 @@ devtimeout_expired (gpointer user_data) NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self); nm_log_info (LOGD_SETTINGS, "Device for connection '%s' did not appear before timeout", - nm_connection_get_id (NM_CONNECTION (self))); + nm_settings_connection_get_id (NM_SETTINGS_CONNECTION (self))); g_signal_handler_disconnect (NM_PLATFORM_GET, priv->devtimeout_link_changed_handler); priv->devtimeout_link_changed_handler = 0; @@ -163,7 +163,7 @@ nm_ifcfg_connection_check_devtimeout (NMIfcfgConnection *self) guint devtimeout; const NMPlatformLink *pllink; - s_con = nm_connection_get_setting_connection (NM_CONNECTION (self)); + s_con = nm_connection_get_setting_connection (nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (self))); if (!nm_setting_connection_get_autoconnect (s_con)) return; @@ -186,7 +186,7 @@ nm_ifcfg_connection_check_devtimeout (NMIfcfgConnection *self) nm_settings_connection_set_ready (NM_SETTINGS_CONNECTION (self), FALSE); nm_log_info (LOGD_SETTINGS, "Waiting %u seconds for %s to appear for connection '%s'", - devtimeout, ifname, nm_connection_get_id (NM_CONNECTION (self))); + devtimeout, ifname, nm_settings_connection_get_id (NM_SETTINGS_CONNECTION (self))); priv->devtimeout_link_changed_handler = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_LINK_CHANGED, diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c index 0fb77b9d..6cac8cb6 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c @@ -70,19 +70,15 @@ typedef struct { } SettingsPluginIfcfgPrivate; struct _SettingsPluginIfcfg { - GObject parent; + NMSettingsPlugin parent; SettingsPluginIfcfgPrivate _priv; }; struct _SettingsPluginIfcfgClass { - GObjectClass parent; + NMSettingsPluginClass parent; }; -static void settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface); - -G_DEFINE_TYPE_EXTENDED (SettingsPluginIfcfg, settings_plugin_ifcfg, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN, - settings_plugin_interface_init)) +G_DEFINE_TYPE (SettingsPluginIfcfg, settings_plugin_ifcfg, NM_TYPE_SETTINGS_PLUGIN) #define SETTINGS_PLUGIN_IFCFG_GET_PRIVATE(self) _NM_GET_PRIVATE (self, SettingsPluginIfcfg, SETTINGS_IS_PLUGIN_IFCFG) @@ -139,7 +135,7 @@ static void connection_removed_cb (NMSettingsConnection *obj, gpointer user_data) { g_hash_table_remove (SETTINGS_PLUGIN_IFCFG_GET_PRIVATE ((SettingsPluginIfcfg *) user_data)->connections, - nm_connection_get_uuid (NM_CONNECTION (obj))); + nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (obj))); } static void @@ -157,16 +153,16 @@ remove_connection (SettingsPluginIfcfg *self, NMIfcfgConnection *connection) unrecognized = !!nm_ifcfg_connection_get_unrecognized_spec (connection); g_object_ref (connection); - g_hash_table_remove (priv->connections, nm_connection_get_uuid (NM_CONNECTION (connection))); + g_hash_table_remove (priv->connections, nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (connection))); if (!unmanaged && !unrecognized) nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection)); g_object_unref (connection); /* Emit changes _after_ removing the connection */ if (unmanaged) - g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); + _nm_settings_plugin_emit_signal_unmanaged_specs_changed (NM_SETTINGS_PLUGIN (self)); if (unrecognized) - g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED); + _nm_settings_plugin_emit_signal_unrecognized_specs_changed (NM_SETTINGS_PLUGIN (self)); } static NMIfcfgConnection * @@ -228,7 +224,7 @@ update_connection (SettingsPluginIfcfg *self, return NULL; } - uuid = nm_connection_get_uuid (NM_CONNECTION (connection_new)); + uuid = nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (connection_new)); connection_by_uuid = g_hash_table_lookup (priv->connections, uuid); if ( connection @@ -285,12 +281,16 @@ update_connection (SettingsPluginIfcfg *self, if ( !unmanaged_changed && !unrecognized_changed - && nm_connection_compare (NM_CONNECTION (connection_by_uuid), - NM_CONNECTION (connection_new), + && nm_connection_compare (nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (connection_by_uuid)), + nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (connection_new)), NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS | NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) { - if (old_path && g_strcmp0 (old_path, full_path) != 0) - _LOGI ("rename \"%s\" to "NM_IFCFG_CONNECTION_LOG_FMT" without other changes", nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_by_uuid)), NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); + if ( old_path + && !nm_streq0 (old_path, full_path)) { + _LOGI ("rename \"%s\" to "NM_IFCFG_CONNECTION_LOG_FMT" without other changes", + nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_by_uuid)), + NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); + } } else { /******************************************************* @@ -299,7 +299,7 @@ update_connection (SettingsPluginIfcfg *self, if (source) _LOGI ("update "NM_IFCFG_CONNECTION_LOG_FMT" from %s", NM_IFCFG_CONNECTION_LOG_ARG (connection_new), NM_IFCFG_CONNECTION_LOG_PATH (old_path)); - else if (!g_strcmp0 (old_path, nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_new)))) + else if (nm_streq0 (old_path, nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_new)))) _LOGI ("update "NM_IFCFG_CONNECTION_LOG_FMT, NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); else if (old_path) _LOGI ("rename \"%s\" to "NM_IFCFG_CONNECTION_LOG_FMT, old_path, NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); @@ -312,7 +312,7 @@ update_connection (SettingsPluginIfcfg *self, NULL); if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (connection_by_uuid), - NM_CONNECTION (connection_new), + nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (connection_new)), NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP_SAVED, NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, "ifcfg-update", @@ -338,25 +338,27 @@ update_connection (SettingsPluginIfcfg *self, * so add it back now. */ g_hash_table_insert (priv->connections, - g_strdup (nm_connection_get_uuid (NM_CONNECTION (connection_by_uuid))), + g_strdup (nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (connection_by_uuid))), connection_by_uuid /* we took reference above and pass it on */); } } else { if (old_unmanaged /* && !new_unmanaged */) { _LOGI ("Managing connection "NM_IFCFG_CONNECTION_LOG_FMT" and its device because NM_CONTROLLED was true.", NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); - g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, connection_by_uuid); + _nm_settings_plugin_emit_signal_connection_added (NM_SETTINGS_PLUGIN (self), + NM_SETTINGS_CONNECTION (connection_by_uuid)); } else if (old_unrecognized /* && !new_unrecognized */) { _LOGI ("Managing connection "NM_IFCFG_CONNECTION_LOG_FMT" because it is now a recognized type.", NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); - g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, connection_by_uuid); + _nm_settings_plugin_emit_signal_connection_added (NM_SETTINGS_PLUGIN (self), + NM_SETTINGS_CONNECTION (connection_by_uuid)); } } if (unmanaged_changed) - g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); + _nm_settings_plugin_emit_signal_unmanaged_specs_changed (NM_SETTINGS_PLUGIN (self)); if (unrecognized_changed) - g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED); + _nm_settings_plugin_emit_signal_unrecognized_specs_changed (NM_SETTINGS_PLUGIN (self)); } nm_settings_connection_set_filename (NM_SETTINGS_CONNECTION (connection_by_uuid), full_path); g_object_unref (connection_new); @@ -394,11 +396,13 @@ update_connection (SettingsPluginIfcfg *self, /* Only raise the signal if we were called without source, i.e. if we read the connection from file. * Otherwise, we were called by add_connection() which does not expect the signal. */ if (nm_ifcfg_connection_get_unmanaged_spec (connection_new)) - g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); + _nm_settings_plugin_emit_signal_unmanaged_specs_changed (NM_SETTINGS_PLUGIN (self)); else if (nm_ifcfg_connection_get_unrecognized_spec (connection_new)) - g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED); - else - g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, connection_new); + _nm_settings_plugin_emit_signal_unrecognized_specs_changed (NM_SETTINGS_PLUGIN (self)); + else { + _nm_settings_plugin_emit_signal_connection_added (NM_SETTINGS_PLUGIN (self), + NM_SETTINGS_CONNECTION (connection_new)); + } } return connection_new; } @@ -731,7 +735,7 @@ impl_ifcfgrh_get_ifcfg_details (SettingsPluginIfcfg *plugin, return; } - s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); + s_con = nm_connection_get_setting_connection (nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (connection))); if (!s_con) { g_dbus_method_invocation_return_error (context, NM_SETTINGS_ERROR, @@ -998,11 +1002,6 @@ config_changed_cb (NMConfig *config, /*****************************************************************************/ static void -init (NMSettingsPlugin *config) -{ -} - -static void settings_plugin_ifcfg_init (SettingsPluginIfcfg *plugin) { SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE ((SettingsPluginIfcfg *) plugin); @@ -1059,30 +1058,26 @@ dispose (GObject *object) } static void -settings_plugin_ifcfg_class_init (SettingsPluginIfcfgClass *req_class) +settings_plugin_ifcfg_class_init (SettingsPluginIfcfgClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (req_class); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMSettingsPluginClass *plugin_class = NM_SETTINGS_PLUGIN_CLASS (klass); object_class->constructed = constructed; object_class->dispose = dispose; -} -static void -settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) -{ - plugin_iface->get_connections = get_connections; - plugin_iface->add_connection = add_connection; - plugin_iface->load_connection = load_connection; - plugin_iface->reload_connections = reload_connections; - plugin_iface->get_unmanaged_specs = get_unmanaged_specs; - plugin_iface->get_unrecognized_specs = get_unrecognized_specs; - plugin_iface->init = init; + plugin_class->get_connections = get_connections; + plugin_class->add_connection = add_connection; + plugin_class->load_connection = load_connection; + plugin_class->reload_connections = reload_connections; + plugin_class->get_unmanaged_specs = get_unmanaged_specs; + plugin_class->get_unrecognized_specs = get_unrecognized_specs; } /*****************************************************************************/ -G_MODULE_EXPORT GObject * +G_MODULE_EXPORT NMSettingsPlugin * nm_settings_plugin_factory (void) { - return G_OBJECT (g_object_ref (settings_plugin_ifcfg_get ())); + return NM_SETTINGS_PLUGIN (g_object_ref (settings_plugin_ifcfg_get ())); } diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index c1960846..09a37991 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -33,6 +33,7 @@ #include <sys/ioctl.h> #include <unistd.h> +#include "nm-utils/nm-secret-utils.h" #include "nm-connection.h" #include "nm-dbus-interface.h" #include "nm-setting-connection.h" @@ -41,6 +42,7 @@ #include "nm-setting-ip6-config.h" #include "nm-setting-wired.h" #include "nm-setting-wireless.h" +#include "nm-setting-ethtool.h" #include "nm-setting-8021x.h" #include "nm-setting-bond.h" #include "nm-setting-team.h" @@ -53,6 +55,7 @@ #include "nm-setting-generic.h" #include "nm-core-internal.h" #include "nm-utils.h" +#include "nm-ethtool-utils.h" #include "platform/nm-platform.h" #include "NetworkManagerUtils.h" @@ -77,6 +80,210 @@ /*****************************************************************************/ +static char * +get_full_file_path (const char *ifcfg_path, const char *file_path) +{ + const char *base = file_path; + char *p, *ret, *dirname; + + g_return_val_if_fail (ifcfg_path != NULL, NULL); + g_return_val_if_fail (file_path != NULL, NULL); + + if (file_path[0] == '/') + return g_strdup (file_path); + + p = strrchr (file_path, '/'); + if (p) + base = p + 1; + + dirname = g_path_get_dirname (ifcfg_path); + ret = g_build_path ("/", dirname, base, NULL); + g_free (dirname); + return ret; +} + +/*****************************************************************************/ + +static NMSettingSecretFlags +_secret_read_ifcfg_flags (shvarFile *ifcfg, const char *flags_key) +{ + NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; + gs_free char *val_free = NULL; + const char *val; + + nm_assert (flags_key); + nm_assert (g_str_has_suffix (flags_key, "_FLAGS")); + + val = svGetValueStr (ifcfg, flags_key, &val_free); + if (val) { + if (strstr (val, SECRET_FLAG_AGENT)) + flags |= NM_SETTING_SECRET_FLAG_AGENT_OWNED; + if (strstr (val, SECRET_FLAG_NOT_SAVED)) + flags |= NM_SETTING_SECRET_FLAG_NOT_SAVED; + if (strstr (val, SECRET_FLAG_NOT_REQUIRED)) + flags |= NM_SETTING_SECRET_FLAG_NOT_REQUIRED; + } + return flags; +} + +static void +_secret_read_ifcfg (shvarFile *ifcfg, + shvarFile *keys_ifcfg, + const char *name, + char **value, + NMSettingSecretFlags *flags) +{ + char flags_key[250]; + + nm_sprintf_buf (flags_key, "%s_FLAGS", name); + + *flags = _secret_read_ifcfg_flags (ifcfg, flags_key); + + if (*flags != NM_SETTING_SECRET_FLAG_NONE) + *value = NULL; + else { + *value = svGetValue_cp (ifcfg, name); + if (!*value && keys_ifcfg) + *value = svGetValue_cp (keys_ifcfg, name); + } +} + +static void +_secret_set_from_ifcfg (gpointer setting, + shvarFile *ifcfg, + shvarFile *keys_ifcfg, + const char *ifcfg_key, + const char *property_name) +{ + nm_auto_free_secret char *secret = NULL; + NMSettingSecretFlags flags; + char flags_key[250]; + + nm_assert (NM_IS_SETTING (setting)); + + _secret_read_ifcfg (ifcfg, keys_ifcfg, ifcfg_key, &secret, &flags); + + g_object_set (setting, + property_name, + secret, + nm_sprintf_buf (flags_key, "%s-flags", property_name), + flags, + NULL); +} + +static gboolean +_secret_password_raw_to_bytes (const char *ifcfg_key, + const char *password_raw, + GBytes **out_bytes, + GError **error) +{ + nm_auto_free_secret_buf NMSecretBuf *secret = NULL; + gsize len; + + if (!password_raw) { + NM_SET_OUT (out_bytes, NULL); + return TRUE; + } + + if (password_raw[0] == '0' && password_raw[1] == 'x') + password_raw += 2; + + secret = nm_secret_buf_new (strlen (password_raw) / 2 + 3); + if (!_nm_utils_str2bin_full (password_raw, FALSE, ":", secret->bin, secret->len, &len)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid hex password in %s", + ifcfg_key); + return FALSE; + } + + NM_SET_OUT (out_bytes, nm_secret_buf_to_gbytes_take (g_steal_pointer (&secret), len)); + return TRUE; +} + +/*****************************************************************************/ + +static GBytes * +_cert_get_cert_bytes (const char *ifcfg_path, + const char *value, + GError **error) +{ + gs_free char *path = NULL; + + if (g_str_has_prefix (value, "pkcs11:")) + return _nm_setting_802_1x_cert_value_to_bytes (NM_SETTING_802_1X_CK_SCHEME_PKCS11, (guint8 *) value, -1, error); + + path = get_full_file_path (ifcfg_path, value); + return _nm_setting_802_1x_cert_value_to_bytes (NM_SETTING_802_1X_CK_SCHEME_PATH, (guint8 *) path, -1, error); +} + +static gboolean +_cert_get_cert (shvarFile *ifcfg, + const char *ifcfg_key, + GBytes **out_cert, + NMSetting8021xCKScheme *out_scheme, + GError **error) +{ + nm_auto_free_secret char *val_free = NULL; + const char *val; + gs_unref_bytes GBytes *cert = NULL; + GError *local = NULL; + NMSetting8021xCKScheme scheme; + + val = svGetValueStr (ifcfg, ifcfg_key, &val_free); + if (!val) { + NM_SET_OUT (out_cert, NULL); + NM_SET_OUT (out_scheme, NM_SETTING_802_1X_CK_SCHEME_UNKNOWN); + return TRUE; + } + + cert = _cert_get_cert_bytes (svFileGetName (ifcfg), val, &local); + if (!cert) + goto err; + + scheme = _nm_setting_802_1x_cert_get_scheme (cert, &local); + if (scheme == NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) + goto err; + + NM_SET_OUT (out_cert, g_steal_pointer (&cert)); + NM_SET_OUT (out_scheme, scheme); + return TRUE; + +err: + g_set_error (error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_CONNECTION, + "invalid certificate %s: %s", + ifcfg_key, + local->message); + g_error_free (local); + return FALSE; +} + +static gboolean +_cert_set_from_ifcfg (gpointer setting, + shvarFile *ifcfg, + const char *ifcfg_key, + const char *property_name, + GBytes **out_cert, + GError **error) +{ + gs_unref_bytes GBytes *cert = NULL; + + if (!_cert_get_cert (ifcfg, + ifcfg_key, + &cert, + NULL, + error)) + return FALSE; + + g_object_set (setting, property_name, cert, NULL); + + NM_SET_OUT (out_cert, g_steal_pointer (&cert)); + return TRUE; +} + +/*****************************************************************************/ + static void check_if_bond_slave (shvarFile *ifcfg, NMSettingConnection *s_con) @@ -232,13 +439,16 @@ make_connection_setting (const char *file, NM_SETTING_CONNECTION_AUTOCONNECT, svGetValueBoolean (ifcfg, "ONBOOT", TRUE), NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, - (gint) svGetValueInt64 (ifcfg, "AUTOCONNECT_PRIORITY", 10, + (int) svGetValueInt64 (ifcfg, "AUTOCONNECT_PRIORITY", 10, NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MIN, NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MAX, NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_DEFAULT), NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES, - (gint) svGetValueInt64 (ifcfg, "AUTOCONNECT_RETRIES", 10, + (int) svGetValueInt64 (ifcfg, "AUTOCONNECT_RETRIES", 10, -1, G_MAXINT32, -1), + NM_SETTING_CONNECTION_MULTI_CONNECT, + (gint) svGetValueInt64 (ifcfg, "MULTI_CONNECT", 10, + G_MININT32, G_MAXINT32, NM_CONNECTION_MULTI_CONNECT_DEFAULT), NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES, svGetValueBoolean (ifcfg, "AUTOCONNECT_SLAVES", NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT), NM_SETTING_CONNECTION_LLDP, lldp, @@ -249,7 +459,7 @@ make_connection_setting (const char *file, if (v) { gs_free const char **items = NULL; - items = nm_utils_strsplit_set (v, " "); + items = nm_utils_strsplit_set (v, " ", FALSE); for (iter = items; iter && *iter; iter++) { if (!nm_setting_connection_add_permission (s_con, "user", *iter, NULL)) PARSE_WARNING ("invalid USERS item '%s'", *iter); @@ -265,7 +475,7 @@ make_connection_setting (const char *file, if (v) { gs_free const char **items = NULL; - items = nm_utils_strsplit_set (v, " \t"); + items = nm_utils_strsplit_set (v, " \t", FALSE); for (iter = items; iter && *iter; iter++) { if (!nm_setting_connection_add_secondary (s_con, *iter)) PARSE_WARNING ("secondary connection UUID '%s' already added", *iter); @@ -335,7 +545,7 @@ make_connection_setting (const char *file, } vint64 = svGetValueInt64 (ifcfg, "AUTH_RETRIES", 10, -1, G_MAXINT32, -1); - g_object_set (s_con, NM_SETTING_CONNECTION_AUTH_RETRIES, (gint) vint64, NULL); + g_object_set (s_con, NM_SETTING_CONNECTION_AUTH_RETRIES, (int) vint64, NULL); i_val = NM_SETTING_CONNECTION_MDNS_DEFAULT; if (!svGetValueEnum (ifcfg, "MDNS", @@ -344,6 +554,13 @@ make_connection_setting (const char *file, PARSE_WARNING ("invalid MDNS setting"); g_object_set (s_con, NM_SETTING_CONNECTION_MDNS, i_val, NULL); + i_val = NM_SETTING_CONNECTION_LLMNR_DEFAULT; + if (!svGetValueEnum (ifcfg, "LLMNR", + nm_setting_connection_llmnr_get_type (), + &i_val, NULL)) + PARSE_WARNING ("invalid LLMNR setting"); + g_object_set (s_con, NM_SETTING_CONNECTION_LLMNR, i_val, NULL); + return NM_SETTING (s_con); } @@ -674,7 +891,7 @@ parse_route_line (const char *line, * Maybe later we want to support some form of quotation here. * Which of course, would be incompatible with initscripts. */ - words_free = nm_utils_strsplit_set (line, " \t\n"); + words_free = nm_utils_strsplit_set (line, " \t\n", FALSE); words = words_free ?: NM_PTRARRAY_EMPTY (const char *); @@ -1110,7 +1327,7 @@ parse_dns_options (NMSettingIPConfig *ip_config, const char *value) if (!nm_setting_ip_config_has_dns_options (ip_config)) nm_setting_ip_config_clear_dns_options (ip_config, TRUE); - options = nm_utils_strsplit_set (value, " "); + options = nm_utils_strsplit_set (value, " ", FALSE); if (options) { for (item = options; *item; item++) { if (!nm_setting_ip_config_add_dns_option (ip_config, *item)) @@ -1178,7 +1395,7 @@ make_user_setting (shvarFile *ifcfg) const char *key; nm_auto_free_gstring GString *str = NULL; - keys = svGetKeys (ifcfg); + keys = svGetKeys (ifcfg, SV_KEY_TYPE_USER); if (!keys) return NULL; @@ -1187,9 +1404,6 @@ make_user_setting (shvarFile *ifcfg) const char *value; gs_free char *value_to_free = NULL; - if (!g_str_has_prefix (key, "NM_USER_")) - continue; - value = svGetValue (ifcfg, key, &value_to_free); if (!value) @@ -1217,6 +1431,32 @@ make_user_setting (shvarFile *ifcfg) } static NMSetting * +make_match_setting (shvarFile *ifcfg) +{ + NMSettingMatch *s_match = NULL; + gs_free const char **strv = NULL; + gs_free char *value = NULL; + const char *v; + gsize i; + + v = svGetValueStr (ifcfg, "MATCH_INTERFACE_NAME", &value); + if (!v) + return NULL; + + strv = nm_utils_strsplit_set (v, " \t", TRUE); + if (strv) { + for (i = 0; strv[i]; i++) { + if (!s_match) + s_match = (NMSettingMatch *) nm_setting_match_new (); + nm_setting_match_add_interface_name (s_match, + _nm_utils_unescape_spaces ((char *) strv[i])); + } + } + + return (NMSetting *) s_match; +} + +static NMSetting * make_proxy_setting (shvarFile *ifcfg) { NMSettingProxy *s_proxy = NULL; @@ -1286,7 +1526,7 @@ make_ip4_setting (shvarFile *ifcfg, shvarFile *route_ifcfg; gboolean never_default; gint64 timeout; - gint priority; + int priority; char inet_buf[NM_UTILS_INET_ADDRSTRLEN]; const char *const *item; guint32 route_table; @@ -1483,7 +1723,7 @@ make_ip4_setting (shvarFile *ifcfg, if (v) { gs_free const char **searches = NULL; - searches = nm_utils_strsplit_set (v, " "); + searches = nm_utils_strsplit_set (v, " ", FALSE); if (searches) { for (item = searches; *item; item++) { if (!nm_setting_ip_config_add_dns_search (s_ip4, *item)) @@ -1544,7 +1784,7 @@ make_ip4_setting (shvarFile *ifcfg, if (v) { gs_free const char **searches = NULL; - searches = nm_utils_strsplit_set (v, " "); + searches = nm_utils_strsplit_set (v, " ", FALSE); if (searches) { for (item = searches; *item; item++) { if (!nm_setting_ip_config_add_dns_search (s_ip4, *item)) @@ -1561,7 +1801,7 @@ make_ip4_setting (shvarFile *ifcfg, if (timeout > 0) timeout *= 1000; } - g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DAD_TIMEOUT, (gint) timeout, NULL); + g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DAD_TIMEOUT, (int) timeout, NULL); return g_steal_pointer (&s_ip4); } @@ -1697,7 +1937,7 @@ make_ip6_setting (shvarFile *ifcfg, guint32 i; int i_val; GError *local = NULL; - gint priority; + int priority; gboolean never_default = FALSE; gboolean ip6_privacy = FALSE, ip6_privacy_prefer_public_ip; NMSettingIP6ConfigPrivacy ip6_privacy_val; @@ -1860,7 +2100,7 @@ make_ip6_setting (shvarFile *ifcfg, ipv6addr_secondaries ?: "", NULL); - list = nm_utils_strsplit_set (value, " "); + list = nm_utils_strsplit_set (value, " ", FALSE); for (iter = list, i = 0; iter && *iter; iter++, i++) { NMIPAddress *addr = NULL; @@ -1953,7 +2193,7 @@ make_ip6_setting (shvarFile *ifcfg, if (v) { gs_free const char **searches = NULL; - searches = nm_utils_strsplit_set (v, " "); + searches = nm_utils_strsplit_set (v, " ", FALSE); if (searches) { for (iter = searches; *iter; iter++) { if (!nm_setting_ip_config_add_dns_search (s_ip6, *iter)) @@ -1982,6 +2222,68 @@ error: } static NMSetting * +make_sriov_setting (shvarFile *ifcfg) +{ + gs_unref_hashtable GHashTable *keys = NULL; + gs_unref_ptrarray GPtrArray *vfs = NULL; + NMTernary autoprobe_drivers; + NMSettingSriov *s_sriov; + int total_vfs; + + total_vfs = svGetValueInt64 (ifcfg, "SRIOV_TOTAL_VFS", 10, 0, G_MAXINT32, 0); + if (!total_vfs) + return NULL; + + autoprobe_drivers = svGetValueInt64 (ifcfg, + "SRIOV_AUTOPROBE_DRIVERS", + 10, + NM_TERNARY_FALSE, + NM_TERNARY_TRUE, + NM_TERNARY_DEFAULT); + + keys = svGetKeys (ifcfg, SV_KEY_TYPE_SRIOV_VF); + if (keys) { + GHashTableIter iter; + const char *key; + + g_hash_table_iter_init (&iter, keys); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) { + gs_free_error GError *error = NULL; + gs_free char *value_to_free = NULL; + const char *value; + NMSriovVF *vf; + + nm_assert (g_str_has_prefix (key, "SRIOV_VF")); + + value = svGetValue (ifcfg, key, &value_to_free); + if (!value) + continue; + + key += NM_STRLEN ("SRIOV_VF"); + + vf = _nm_utils_sriov_vf_from_strparts (key, value, &error); + if (!vf) { + PARSE_WARNING ("ignoring invalid SR-IOV VF '%s %s': %s", + key, value, error->message); + continue; + } + if (!vfs) + vfs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_sriov_vf_unref); + g_ptr_array_add (vfs, vf); + } + } + + s_sriov = (NMSettingSriov *) nm_setting_sriov_new (); + g_object_set (s_sriov, + NM_SETTING_SRIOV_TOTAL_VFS, total_vfs, + NM_SETTING_SRIOV_VFS, vfs, + NM_SETTING_SRIOV_AUTOPROBE_DRIVERS, (int) autoprobe_drivers, + NULL); + + return (NMSetting *) s_sriov; +} + +static NMSetting * make_tc_setting (shvarFile *ifcfg) { NMSettingTCConfig *s_tc = NULL; @@ -2241,7 +2543,7 @@ read_dcb_percent_array (shvarFile *ifcfg, return TRUE; } - split = nm_utils_strsplit_set (val, ","); + split = nm_utils_strsplit_set (val, ",", FALSE); if (NM_PTRARRAY_LEN (split) != 8) { PARSE_WARNING ("invalid %s percentage list value '%s'", prop, val); g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, @@ -2518,30 +2820,6 @@ read_wep_keys (shvarFile *ifcfg, return TRUE; } -static NMSettingSecretFlags -read_secret_flags (shvarFile *ifcfg, const char *flags_key) -{ - NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE; - char *val; - - g_return_val_if_fail (flags_key != NULL, NM_SETTING_SECRET_FLAG_NONE); - g_return_val_if_fail (flags_key[0] != '\0', NM_SETTING_SECRET_FLAG_NONE); - g_return_val_if_fail (g_str_has_suffix (flags_key, "_FLAGS"), NM_SETTING_SECRET_FLAG_NONE); - - val = svGetValueStr_cp (ifcfg, flags_key); - if (val) { - if (strstr (val, SECRET_FLAG_AGENT)) - flags |= NM_SETTING_SECRET_FLAG_AGENT_OWNED; - if (strstr (val, SECRET_FLAG_NOT_SAVED)) - flags |= NM_SETTING_SECRET_FLAG_NOT_SAVED; - if (strstr (val, SECRET_FLAG_NOT_REQUIRED)) - flags |= NM_SETTING_SECRET_FLAG_NOT_REQUIRED; - - g_free (val); - } - return flags; -} - static NMSetting * make_wep_setting (shvarFile *ifcfg, const char *file, @@ -2573,7 +2851,7 @@ make_wep_setting (shvarFile *ifcfg, } /* Read WEP key flags */ - key_flags = read_secret_flags (ifcfg, "WEP_KEY_FLAGS"); + key_flags = _secret_read_ifcfg_flags (ifcfg, "WEP_KEY_FLAGS"); g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, key_flags, NULL); /* Read keys in the ifcfg file if they are system-owned */ @@ -2677,7 +2955,7 @@ fill_wpa_ciphers (shvarFile *ifcfg, if (!p) return TRUE; - list = nm_utils_strsplit_set (p, " "); + list = nm_utils_strsplit_set (p, " ", FALSE); for (iter = list; iter && *iter; iter++, i++) { /* Ad-Hoc configurations cannot have pairwise ciphers, and can only * have one group cipher. Ignore any additional group ciphers and @@ -2772,254 +3050,118 @@ parse_wpa_psk (shvarFile *ifcfg, return g_steal_pointer (&psk); } -static void -read_8021x_password (shvarFile *ifcfg, shvarFile *keys_ifcfg, const char *name, - char **value, NMSettingSecretFlags *flags) -{ - gs_free char *flags_key = NULL; - - *value = NULL; - flags_key = g_strdup_printf ("%s_FLAGS", name); - *flags = read_secret_flags (ifcfg, flags_key); - - if (*flags == NM_SETTING_SECRET_FLAG_NONE) { - *value = svGetValueStr_cp (ifcfg, name); - if (!*value && keys_ifcfg) - *value = svGetValueStr_cp (keys_ifcfg, name); - } -} - static gboolean eap_simple_reader (const char *eap_method, shvarFile *ifcfg, - shvarFile *keys, + shvarFile *keys_ifcfg, NMSetting8021x *s_8021x, gboolean phase2, GError **error) { NMSettingSecretFlags flags; - GBytes *bytes; - char *value; + gs_free char *identity_free = NULL; + nm_auto_free_secret char *password_raw_str = NULL; + gs_unref_bytes GBytes *password_raw_bytes = NULL; - value = svGetValueStr_cp (ifcfg, "IEEE_8021X_IDENTITY"); - if (!value) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Missing IEEE_8021X_IDENTITY for EAP method '%s'.", - eap_method); - return FALSE; - } - g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL); - nm_clear_g_free (&value); + g_object_set (s_8021x, + NM_SETTING_802_1X_IDENTITY, + svGetValueStr (ifcfg, "IEEE_8021X_IDENTITY", &identity_free), + NULL); - read_8021x_password (ifcfg, keys, "IEEE_8021X_PASSWORD", &value, &flags); - g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD_FLAGS, flags, NULL); - if (value) { - g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD, value, NULL); - nm_clear_g_free (&value); - } + _secret_set_from_ifcfg (s_8021x, + ifcfg, + keys_ifcfg, + "IEEE_8021X_PASSWORD", + NM_SETTING_802_1X_PASSWORD); + + _secret_read_ifcfg (ifcfg, keys_ifcfg, "IEEE_8021X_PASSWORD_RAW", &password_raw_str, &flags); + if (!_secret_password_raw_to_bytes ("IEEE_8021X_PASSWORD_RAW", + password_raw_str, + &password_raw_bytes, + error)) + return FALSE; - read_8021x_password (ifcfg, keys, "IEEE_8021X_PASSWORD_RAW", &value, &flags); - g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD_RAW_FLAGS, flags, NULL); - if (value) { - bytes = nm_utils_hexstr2bin (value); - if (!bytes) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid hex string '%s' in IEEE_8021X_PASSWORD_RAW.", - value); - g_free (value); - return FALSE; - } - g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD_RAW, bytes, NULL); - g_bytes_unref (bytes); - nm_clear_g_free (&value); - } + g_object_set (s_8021x, + NM_SETTING_802_1X_PASSWORD_RAW_FLAGS, + flags, + NM_SETTING_802_1X_PASSWORD_RAW, + password_raw_bytes, + NULL); return TRUE; } -static char * -get_full_file_path (const char *ifcfg_path, const char *file_path) -{ - const char *base = file_path; - char *p, *ret, *dirname; - - g_return_val_if_fail (ifcfg_path != NULL, NULL); - g_return_val_if_fail (file_path != NULL, NULL); - - if (file_path[0] == '/') - return g_strdup (file_path); - - p = strrchr (file_path, '/'); - if (p) - base = p + 1; - - dirname = g_path_get_dirname (ifcfg_path); - ret = g_build_path ("/", dirname, base, NULL); - g_free (dirname); - return ret; -} - -static char * -get_cert_value (const char *ifcfg_path, const char *value, - NMSetting8021xCKScheme *out_scheme) -{ - if (strncmp (value, "pkcs11:", 7) == 0) { - *out_scheme = NM_SETTING_802_1X_CK_SCHEME_PKCS11; - return g_strdup (value); - } - - *out_scheme = NM_SETTING_802_1X_CK_SCHEME_PATH; - return get_full_file_path (ifcfg_path, value); -} - static gboolean eap_tls_reader (const char *eap_method, shvarFile *ifcfg, - shvarFile *keys, + shvarFile *keys_ifcfg, NMSetting8021x *s_8021x, gboolean phase2, GError **error) { - gs_free char *ca_cert = NULL; - gs_free char *privkey = NULL; - gs_free char *privkey_password = NULL; - char *value; - char *ca_cert_password = NULL; - char *client_cert_password = NULL; - NMSetting8021xCKFormat privkey_format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; - const char *ca_cert_key = phase2 ? "IEEE_8021X_INNER_CA_CERT" : "IEEE_8021X_CA_CERT"; - const char *ca_cert_pw_key = phase2 ? "IEEE_8021X_INNER_CA_CERT_PASSWORD" : "IEEE_8021X_CA_CERT_PASSWORD"; - const char *ca_cert_pw_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD : NM_SETTING_802_1X_CA_CERT_PASSWORD; - const char *ca_cert_pw_flags_key = phase2 ? "IEEE_8021X_INNER_CA_CERT_PASSWORD_FLAGS" : "IEEE_8021X_CA_CERT_PASSWORD_FLAGS"; - const char *ca_cert_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD_FLAGS : NM_SETTING_802_1X_CA_CERT_PASSWORD_FLAGS; - const char *cli_cert_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT"; - const char *cli_cert_pw_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT_PASSWORD" : "IEEE_8021X_CLIENT_CERT_PASSWORD"; - const char *cli_cert_pw_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD : NM_SETTING_802_1X_CLIENT_CERT_PASSWORD; - const char *cli_cert_pw_flags_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT_PASSWORD_FLAGS" : "IEEE_8021X_CLIENT_CERT_PASSWORD_FLAGS"; - const char *cli_cert_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD_FLAGS : NM_SETTING_802_1X_CLIENT_CERT_PASSWORD_FLAGS; - const char *pk_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY"; - const char *pk_pw_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD": "IEEE_8021X_PRIVATE_KEY_PASSWORD"; - const char *pk_pw_flags_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD_FLAGS" : "IEEE_8021X_PRIVATE_KEY_PASSWORD_FLAGS"; - const char *pk_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS : NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS; - NMSettingSecretFlags flags; - NMSetting8021xCKScheme scheme; + gs_unref_bytes GBytes *privkey = NULL; + gs_unref_bytes GBytes *client_cert = NULL; + gs_free char *identity_free = NULL; - value = svGetValueStr_cp (ifcfg, "IEEE_8021X_IDENTITY"); - if (value) { - g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL); - g_free (value); - } - - ca_cert = svGetValueStr_cp (ifcfg, ca_cert_key); - if (ca_cert) { - gs_free char *real_cert_value = NULL; - - real_cert_value = get_cert_value (svFileGetName (ifcfg), ca_cert, &scheme); - if (phase2) { - if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x, real_cert_value, scheme, NULL, error)) - return FALSE; - } else { - if (!nm_setting_802_1x_set_ca_cert (s_8021x, real_cert_value, scheme, NULL, error)) - return FALSE; - } - - if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) { - flags = read_secret_flags (ifcfg, ca_cert_pw_flags_key); - g_object_set (s_8021x, ca_cert_pw_flags_prop, flags, NULL); - - if (flags == NM_SETTING_SECRET_FLAG_NONE) { - ca_cert_password = svGetValueStr_cp (ifcfg, ca_cert_pw_key); - g_object_set (s_8021x, ca_cert_pw_prop, ca_cert_password, NULL); - } - } - } else { - PARSE_WARNING ("missing %s for EAP method '%s'; this is insecure!", - ca_cert_key, eap_method); - } - - /* Read and set private key password flags */ - flags = read_secret_flags (ifcfg, pk_pw_flags_key); - g_object_set (s_8021x, pk_pw_flags_prop, flags, NULL); - - /* Read the private key password if it's system-owned */ - if (flags == NM_SETTING_SECRET_FLAG_NONE) { - /* Private key password */ - privkey_password = svGetValueStr_cp (ifcfg, pk_pw_key); - if (!privkey_password && keys) { - /* Try the lookaside keys file */ - privkey_password = svGetValueStr_cp (keys, pk_pw_key); - } - } + g_object_set (s_8021x, + NM_SETTING_802_1X_IDENTITY, + svGetValueStr (ifcfg, "IEEE_8021X_IDENTITY", &identity_free), + NULL); - /* The private key itself */ - privkey = svGetValueStr_cp (ifcfg, pk_key); + if (!_cert_set_from_ifcfg (s_8021x, + ifcfg, + phase2 ? "IEEE_8021X_INNER_CA_CERT" : "IEEE_8021X_CA_CERT", + phase2 ? NM_SETTING_802_1X_PHASE2_CA_CERT : NM_SETTING_802_1X_CA_CERT, + NULL, + error)) + return FALSE; + _secret_set_from_ifcfg (s_8021x, + ifcfg, + keys_ifcfg, + phase2 ? "IEEE_8021X_INNER_CA_CERT_PASSWORD" : "IEEE_8021X_CA_CERT_PASSWORD", + phase2 ? NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD : NM_SETTING_802_1X_CA_CERT_PASSWORD); + + if (!_cert_set_from_ifcfg (s_8021x, + ifcfg, + phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY", + phase2 ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY : NM_SETTING_802_1X_PRIVATE_KEY, + &privkey, + error)) + return FALSE; + _secret_set_from_ifcfg (s_8021x, + ifcfg, + keys_ifcfg, + phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD" : "IEEE_8021X_PRIVATE_KEY_PASSWORD", + phase2 ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD : NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD); if (!privkey) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing %s for EAP method '%s'.", - pk_key, + phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY", eap_method); return FALSE; } - { - gs_free char *real_cert_value = NULL; - - real_cert_value = get_cert_value (svFileGetName (ifcfg), privkey, &scheme); - if (phase2) { - if (!nm_setting_802_1x_set_phase2_private_key (s_8021x, - real_cert_value, - privkey_password, - scheme, - &privkey_format, - error)) - return FALSE; - } else { - if (!nm_setting_802_1x_set_private_key (s_8021x, - real_cert_value, - privkey_password, - scheme, - &privkey_format, - error)) - return FALSE; - } - } - - /* Only set the client certificate if the private key is not PKCS#12 format, - * as NM (due to supplicant restrictions) requires. If the key was PKCS#12, - * then nm_setting_802_1x_set_private_key() already set the client certificate - * to the same value as the private key. - */ - if (privkey_format != NM_SETTING_802_1X_CK_FORMAT_PKCS12) { - gs_free char *real_cert_value = NULL; - gs_free char *client_cert = NULL; - - client_cert = svGetValueStr_cp (ifcfg, cli_cert_key); - if (!client_cert) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Missing %s for EAP method '%s'.", - cli_cert_key, - eap_method); - return FALSE; - } - - real_cert_value = get_cert_value (svFileGetName (ifcfg), client_cert, &scheme); - if (phase2) { - if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x, real_cert_value, scheme, NULL, error)) - return FALSE; - } else { - if (!nm_setting_802_1x_set_client_cert (s_8021x, real_cert_value, scheme, NULL, error)) - return FALSE; - } - - if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) { - flags = read_secret_flags (ifcfg, cli_cert_pw_flags_key); - g_object_set (s_8021x, cli_cert_pw_flags_prop, flags, NULL); - - if (flags == NM_SETTING_SECRET_FLAG_NONE) { - client_cert_password = svGetValueStr_cp (ifcfg, cli_cert_pw_key); - g_object_set (s_8021x, cli_cert_pw_prop, client_cert_password, NULL); - } - } + if (!_cert_set_from_ifcfg (s_8021x, + ifcfg, + phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT", + phase2 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT : NM_SETTING_802_1X_CLIENT_CERT, + &client_cert, + error)) + return FALSE; + /* FIXME: writer does not actually write IEEE_8021X_CLIENT_CERT_PASSWORD and other + * certificate related passwords. It should, because otherwise persisting such profiles + * to ifcfg looses information. As this currently only matters for PKCS11 URIs, it seems + * a seldomly used feature so that it is not fixed yet. */ + _secret_set_from_ifcfg (s_8021x, + ifcfg, + keys_ifcfg, + phase2 ? "IEEE_8021X_INNER_CLIENT_CERT_PASSWORD" : "IEEE_8021X_CLIENT_CERT_PASSWORD", + phase2 ? NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD : NM_SETTING_802_1X_CLIENT_CERT_PASSWORD); + if (!client_cert) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Missing certificate for EAP method '%s'.", + eap_method); + return FALSE; } return TRUE; @@ -3028,7 +3170,7 @@ eap_tls_reader (const char *eap_method, static gboolean eap_peap_reader (const char *eap_method, shvarFile *ifcfg, - shvarFile *keys, + shvarFile *keys_ifcfg, NMSetting8021x *s_8021x, gboolean phase2, GError **error) @@ -3037,19 +3179,19 @@ eap_peap_reader (const char *eap_method, const char *v; gs_free const char **list = NULL; const char *const *iter; - NMSetting8021xCKScheme scheme; - - v = svGetValueStr (ifcfg, "IEEE_8021X_CA_CERT", &value); - if (v) { - gs_free char *real_cert_value = NULL; - real_cert_value = get_cert_value (svFileGetName (ifcfg), v, &scheme); - if (!nm_setting_802_1x_set_ca_cert (s_8021x, real_cert_value, scheme, NULL, error)) - return FALSE; - } else { - PARSE_WARNING ("missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!", - eap_method); - } + if (!_cert_set_from_ifcfg (s_8021x, + ifcfg, + "IEEE_8021X_CA_CERT", + NM_SETTING_802_1X_CA_CERT, + NULL, + error)) + return FALSE; + _secret_set_from_ifcfg (s_8021x, + ifcfg, + keys_ifcfg, + "IEEE_8021X_CA_CERT_PASSWORD", + NM_SETTING_802_1X_CA_CERT_PASSWORD); nm_clear_g_free (&value); v = svGetValueStr (ifcfg, "IEEE_8021X_PEAP_VERSION", &value); @@ -3083,16 +3225,16 @@ eap_peap_reader (const char *eap_method, } /* Handle options for the inner auth method */ - list = nm_utils_strsplit_set (v, " "); + list = nm_utils_strsplit_set (v, " ", FALSE); iter = list; if (iter) { if (NM_IN_STRSET (*iter, "MSCHAPV2", "MD5", "GTC")) { - if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error)) + if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error)) return FALSE; } else if (nm_streq (*iter, "TLS")) { - if (!eap_tls_reader (*iter, ifcfg, keys, s_8021x, TRUE, error)) + if (!eap_tls_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error)) return FALSE; } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, @@ -3121,7 +3263,7 @@ eap_peap_reader (const char *eap_method, static gboolean eap_ttls_reader (const char *eap_method, shvarFile *ifcfg, - shvarFile *keys, + shvarFile *keys_ifcfg, NMSetting8021x *s_8021x, gboolean phase2, GError **error) @@ -3131,19 +3273,19 @@ eap_ttls_reader (const char *eap_method, const char *v; gs_free const char **list = NULL; const char *const *iter; - NMSetting8021xCKScheme scheme; - - v = svGetValueStr (ifcfg, "IEEE_8021X_CA_CERT", &value); - if (v) { - gs_free char *real_cert_value = NULL; - real_cert_value = get_cert_value (svFileGetName (ifcfg), v, &scheme); - if (!nm_setting_802_1x_set_ca_cert (s_8021x, real_cert_value, scheme, NULL, error)) - return FALSE; - } else { - PARSE_WARNING ("missing IEEE_8021X_CA_CERT for EAP method '%s'; this is insecure!", - eap_method); - } + if (!_cert_set_from_ifcfg (s_8021x, + ifcfg, + "IEEE_8021X_CA_CERT", + NM_SETTING_802_1X_CA_CERT, + NULL, + error)) + return FALSE; + _secret_set_from_ifcfg (s_8021x, + ifcfg, + keys_ifcfg, + "IEEE_8021X_CA_CERT_PASSWORD", + NM_SETTING_802_1X_CA_CERT_PASSWORD); nm_clear_g_free (&value); v = svGetValueStr (ifcfg, "IEEE_8021X_ANON_IDENTITY", &value); @@ -3161,24 +3303,24 @@ eap_ttls_reader (const char *eap_method, inner_auth = g_ascii_strdown (v, -1); /* Handle options for the inner auth method */ - list = nm_utils_strsplit_set (inner_auth, " "); + list = nm_utils_strsplit_set (inner_auth, " ", FALSE); iter = list; if (iter) { if (NM_IN_STRSET (*iter, "mschapv2", "mschap", "pap", "chap")) { - if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error)) + if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error)) return FALSE; g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, *iter, NULL); } else if (nm_streq (*iter, "eap-tls")) { - if (!eap_tls_reader (*iter, ifcfg, keys, s_8021x, TRUE, error)) + if (!eap_tls_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error)) return FALSE; g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, "tls", NULL); } else if (NM_IN_STRSET (*iter, "eap-mschapv2", "eap-md5", "eap-gtc")) { - if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error)) + if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error)) return FALSE; g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, (*iter + NM_STRLEN ("eap-")), NULL); } else { @@ -3195,7 +3337,7 @@ eap_ttls_reader (const char *eap_method, static gboolean eap_fast_reader (const char *eap_method, shvarFile *ifcfg, - shvarFile *keys, + shvarFile *keys_ifcfg, NMSetting8021x *s_8021x, gboolean phase2, GError **error) @@ -3222,7 +3364,7 @@ eap_fast_reader (const char *eap_method, if (fast_provisioning) { gs_free const char **list1 = NULL; - list1 = nm_utils_strsplit_set (fast_provisioning, " \t"); + list1 = nm_utils_strsplit_set (fast_provisioning, " \t", FALSE); for (iter = list1; iter && *iter; iter++) { if (strcmp (*iter, "allow-unauth") == 0) allow_unauth = TRUE; @@ -3256,12 +3398,12 @@ eap_fast_reader (const char *eap_method, } /* Handle options for the inner auth method */ - list = nm_utils_strsplit_set (inner_auth, " "); + list = nm_utils_strsplit_set (inner_auth, " ", FALSE); iter = list; if (iter) { if ( !strcmp (*iter, "MSCHAPV2") || !strcmp (*iter, "GTC")) { - if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error)) + if (!eap_simple_reader (*iter, ifcfg, keys_ifcfg, s_8021x, TRUE, error)) goto done; } else { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, @@ -3296,7 +3438,7 @@ typedef struct { const char *method; gboolean (*reader) (const char *eap_method, shvarFile *ifcfg, - shvarFile *keys, + shvarFile *keys_ifcfg, NMSetting8021x *s_8021x, gboolean phase2, GError **error); @@ -3336,7 +3478,7 @@ read_8021x_list_value (shvarFile *ifcfg, if (!v) return; - strv = nm_utils_strsplit_set (v, " \t"); + strv = nm_utils_strsplit_set (v, " \t", FALSE); if (strv) g_object_set (setting, prop_name, strv, NULL); } @@ -3348,7 +3490,7 @@ fill_8021x (shvarFile *ifcfg, gboolean wifi, GError **error) { - nm_auto_shvar_file_close shvarFile *keys = NULL; + nm_auto_shvar_file_close shvarFile *keys_ifcfg = NULL; gs_unref_object NMSetting8021x *s_8021x = NULL; gs_free char *value = NULL; const char *v; @@ -3365,12 +3507,12 @@ fill_8021x (shvarFile *ifcfg, return NULL; } - list = nm_utils_strsplit_set (v, " "); + list = nm_utils_strsplit_set (v, " ", FALSE); s_8021x = (NMSetting8021x *) nm_setting_802_1x_new (); - /* Read in the lookaside keys file, if present */ - keys = utils_get_keys_ifcfg (file, FALSE); + /* Read in the lookaside keys_ifcfg file, if present */ + keys_ifcfg = utils_get_keys_ifcfg (file, FALSE); /* Validate and handle each EAP method */ for (iter = list; iter && *iter; iter++) { @@ -3394,7 +3536,7 @@ fill_8021x (shvarFile *ifcfg, } /* Parse EAP method specific options */ - if (!(*eap->reader)(lower, ifcfg, keys, s_8021x, FALSE, error)) + if (!(*eap->reader)(lower, ifcfg, keys_ifcfg, s_8021x, FALSE, error)) return NULL; nm_setting_802_1x_add_eap_method (s_8021x, lower); @@ -3444,7 +3586,7 @@ next: g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH, v, NULL); timeout = svGetValueInt64 (ifcfg, "IEEE_8021X_AUTH_TIMEOUT", 10, 0, G_MAXINT32, 0); - g_object_set (s_8021x, NM_SETTING_802_1X_AUTH_TIMEOUT, (gint) timeout, NULL); + g_object_set (s_8021x, NM_SETTING_802_1X_AUTH_TIMEOUT, (int) timeout, NULL); return g_steal_pointer (&s_8021x); } @@ -3510,7 +3652,7 @@ make_wpa_setting (shvarFile *ifcfg, if (wpa_psk) { NMSettingSecretFlags psk_flags; - psk_flags = read_secret_flags (ifcfg, "WPA_PSK_FLAGS"); + psk_flags = _secret_read_ifcfg_flags (ifcfg, "WPA_PSK_FLAGS"); g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS, psk_flags, NULL); /* Read PSK if it's system-owned */ @@ -3597,7 +3739,7 @@ make_leap_setting (shvarFile *ifcfg, return NULL; /* Not LEAP */ nm_clear_g_free (&value); - flags = read_secret_flags (ifcfg, "IEEE_8021X_PASSWORD_FLAGS"); + flags = _secret_read_ifcfg_flags (ifcfg, "IEEE_8021X_PASSWORD_FLAGS"); g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS, flags, NULL); /* Read LEAP password if it's system-owned */ @@ -3674,7 +3816,7 @@ transform_hwaddr_blacklist (const char *blacklist) const char **strv; gsize i, j; - strv = nm_utils_strsplit_set (blacklist, " \t"); + strv = nm_utils_strsplit_set (blacklist, " \t", FALSE); if (!strv) return NULL; for (i = 0, j = 0; strv[j]; j++) { @@ -3923,7 +4065,7 @@ wireless_connection_from_ifcfg (const char *file, NMSetting8021x *s_8021x = NULL; GBytes *ssid; NMSetting *security_setting = NULL; - char *printable_ssid = NULL; + gs_free char *ssid_utf8 = NULL; const char *mode; gboolean adhoc = FALSE; GError *local = NULL; @@ -3943,12 +4085,6 @@ wireless_connection_from_ifcfg (const char *file, nm_connection_add_setting (connection, wireless_setting); ssid = nm_setting_wireless_get_ssid (NM_SETTING_WIRELESS (wireless_setting)); - if (ssid) { - printable_ssid = nm_utils_ssid_to_utf8 (g_bytes_get_data (ssid, NULL), - g_bytes_get_size (ssid)); - } else - printable_ssid = g_strdup ("unmanaged"); - mode = nm_setting_wireless_get_mode (NM_SETTING_WIRELESS (wireless_setting)); if (mode && !strcmp (mode, "adhoc")) adhoc = TRUE; @@ -3956,7 +4092,6 @@ wireless_connection_from_ifcfg (const char *file, /* Wireless security */ security_setting = make_wireless_security_setting (ifcfg, file, ssid, adhoc, &s_8021x, &local); if (local) { - g_free (printable_ssid); g_object_unref (connection); g_propagate_error (error, local); return NULL; @@ -3967,11 +4102,16 @@ wireless_connection_from_ifcfg (const char *file, nm_connection_add_setting (connection, NM_SETTING (s_8021x)); } + if (ssid) + ssid_utf8 = _nm_utils_ssid_to_utf8 (ssid); + /* Connection */ - con_setting = make_connection_setting (file, ifcfg, + con_setting = make_connection_setting (file, + ifcfg, NM_SETTING_WIRELESS_SETTING_NAME, - printable_ssid, NULL); - g_free (printable_ssid); + nm_str_not_empty (ssid_utf8) ?: "unmanaged", + NULL); + if (!con_setting) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Failed to create connection setting."); @@ -3984,199 +4124,253 @@ wireless_connection_from_ifcfg (const char *file, } static void -parse_ethtool_option_autoneg (const char *value, gboolean *out_autoneg) +parse_ethtool_option (const char *value, + NMSettingWiredWakeOnLan *out_flags, + char **out_password, + gboolean *out_autoneg, + guint32 *out_speed, + const char **out_duplex, + NMSettingEthtool **out_s_ethtool) { - if (!value) { - PARSE_WARNING ("Auto-negotiation option missing"); + gs_free const char **words = NULL; + guint i; + + words = nm_utils_strsplit_set (value, NULL, FALSE); + if (!words) return; - } - if (g_str_equal (value, "off")) - *out_autoneg = FALSE; - else if (g_str_equal (value, "on")) - *out_autoneg = TRUE; - else - PARSE_WARNING ("Auto-negotiation unknown value: %s", value); -} + if (words[0] && words[0][0] == '-') { + /* /sbin/ethtool $opts */ + if (NM_IN_STRSET (words[0], "-K", "--features", "--offload")) { + if (!words[1]) { + /* first argument must be the interface name. This is invalid. */ + return; + } -static void -parse_ethtool_option_speed (const char *value, guint32 *out_speed) -{ - if (!value) { - PARSE_WARNING ("Speed option missing"); - return; - } + if (!*out_s_ethtool) + *out_s_ethtool = NM_SETTING_ETHTOOL (nm_setting_ethtool_new ()); - *out_speed = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, 0); - if (errno) - PARSE_WARNING ("Speed value '%s' is invalid", value); -} + for (i = 2; words[i]; ) { + const char *opt = words[i]; + const char *opt_val = words[++i]; + const NMEthtoolData *d = NULL; + NMTernary onoff = NM_TERNARY_DEFAULT; -static void -parse_ethtool_option_duplex (const char *value, const char **out_duplex) -{ - if (!value) { - PARSE_WARNING ("Duplex option missing"); - return; - } + if (nm_streq0 (opt_val, "on")) + onoff = NM_TERNARY_TRUE; + else if (nm_streq0 (opt_val, "off")) + onoff = NM_TERNARY_FALSE; - if (g_str_equal (value, "half")) - *out_duplex = "half"; - else if (g_str_equal (value, "full")) - *out_duplex = "full"; - else - PARSE_WARNING ("Duplex unknown value: %s", value); + d = nms_ifcfg_rh_utils_get_ethtool_by_name (opt); -} + if (!d) { + if (onoff != NM_TERNARY_DEFAULT) { + /* the next value is just the on/off argument. Skip it too. */ + i++; + } -static void -parse_ethtool_option_wol (const char *value, NMSettingWiredWakeOnLan *out_flags) -{ - NMSettingWiredWakeOnLan wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_NONE; + /* silently ignore unsupported offloading features. */ + continue; + } - if (!value) { - PARSE_WARNING ("Wake-on-LAN options missing"); + i++; + + if (onoff == NM_TERNARY_DEFAULT) { + PARSE_WARNING ("Expects on/off argument for feature '%s'", opt); + continue; + } + + nm_setting_ethtool_set_feature (*out_s_ethtool, + d->optname, + onoff); + } + } return; } - for (; *value; value++) { - switch (*value) { - case 'p': - wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_PHY; - break; - case 'u': - wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST; - break; - case 'm': - wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST; - break; - case 'b': - wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST; - break; - case 'a': - wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_ARP; - break; - case 'g': - wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC; - break; - case 's': - break; - case 'd': - wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_NONE; - break; - default: - PARSE_WARNING ("unrecognized Wake-on-LAN option '%c'", *value); + /* /sbin/ethtool -s ${REALDEVICE} $opts */ + for (i = 0; words[i]; ) { + const char *opt = words[i]; + const char *opt_val = words[++i]; + + if (nm_streq (opt, "autoneg")) { + if (!opt_val) { + PARSE_WARNING ("Auto-negotiation option missing"); + break; + } + i++; + + if (nm_streq (opt_val, "off")) + *out_autoneg = FALSE; + else if (nm_streq (opt_val, "on")) + *out_autoneg = TRUE; + else + PARSE_WARNING ("Auto-negotiation unknown value: %s", opt_val); + continue; } - } - *out_flags = wol_flags; -} + if (nm_streq (opt, "speed")) { + guint32 speed; -static void parse_ethtool_option_sopass (const char *value, char **out_password) -{ - if (!value) { - PARSE_WARNING ("Wake-on-LAN password missing"); - return; - } + if (!opt_val) { + PARSE_WARNING ("Speed option missing"); + break; + } + i++; - g_clear_pointer (out_password, g_free); - if (!nm_utils_hwaddr_valid (value, ETH_ALEN)) { - PARSE_WARNING ("Wake-on-LAN password '%s' is invalid", value); - return; - } + speed = _nm_utils_ascii_str_to_int64 (opt_val, 10, 0, G_MAXUINT32, 0); + if (errno == 0) + *out_speed = speed; + else + PARSE_WARNING ("Speed value '%s' is invalid", opt_val); + continue; + } - *out_password = g_strdup (value); -} + if (nm_streq (opt, "duplex")) { + if (!opt_val) { + PARSE_WARNING ("Duplex option missing"); + break; + } + i++; -static void -parse_ethtool_option (const char *value, - NMSettingWiredWakeOnLan *out_flags, - char **out_password, - gboolean *out_autoneg, - guint32 *out_speed, - const char **out_duplex) -{ - gs_free const char **words = NULL; - const char *const *iter; - const char *opt_val, *opt; + if (nm_streq (opt_val, "half")) + *out_duplex = "half"; + else if (nm_streq (opt_val, "full")) + *out_duplex = "full"; + else + PARSE_WARNING ("Duplex unknown value: %s", opt_val); + continue; + } - words = nm_utils_strsplit_set (value, "\t "); - if (!words) - return; + if (nm_streq (opt, "wol")) { + NMSettingWiredWakeOnLan wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_NONE; - iter = words; - - while (iter[0]) { - opt = iter++[0]; - opt_val = iter[0]; - - if (nm_streq (opt, "autoneg")) - parse_ethtool_option_autoneg (opt_val, out_autoneg); - else if (nm_streq (opt, "speed")) - parse_ethtool_option_speed (opt_val, out_speed); - else if (nm_streq (opt, "duplex")) - parse_ethtool_option_duplex (opt_val, out_duplex); - else if (nm_streq (opt, "wol")) - parse_ethtool_option_wol (opt_val, out_flags); - else if (nm_streq (opt, "sopass")) - parse_ethtool_option_sopass (opt_val, out_password); - else { - /* Silently skip unknown options */ + if (!opt_val) { + PARSE_WARNING ("Wake-on-LAN options missing"); + break; + } + i++; + + for (; *opt_val; opt_val++) { + switch (*opt_val) { + case 'p': + wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_PHY; + break; + case 'u': + wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST; + break; + case 'm': + wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST; + break; + case 'b': + wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST; + break; + case 'a': + wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_ARP; + break; + case 'g': + wol_flags |= NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC; + break; + case 's': + break; + case 'd': + wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_NONE; + break; + default: + PARSE_WARNING ("unrecognized Wake-on-LAN option '%c'", *opt_val); + } + } + + *out_flags = wol_flags; continue; } - if (iter[0]) - iter++; + if (nm_streq (opt, "sopass")) { + if (!opt_val) { + PARSE_WARNING ("Wake-on-LAN password missing"); + break; + } + i++; + + if (nm_utils_hwaddr_valid (opt_val, ETH_ALEN)) { + g_clear_pointer (out_password, g_free); + *out_password = g_strdup (opt_val); + } else + PARSE_WARNING ("Wake-on-LAN password '%s' is invalid", opt_val); + continue; + } + + /* Silently skip unknown options */ } } static void -parse_ethtool_options (shvarFile *ifcfg, NMSettingWired *s_wired, const char *value) +parse_ethtool_options (shvarFile *ifcfg, NMConnection *connection) { + NMSettingWired *s_wired; + gs_unref_object NMSettingEthtool *s_ethtool = NULL; NMSettingWiredWakeOnLan wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT; - gs_free char *wol_password = NULL, *wol_value = NULL; - gboolean ignore_wol_password = FALSE, autoneg = FALSE; + gs_free char *ethtool_opts_free = NULL; + const char *ethtool_opts; + gs_free char *wol_password = NULL; + gs_free char *wol_value_free = NULL; + const char *tmp; + gboolean autoneg = FALSE; guint32 speed = 0; const char *duplex = NULL; - if (value) { - gs_free const char **opts = NULL; - const char *const *iter; - + ethtool_opts = svGetValue (ifcfg, "ETHTOOL_OPTS", ðtool_opts_free); + if (ethtool_opts) { /* WAKE_ON_LAN_IGNORE is inferred from a specified but empty ETHTOOL_OPTS */ - if (!value[0]) + if (!ethtool_opts[0]) wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE; - - opts = nm_utils_strsplit_set (value, ";"); - for (iter = opts; iter && iter[0]; iter++) { - /* in case of repeated wol_passwords, parse_ethtool_option() - * will do the right thing and clear wol_password before resetting. */ - parse_ethtool_option (iter[0], &wol_flags, &wol_password, &autoneg, &speed, &duplex); + else { + gs_free const char **opts = NULL; + const char *const *iter; + + opts = nm_utils_strsplit_set (ethtool_opts, ";", FALSE); + for (iter = opts; iter && iter[0]; iter++) { + /* in case of repeated wol_passwords, parse_ethtool_option() + * will do the right thing and clear wol_password before resetting. */ + parse_ethtool_option (iter[0], + &wol_flags, + &wol_password, + &autoneg, + &speed, + &duplex, + &s_ethtool); + } } } /* ETHTOOL_WAKE_ON_LAN = ignore overrides WoL settings in ETHTOOL_OPTS */ - wol_value = svGetValueStr_cp (ifcfg, "ETHTOOL_WAKE_ON_LAN"); - if (wol_value) { - if (strcmp (wol_value, "ignore") == 0) - wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE; - else - PARSE_WARNING ("invalid ETHTOOL_WAKE_ON_LAN value '%s'", wol_value); - } + tmp = svGetValueStr (ifcfg, "ETHTOOL_WAKE_ON_LAN", &wol_value_free); + if (nm_streq0 (tmp, "ignore")) + wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE; + else if (tmp) + PARSE_WARNING ("invalid ETHTOOL_WAKE_ON_LAN value '%s'", tmp); if ( wol_password && !NM_FLAGS_HAS (wol_flags, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) { PARSE_WARNING ("Wake-on-LAN password not expected"); - ignore_wol_password = TRUE; + nm_clear_g_free (&wol_password); } - g_object_set (s_wired, - NM_SETTING_WIRED_WAKE_ON_LAN, wol_flags, - NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, ignore_wol_password ? NULL : wol_password, - NM_SETTING_WIRED_AUTO_NEGOTIATE, autoneg, - NM_SETTING_WIRED_SPEED, speed, - NM_SETTING_WIRED_DUPLEX, duplex, - NULL); + s_wired = nm_connection_get_setting_wired (connection); + if (s_wired) { + g_object_set (s_wired, + NM_SETTING_WIRED_WAKE_ON_LAN, wol_flags, + NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, wol_password, + NM_SETTING_WIRED_AUTO_NEGOTIATE, autoneg, + NM_SETTING_WIRED_SPEED, speed, + NM_SETTING_WIRED_DUPLEX, duplex, + NULL); + } + + if (s_ethtool) { + nm_connection_add_setting (connection, + NM_SETTING (g_steal_pointer (&s_ethtool))); + } } static NMSetting * @@ -4230,7 +4424,7 @@ make_wired_setting (shvarFile *ifcfg, gs_free const char **chans = NULL; guint32 num_chans; - chans = nm_utils_strsplit_set (value, ","); + chans = nm_utils_strsplit_set (value, ",", FALSE); num_chans = NM_PTRARRAY_LEN (chans); if (num_chans < 2 || num_chans > 3) { PARSE_WARNING ("invalid SUBCHANNELS '%s' (%u channels, 2 or 3 expected)", @@ -4318,10 +4512,6 @@ make_wired_setting (shvarFile *ifcfg, nm_clear_g_free (&value); } - parse_ethtool_options (ifcfg, s_wired, - svGetValue (ifcfg, "ETHTOOL_OPTS", &value)); - nm_clear_g_free (&value); - return (NMSetting *) g_steal_pointer (&s_wired); } @@ -4557,7 +4747,7 @@ make_bond_setting (shvarFile *ifcfg, gs_free const char **items = NULL; const char *const *iter; - items = nm_utils_strsplit_set (v, " "); + items = nm_utils_strsplit_set (v, " ", FALSE); for (iter = items; iter && *iter; iter++) { gs_strfreev char **keys = NULL; const char *key, *val; @@ -4835,7 +5025,7 @@ handle_bridging_opts (NMSetting *setting, gs_free const char **items = NULL; const char *const *iter; - items = nm_utils_strsplit_set (value, " "); + items = nm_utils_strsplit_set (value, " ", FALSE); for (iter = items; iter && *iter; iter++) { gs_strfreev char **keys = NULL; const char *key, *val; @@ -5055,7 +5245,7 @@ parse_prio_map_list (NMSettingVlan *s_vlan, v = svGetValueStr (ifcfg, key, &value); if (!v) return; - list = nm_utils_strsplit_set (v, ","); + list = nm_utils_strsplit_set (v, ",", FALSE); for (iter = list; iter && *iter; iter++) { if (!strchr (*iter, ':')) @@ -5077,7 +5267,7 @@ make_vlan_setting (shvarFile *ifcfg, const char *v = NULL; int vlan_id = -1; guint32 vlan_flags = 0; - gint gvrp, reorder_hdr; + int gvrp, reorder_hdr; v = svGetValueStr (ifcfg, "VLAN_ID", &value); if (v) { @@ -5160,7 +5350,7 @@ make_vlan_setting (shvarFile *ifcfg, gs_free const char **strv = NULL; const char *const *ptr; - strv = nm_utils_strsplit_set (v, ", "); + strv = nm_utils_strsplit_set (v, ", ", FALSE); for (ptr = strv; ptr && *ptr; ptr++) { if (nm_streq (*ptr, "GVRP") && gvrp == -1) vlan_flags |= NM_VLAN_FLAG_GVRP; @@ -5302,7 +5492,7 @@ check_dns_search_domains (shvarFile *ifcfg, NMSetting *s_ip4, NMSetting *s_ip6) gs_free const char **searches = NULL; const char *const *item; - searches = nm_utils_strsplit_set (v, " "); + searches = nm_utils_strsplit_set (v, " ", FALSE); if (searches) { for (item = searches; *item; item++) { if (!nm_setting_ip_config_add_dns_search (NM_SETTING_IP_CONFIG (s_ip6), *item)) @@ -5321,12 +5511,13 @@ connection_from_file_full (const char *filename, GError **error, gboolean *out_ignore_error) { - nm_auto_shvar_file_close shvarFile *parsed = NULL; + nm_auto_shvar_file_close shvarFile *main_ifcfg = NULL; nm_auto_shvar_file_close shvarFile *network_ifcfg = NULL; gs_unref_object NMConnection *connection = NULL; gs_free char *type = NULL; char *devtype, *bootproto; NMSetting *s_ip4, *s_ip6, *s_tc, *s_proxy, *s_port, *s_dcb = NULL, *s_user; + NMSetting *s_sriov, *s_match; const char *ifcfg_name = NULL; gboolean has_ip4_defroute = FALSE; gboolean has_complex_routes_v4; @@ -5348,14 +5539,14 @@ connection_from_file_full (const char *filename, return NULL; } - parsed = svOpenFile (filename, error); - if (!parsed) + main_ifcfg = svOpenFile (filename, error); + if (!main_ifcfg) return NULL; network_ifcfg = svOpenFile (network_file, NULL); - if (!svGetValueBoolean (parsed, "NM_CONTROLLED", TRUE)) { - connection = create_unhandled_connection (filename, parsed, "unmanaged", out_unhandled); + if (!svGetValueBoolean (main_ifcfg, "NM_CONTROLLED", TRUE)) { + connection = create_unhandled_connection (filename, main_ifcfg, "unmanaged", out_unhandled); if (!connection) { NM_SET_OUT (out_ignore_error, TRUE); g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, @@ -5365,7 +5556,7 @@ connection_from_file_full (const char *filename, } /* iBFT is handled by the iBFT settings plugin */ - bootproto = svGetValueStr_cp (parsed, "BOOTPROTO"); + bootproto = svGetValueStr_cp (main_ifcfg, "BOOTPROTO"); if (bootproto && !g_ascii_strcasecmp (bootproto, "ibft")) { NM_SET_OUT (out_ignore_error, TRUE); g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, @@ -5375,19 +5566,19 @@ connection_from_file_full (const char *filename, } g_free (bootproto); - devtype = svGetValueStr_cp (parsed, "DEVICETYPE"); + devtype = svGetValueStr_cp (main_ifcfg, "DEVICETYPE"); if (devtype) { if (!strcasecmp (devtype, TYPE_TEAM)) type = g_strdup (TYPE_TEAM); else if (!strcasecmp (devtype, TYPE_TEAM_PORT)) { gs_free char *device = NULL; - type = svGetValueStr_cp (parsed, "TYPE"); - device = svGetValueStr_cp (parsed, "DEVICE"); + type = svGetValueStr_cp (main_ifcfg, "TYPE"); + device = svGetValueStr_cp (main_ifcfg, "DEVICE"); if (type) { /* nothing to do */ - } else if (device && is_vlan_device (device, parsed)) + } else if (device && is_vlan_device (device, main_ifcfg)) type = g_strdup (TYPE_VLAN); else type = g_strdup (TYPE_ETHERNET); @@ -5400,26 +5591,26 @@ connection_from_file_full (const char *filename, /* Team and TeamPort types are also accepted by the mere * presence of TEAM_CONFIG/TEAM_MASTER. They don't require * DEVICETYPE. */ - t = svGetValueStr_cp (parsed, "TEAM_CONFIG"); + t = svGetValueStr_cp (main_ifcfg, "TEAM_CONFIG"); if (t) type = g_strdup (TYPE_TEAM); } if (!type) - type = svGetValueStr_cp (parsed, "TYPE"); + type = svGetValueStr_cp (main_ifcfg, "TYPE"); if (!type) { gs_free char *tmp = NULL; char *device; - if ((tmp = svGetValueStr_cp (parsed, "IPV6TUNNELIPV4"))) { + if ((tmp = svGetValueStr_cp (main_ifcfg, "IPV6TUNNELIPV4"))) { NM_SET_OUT (out_ignore_error, TRUE); g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Ignoring unsupported connection due to IPV6TUNNELIPV4"); return NULL; } - device = svGetValueStr_cp (parsed, "DEVICE"); + device = svGetValueStr_cp (main_ifcfg, "DEVICE"); if (!device) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "File '%s' had neither TYPE nor DEVICE keys.", filename); @@ -5435,11 +5626,11 @@ connection_from_file_full (const char *filename, } if (!test_type) { - if (is_bond_device (device, parsed)) + if (is_bond_device (device, main_ifcfg)) type = g_strdup (TYPE_BOND); - else if (is_vlan_device (device, parsed)) + else if (is_vlan_device (device, main_ifcfg)) type = g_strdup (TYPE_VLAN); - else if (is_wifi_device (device, parsed)) + else if (is_wifi_device (device, main_ifcfg)) type = g_strdup (TYPE_WIRELESS); else { gs_free char *p_path = NULL; @@ -5505,14 +5696,14 @@ connection_from_file_full (const char *filename, if (nm_streq0 (type, TYPE_ETHERNET)) { gs_free char *bond_options = NULL; - if (svGetValueStr (parsed, "BONDING_OPTS", &bond_options)) { + if (svGetValueStr (main_ifcfg, "BONDING_OPTS", &bond_options)) { /* initscripts consider these as bond masters */ g_free (type); type = g_strdup (TYPE_BOND); } } - if (svGetValueBoolean (parsed, "BONDING_MASTER", FALSE) && + if (svGetValueBoolean (main_ifcfg, "BONDING_MASTER", FALSE) && strcasecmp (type, TYPE_BOND)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "BONDING_MASTER=yes key only allowed in TYPE=bond connections"); @@ -5521,21 +5712,21 @@ connection_from_file_full (const char *filename, /* Construct the connection */ if (!strcasecmp (type, TYPE_ETHERNET)) - connection = wired_connection_from_ifcfg (filename, parsed, error); + connection = wired_connection_from_ifcfg (filename, main_ifcfg, error); else if (!strcasecmp (type, TYPE_WIRELESS)) - connection = wireless_connection_from_ifcfg (filename, parsed, error); + connection = wireless_connection_from_ifcfg (filename, main_ifcfg, error); else if (!strcasecmp (type, TYPE_INFINIBAND)) - connection = infiniband_connection_from_ifcfg (filename, parsed, error); + connection = infiniband_connection_from_ifcfg (filename, main_ifcfg, error); else if (!strcasecmp (type, TYPE_BOND)) - connection = bond_connection_from_ifcfg (filename, parsed, error); + connection = bond_connection_from_ifcfg (filename, main_ifcfg, error); else if (!strcasecmp (type, TYPE_TEAM)) - connection = team_connection_from_ifcfg (filename, parsed, error); + connection = team_connection_from_ifcfg (filename, main_ifcfg, error); else if (!strcasecmp (type, TYPE_VLAN)) - connection = vlan_connection_from_ifcfg (filename, parsed, error); + connection = vlan_connection_from_ifcfg (filename, main_ifcfg, error); else if (!strcasecmp (type, TYPE_BRIDGE)) - connection = bridge_connection_from_ifcfg (filename, parsed, error); + connection = bridge_connection_from_ifcfg (filename, main_ifcfg, error); else { - connection = create_unhandled_connection (filename, parsed, "unrecognized", out_unhandled); + connection = create_unhandled_connection (filename, main_ifcfg, "unrecognized", out_unhandled); if (!connection) { PARSE_WARNING ("connection type was unrecognized but device was not uniquely identified; device may be managed"); g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, @@ -5547,6 +5738,8 @@ connection_from_file_full (const char *filename, if (!connection) return NULL; + parse_ethtool_options (main_ifcfg, connection); + has_complex_routes_v4 = utils_has_complex_routes (filename, AF_INET); has_complex_routes_v6 = utils_has_complex_routes (filename, AF_INET6); @@ -5559,7 +5752,7 @@ connection_from_file_full (const char *filename, PARSE_WARNING ("'rule-' and 'rule6-' files are present; you will need to use a dispatcher script to apply these routes"); } - s_ip6 = make_ip6_setting (parsed, + s_ip6 = make_ip6_setting (main_ifcfg, network_ifcfg, !has_complex_routes_v4 && !has_complex_routes_v6, error); @@ -5568,7 +5761,7 @@ connection_from_file_full (const char *filename, else nm_connection_add_setting (connection, s_ip6); - s_ip4 = make_ip4_setting (parsed, + s_ip4 = make_ip4_setting (main_ifcfg, network_ifcfg, !has_complex_routes_v4 && !has_complex_routes_v6, &has_ip4_defroute, @@ -5582,7 +5775,11 @@ connection_from_file_full (const char *filename, nm_connection_add_setting (connection, s_ip4); } - s_tc = make_tc_setting (parsed); + s_sriov = make_sriov_setting (main_ifcfg); + if (s_sriov) + nm_connection_add_setting (connection, s_sriov); + + s_tc = make_tc_setting (main_ifcfg); if (s_tc) nm_connection_add_setting (connection, s_tc); @@ -5590,27 +5787,31 @@ connection_from_file_full (const char *filename, * config fails for some reason, we read DOMAIN and put the * values into IPv6 config instead of IPv4. */ - check_dns_search_domains (parsed, s_ip4, s_ip6); + check_dns_search_domains (main_ifcfg, s_ip4, s_ip6); - s_proxy = make_proxy_setting (parsed); + s_proxy = make_proxy_setting (main_ifcfg); if (s_proxy) nm_connection_add_setting (connection, s_proxy); - s_user = make_user_setting (parsed); + s_user = make_user_setting (main_ifcfg); if (s_user) nm_connection_add_setting (connection, s_user); + s_match = make_match_setting (main_ifcfg); + if (s_match) + nm_connection_add_setting (connection, s_match); + /* Bridge port? */ - s_port = make_bridge_port_setting (parsed); + s_port = make_bridge_port_setting (main_ifcfg); if (s_port) nm_connection_add_setting (connection, s_port); /* Team port? */ - s_port = make_team_port_setting (parsed); + s_port = make_team_port_setting (main_ifcfg); if (s_port) nm_connection_add_setting (connection, s_port); - if (!make_dcb_setting (parsed, &s_dcb, error)) + if (!make_dcb_setting (main_ifcfg, &s_dcb, error)) return NULL; if (s_dcb) nm_connection_add_setting (connection, s_dcb); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index 862e640e..49096d26 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -470,3 +470,104 @@ nms_ifcfg_rh_utils_user_key_decode (const char *name, GString *str_buffer) return TRUE; } + +/*****************************************************************************/ + +const char *const _nm_ethtool_ifcfg_names[] = { +#define ETHT_NAME(eid, ename) \ +[eid - _NM_ETHTOOL_ID_FEATURE_FIRST] = ""ename"" + /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */ + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD, "esp-hw-offload"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD, "esp-tx-csum-hw-offload"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_FCOE_MTU, "fcoe-mtu"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_GRO, "gro"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_GSO, "gso"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_HIGHDMA, "highdma"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_HW_TC_OFFLOAD, "hw-tc-offload"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_L2_FWD_OFFLOAD, "l2-fwd-offload"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_LOOPBACK, "loopback"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_LRO, "lro"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_NTUPLE, "ntuple"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_RX, "rx"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_RXHASH, "rxhash"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_RXVLAN, "rxvlan"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_RX_ALL, "rx-all"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_RX_FCS, "rx-fcs"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_RX_GRO_HW, "rx-gro-hw"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD, "rx-udp_tunnel-port-offload"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_RX_VLAN_FILTER, "rx-vlan-filter"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_FILTER, "rx-vlan-stag-filter"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_HW_PARSE, "rx-vlan-stag-hw-parse"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_SG, "sg"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TLS_HW_RECORD, "tls-hw-record"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TLS_HW_TX_OFFLOAD, "tls-hw-tx-offload"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TSO, "tso"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX, "tx"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TXVLAN, "txvlan"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_FCOE_CRC, "tx-checksum-fcoe-crc"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV4, "tx-checksum-ipv4"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV6, "tx-checksum-ipv6"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IP_GENERIC, "tx-checksum-ip-generic"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_SCTP, "tx-checksum-sctp"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_ESP_SEGMENTATION, "tx-esp-segmentation"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_FCOE_SEGMENTATION, "tx-fcoe-segmentation"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_GRE_CSUM_SEGMENTATION, "tx-gre-csum-segmentation"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_GRE_SEGMENTATION, "tx-gre-segmentation"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_GSO_PARTIAL, "tx-gso-partial"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_GSO_ROBUST, "tx-gso-robust"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_IPXIP4_SEGMENTATION, "tx-ipxip4-segmentation"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_IPXIP6_SEGMENTATION, "tx-ipxip6-segmentation"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_NOCACHE_COPY, "tx-nocache-copy"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER, "tx-scatter-gather"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER_FRAGLIST, "tx-scatter-gather-fraglist"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_SCTP_SEGMENTATION, "tx-sctp-segmentation"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION, "tx-tcp6-segmentation"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_TCP_ECN_SEGMENTATION, "tx-tcp-ecn-segmentation"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_TCP_MANGLEID_SEGMENTATION, "tx-tcp-mangleid-segmentation"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_TCP_SEGMENTATION, "tx-tcp-segmentation"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_UDP_SEGMENTATION, "tx-udp-segmentation"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION, "tx-udp_tnl-csum-segmentation"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION, "tx-udp_tnl-segmentation"), + ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT, "tx-vlan-stag-hw-insert"), +}; + +const NMEthtoolData * +nms_ifcfg_rh_utils_get_ethtool_by_name (const char *name) +{ + static const struct { + NMEthtoolID ethtool_id; + const char *kernel_name; + } kernel_names[] = { + { NM_ETHTOOL_ID_FEATURE_GRO, "rx-gro" }, + { NM_ETHTOOL_ID_FEATURE_GSO, "tx-generic-segmentation" }, + { NM_ETHTOOL_ID_FEATURE_LRO, "rx-lro" }, + { NM_ETHTOOL_ID_FEATURE_NTUPLE, "rx-ntuple-filter" }, + { NM_ETHTOOL_ID_FEATURE_RX, "rx-checksum" }, + { NM_ETHTOOL_ID_FEATURE_RXHASH, "rx-hashing" }, + { NM_ETHTOOL_ID_FEATURE_RXVLAN, "rx-vlan-hw-parse" }, + { NM_ETHTOOL_ID_FEATURE_TXVLAN, "tx-vlan-hw-insert" }, + }; + guint i; + + for (i = 0; i < G_N_ELEMENTS (_nm_ethtool_ifcfg_names); i++) { + if (nm_streq (name, _nm_ethtool_ifcfg_names[i])) + return nm_ethtool_data[i]; + } + + /* Option not found. Note that ethtool utility has built-in features and + * NetworkManager's API follows the naming of these built-in features, whenever + * they exist. + * For example, NM's "ethtool.feature-ntuple" corresponds to ethtool utility's "ntuple" + * feature. However the underlying kernel feature is called "rx-ntuple-filter" (as reported + * for ETH_SS_FEATURES). + * + * With ethtool utility, whose command line we attempt to parse here, the user can also + * specify the name of the underlying kernel feature directly. So, check whether that is + * the case and if yes, map them to the corresponding NetworkManager's features. */ + for (i = 0; i < G_N_ELEMENTS (kernel_names); i++) { + if (nm_streq (name, kernel_names[i].kernel_name)) + return nm_ethtool_data[kernel_names[i].ethtool_id]; + } + + return NULL; +} diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index 3756af7c..84c22094 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -22,14 +22,15 @@ #define _UTILS_H_ #include "nm-connection.h" +#include "nm-ethtool-utils.h" #include "shvar.h" #define NM_IFCFG_CONNECTION_LOG_PATH(path) ((path) ?: "in-memory") #define NM_IFCFG_CONNECTION_LOG_FMT "%s (%s,\"%s\")" -#define NM_IFCFG_CONNECTION_LOG_ARG(con) NM_IFCFG_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_connection_get_uuid ((NMConnection *) (con)), nm_connection_get_id ((NMConnection *) (con)) +#define NM_IFCFG_CONNECTION_LOG_ARG(con) NM_IFCFG_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_settings_connection_get_uuid ((NMSettingsConnection *) (con)), nm_settings_connection_get_id ((NMSettingsConnection *) (con)) #define NM_IFCFG_CONNECTION_LOG_FMTD "%s (%s,\"%s\",%p)" -#define NM_IFCFG_CONNECTION_LOG_ARGD(con) NM_IFCFG_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_connection_get_uuid ((NMConnection *) (con)), nm_connection_get_id ((NMConnection *) (con)), (con) +#define NM_IFCFG_CONNECTION_LOG_ARGD(con) NM_IFCFG_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_settings_connection_get_uuid ((NMSettingsConnection *) (con)), nm_settings_connection_get_id ((NMSettingsConnection *) (con)), (con) char *utils_cert_path (const char *parent, const char *suffix, const char *extension); @@ -80,4 +81,20 @@ _nms_ifcfg_rh_utils_numbered_tag (char *buf, gsize buf_len, const char *tag_name _nms_ifcfg_rh_utils_numbered_tag (buf, sizeof (buf), ""tag_name"", (which)); \ }) +/*****************************************************************************/ + +extern const char *const _nm_ethtool_ifcfg_names[_NM_ETHTOOL_ID_FEATURE_NUM]; + +static inline const char * +nms_ifcfg_rh_utils_get_ethtool_name (NMEthtoolID ethtool_id) +{ + nm_assert (ethtool_id >= _NM_ETHTOOL_ID_FEATURE_FIRST && ethtool_id <= _NM_ETHTOOL_ID_FEATURE_LAST); + nm_assert ((ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST) < G_N_ELEMENTS (_nm_ethtool_ifcfg_names)); + nm_assert (_nm_ethtool_ifcfg_names[ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST]); + + return _nm_ethtool_ifcfg_names[ethtool_id - _NM_ETHTOOL_ID_FEATURE_FIRST]; +} + +const NMEthtoolData *nms_ifcfg_rh_utils_get_ethtool_by_name (const char *name); + #endif /* _UTILS_H_ */ diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index fdb2e10a..b70690cc 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -33,10 +33,12 @@ #include <stdio.h> #include "nm-utils/nm-enum-utils.h" +#include "nm-utils/nm-io-utils.h" #include "nm-manager.h" #include "nm-setting-connection.h" #include "nm-setting-wired.h" #include "nm-setting-wireless.h" +#include "nm-setting-ethtool.h" #include "nm-setting-8021x.h" #include "nm-setting-proxy.h" #include "nm-setting-ip4-config.h" @@ -50,6 +52,7 @@ #include "nm-core-internal.h" #include "NetworkManagerUtils.h" #include "nm-meta-setting.h" +#include "nm-ethtool-utils.h" #include "nms-ifcfg-rh-common.h" #include "nms-ifcfg-rh-reader.h" @@ -809,7 +812,7 @@ write_wireless_setting (NMConnection *connection, const char *device_mac, *cloned_mac; guint32 mtu, chan, i; gboolean adhoc = FALSE, hex_ssid = FALSE; - const char * const *macaddr_blacklist; + const char *const*macaddr_blacklist; s_wireless = nm_connection_get_setting_wireless (connection); if (!s_wireless) { @@ -1041,16 +1044,9 @@ static gboolean write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) { NMSettingWired *s_wired; - const char *device_mac, *cloned_mac; - char *tmp; - const char *nettype, *portname, *ctcprot, *s390_key, *s390_val, *duplex; - guint32 mtu, num_opts, speed, i; - const char *const *s390_subchannels; - GString *str = NULL; - const char * const *macaddr_blacklist; - gboolean auto_negotiate; - NMSettingWiredWakeOnLan wol; - const char *wol_password; + const char *const*s390_subchannels; + guint32 mtu, num_opts, i; + const char *const*macaddr_blacklist; s_wired = nm_connection_get_setting_wired (connection); if (!s_wired) { @@ -1059,144 +1055,211 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) return FALSE; } - device_mac = nm_setting_wired_get_mac_address (s_wired); - svSetValueStr (ifcfg, "HWADDR", device_mac); + svSetValueStr (ifcfg, "HWADDR", + nm_setting_wired_get_mac_address (s_wired)); - cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired); - svSetValueStr (ifcfg, "MACADDR", cloned_mac); + svSetValueStr (ifcfg, "MACADDR", + nm_setting_wired_get_cloned_mac_address (s_wired)); svSetValueStr (ifcfg, "GENERATE_MAC_ADDRESS_MASK", nm_setting_wired_get_generate_mac_address_mask (s_wired)); - svUnsetValue (ifcfg, "HWADDR_BLACKLIST"); macaddr_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired); if (macaddr_blacklist[0]) { - char *blacklist_str; + gs_free char *blacklist_str = NULL; blacklist_str = g_strjoinv (" ", (char **) macaddr_blacklist); svSetValueStr (ifcfg, "HWADDR_BLACKLIST", blacklist_str); - g_free (blacklist_str); - } + } else + svUnsetValue (ifcfg, "HWADDR_BLACKLIST"); mtu = nm_setting_wired_get_mtu (s_wired); svSetValueInt64_cond (ifcfg, "MTU", mtu != 0, mtu); - svUnsetValue (ifcfg, "SUBCHANNELS"); s390_subchannels = nm_setting_wired_get_s390_subchannels (s_wired); - if (s390_subchannels) { - int len = g_strv_length ((char **)s390_subchannels); - tmp = NULL; + { + gs_free char *tmp = NULL; + gsize len = NM_PTRARRAY_LEN (s390_subchannels); + if (len == 2) { - tmp = g_strdup_printf ("%s,%s", s390_subchannels[0], s390_subchannels[1]); + tmp = g_strdup_printf ("%s,%s", + s390_subchannels[0], + s390_subchannels[1]); } else if (len == 3) { - tmp = g_strdup_printf ("%s,%s,%s", s390_subchannels[0], s390_subchannels[1], + tmp = g_strdup_printf ("%s,%s,%s", + s390_subchannels[0], + s390_subchannels[1], s390_subchannels[2]); } + svSetValueStr (ifcfg, "SUBCHANNELS", tmp); - g_free (tmp); } - svUnsetValue (ifcfg, "NETTYPE"); - nettype = nm_setting_wired_get_s390_nettype (s_wired); - if (nettype) - svSetValueStr (ifcfg, "NETTYPE", nettype); + svSetValueStr (ifcfg, "NETTYPE", + nm_setting_wired_get_s390_nettype (s_wired)); - svUnsetValue (ifcfg, "PORTNAME"); - portname = nm_setting_wired_get_s390_option_by_key (s_wired, "portname"); - if (portname) - svSetValueStr (ifcfg, "PORTNAME", portname); + svSetValueStr (ifcfg, "PORTNAME", + nm_setting_wired_get_s390_option_by_key (s_wired, "portname")); - svUnsetValue (ifcfg, "CTCPROT"); - ctcprot = nm_setting_wired_get_s390_option_by_key (s_wired, "ctcprot"); - if (ctcprot) - svSetValueStr (ifcfg, "CTCPROT", ctcprot); + svSetValueStr (ifcfg, "CTCPROT", + nm_setting_wired_get_s390_option_by_key (s_wired, "ctcprot")); svUnsetValue (ifcfg, "OPTIONS"); num_opts = nm_setting_wired_get_num_s390_options (s_wired); if (s390_subchannels && num_opts) { - str = g_string_sized_new (30); + nm_auto_free_gstring GString *tmp = NULL; + for (i = 0; i < num_opts; i++) { + const char *s390_key, *s390_val; + nm_setting_wired_get_s390_option (s_wired, i, &s390_key, &s390_val); /* portname is handled separately */ if (!strcmp (s390_key, "portname") || !strcmp (s390_key, "ctcprot")) continue; - if (str->len) - g_string_append_c (str, ' '); - g_string_append_printf (str, "%s=%s", s390_key, s390_val); + if (!tmp) + tmp = g_string_sized_new (30); + else + g_string_append_c (tmp, ' '); + g_string_append_printf (tmp, "%s=%s", s390_key, s390_val); } - if (str->len) - svSetValueStr (ifcfg, "OPTIONS", str->str); - g_string_free (str, TRUE); + if (tmp) + svSetValueStr (ifcfg, "OPTIONS", tmp->str); } - /* Stuff ETHTOOL_OPT with required options */ - str = NULL; - auto_negotiate = nm_setting_wired_get_auto_negotiate (s_wired); - speed = nm_setting_wired_get_speed (s_wired); - duplex = nm_setting_wired_get_duplex (s_wired); + svSetValueStr (ifcfg, "TYPE", TYPE_ETHERNET); - /* autoneg off + speed 0 + duplex NULL, means we want NM - * to skip link configuration which is default. So write - * down link config only if we have auto-negotiate true or - * a valid value for one among speed and duplex. - */ - if (auto_negotiate) { - str = g_string_sized_new (64); - g_string_printf (str, "autoneg on"); - } else if (speed || duplex) { - str = g_string_sized_new (64); - g_string_printf (str, "autoneg off"); + return TRUE; +} + +static gboolean +write_ethtool_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) +{ + NMSettingWired *s_wired; + NMSettingEthtool *s_ethtool; + const char *duplex; + guint32 speed; + GString *str = NULL; + gboolean auto_negotiate; + NMSettingWiredWakeOnLan wol; + const char *wol_password; + + s_wired = nm_connection_get_setting_wired (connection); + s_ethtool = NM_SETTING_ETHTOOL (nm_connection_get_setting (connection, NM_TYPE_SETTING_ETHTOOL)); + + if (!s_wired && !s_ethtool) { + svUnsetValue (ifcfg, "ETHTOOL_WAKE_ON_LAN"); + svUnsetValue (ifcfg, "ETHTOOL_OPTS"); + return TRUE; } - if (speed) - g_string_append_printf (str, " speed %u", speed); - if (duplex) - g_string_append_printf (str, " duplex %s", duplex); - wol = nm_setting_wired_get_wake_on_lan (s_wired); - wol_password = nm_setting_wired_get_wake_on_lan_password (s_wired); + if (s_wired) { + auto_negotiate = nm_setting_wired_get_auto_negotiate (s_wired); + speed = nm_setting_wired_get_speed (s_wired); + duplex = nm_setting_wired_get_duplex (s_wired); + + /* autoneg off + speed 0 + duplex NULL, means we want NM + * to skip link configuration which is default. So write + * down link config only if we have auto-negotiate true or + * a valid value for one among speed and duplex. + */ + if (auto_negotiate) { + str = g_string_sized_new (64); + g_string_printf (str, "autoneg on"); + } else if (speed || duplex) { + str = g_string_sized_new (64); + g_string_printf (str, "autoneg off"); + } + if (speed) + g_string_append_printf (str, " speed %u", speed); + if (duplex) + g_string_append_printf (str, " duplex %s", duplex); + + wol = nm_setting_wired_get_wake_on_lan (s_wired); + wol_password = nm_setting_wired_get_wake_on_lan_password (s_wired); + + svSetValue (ifcfg, "ETHTOOL_WAKE_ON_LAN", + wol == NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE + ? "ignore" + : NULL); + if (!NM_IN_SET (wol, NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE, + NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT)) { + if (!str) + str = g_string_sized_new (30); + else + g_string_append (str, " "); + + g_string_append (str, "wol "); + + if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_PHY)) + g_string_append (str, "p"); + if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST)) + g_string_append (str, "u"); + if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST)) + g_string_append (str, "m"); + if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST)) + g_string_append (str, "b"); + if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_ARP)) + g_string_append (str, "a"); + if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) + g_string_append (str, "g"); + + if (!NM_FLAGS_ANY (wol, NM_SETTING_WIRED_WAKE_ON_LAN_ALL)) + g_string_append (str, "d"); + + if (wol_password && NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) + g_string_append_printf (str, "s sopass %s", wol_password); + } + } else + svUnsetValue (ifcfg, "ETHTOOL_WAKE_ON_LAN"); + + if (s_ethtool) { + NMEthtoolID ethtool_id; + NMSettingConnection *s_con; + const char *iface = NULL; + + s_con = nm_connection_get_setting_connection (connection); + if (s_con) { + iface = nm_setting_connection_get_interface_name (s_con); + if ( iface + && ( !iface[0] + || !NM_STRCHAR_ALL (iface, ch, (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') + || (ch >= '0' && ch <= '9') + || NM_IN_SET (ch, '_')))) + iface = NULL; + } - if (wol == NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE) - svSetValue (ifcfg, "ETHTOOL_WAKE_ON_LAN", "ignore"); - else if (wol == NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) { - if (!str) - svUnsetValue (ifcfg, "ETHTOOL_OPTS"); - } else { if (!str) str = g_string_sized_new (30); else - g_string_append (str, " "); + g_string_append (str, " ; "); + g_string_append (str, "-K "); + g_string_append (str, iface ?: "net0"); - g_string_append (str, "wol "); + for (ethtool_id = _NM_ETHTOOL_ID_FEATURE_FIRST; ethtool_id <= _NM_ETHTOOL_ID_FEATURE_LAST; ethtool_id++) { + const NMEthtoolData *ed = nm_ethtool_data[ethtool_id]; + NMTernary val; - if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_PHY)) - g_string_append (str, "p"); - if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST)) - g_string_append (str, "u"); - if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST)) - g_string_append (str, "m"); - if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST)) - g_string_append (str, "b"); - if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_ARP)) - g_string_append (str, "a"); - if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) - g_string_append (str, "g"); + nm_assert (nms_ifcfg_rh_utils_get_ethtool_name (ethtool_id)); - if (!NM_FLAGS_ANY (wol, NM_SETTING_WIRED_WAKE_ON_LAN_ALL)) - g_string_append (str, "d"); + val = nm_setting_ethtool_get_feature (s_ethtool, ed->optname); + if (val == NM_TERNARY_DEFAULT) + continue; - if (wol_password && NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) - g_string_append_printf (str, "s sopass %s", wol_password); + g_string_append_c (str, ' '); + g_string_append (str, nms_ifcfg_rh_utils_get_ethtool_name (ethtool_id)); + g_string_append (str, val == NM_TERNARY_TRUE ? " on" : " off"); + } } + if (str) { svSetValueStr (ifcfg, "ETHTOOL_OPTS", str->str); g_string_free (str, TRUE); - } - /* End ETHTOOL_OPT stuffing */ - - svSetValueStr (ifcfg, "TYPE", TYPE_ETHERNET); + } else + svUnsetValue (ifcfg, "ETHTOOL_OPTS"); return TRUE; } @@ -1555,7 +1618,7 @@ static void write_dcb_app (shvarFile *ifcfg, const char *tag, NMSettingDcbFlags flags, - gint priority) + int priority) { char prop[NM_STRLEN ("DCB_xxxxxxxxxxxxxxxxxxxxxxx_yyyyyyyyyyyyyyyyyyyy")]; @@ -1725,8 +1788,9 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) guint32 n, i; GString *str; const char *master, *master_iface = NULL, *type; - gint vint; + int vint; NMSettingConnectionMdns mdns; + NMSettingConnectionLlmnr llmnr; guint32 vuint32; const char *tmp; @@ -1746,6 +1810,11 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) vint != -1, vint); + vint = nm_setting_connection_get_multi_connect (s_con); + svSetValueInt64_cond (ifcfg, "MULTI_CONNECT", + vint != NM_CONNECTION_MULTI_CONNECT_DEFAULT, + vint); + /* Only save the value for master connections */ type = nm_setting_connection_get_connection_type (s_con); if (_nm_connection_type_is_master (type)) { @@ -1892,6 +1961,13 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) mdns); } else svUnsetValue (ifcfg, "MDNS"); + + llmnr = nm_setting_connection_get_llmnr (s_con); + if (llmnr != NM_SETTING_CONNECTION_LLMNR_DEFAULT) { + svSetValueEnum (ifcfg, "LLMNR", nm_setting_connection_llmnr_get_type (), + llmnr); + } else + svUnsetValue (ifcfg, "LLMNR"); } static char * @@ -2135,6 +2211,45 @@ write_user_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) return TRUE; } +static void +write_sriov_setting (NMConnection *connection, shvarFile *ifcfg) +{ + NMSettingSriov *s_sriov; + guint i, num = 0; + NMTernary b; + NMSriovVF *vf; + char key[32]; + char *str; + + svUnsetAll (ifcfg, SV_KEY_TYPE_SRIOV_VF); + + s_sriov = NM_SETTING_SRIOV (nm_connection_get_setting (connection, NM_TYPE_SETTING_SRIOV)); + if (s_sriov) + num = nm_setting_sriov_get_total_vfs (s_sriov); + if (num == 0) { + svUnsetValue (ifcfg, "SRIOV_TOTAL_VFS"); + svUnsetValue (ifcfg, "SRIOV_AUTOPROBE_DRIVERS"); + return; + } + + svSetValueInt64 (ifcfg, "SRIOV_TOTAL_VFS", num); + + b = nm_setting_sriov_get_autoprobe_drivers (s_sriov); + if (b != NM_TERNARY_DEFAULT) + svSetValueInt64 (ifcfg, "SRIOV_AUTOPROBE_DRIVERS", b); + else + svUnsetValue (ifcfg, "SRIOV_AUTOPROBE_DRIVERS"); + + num = nm_setting_sriov_get_num_vfs (s_sriov); + for (i = 0; i < num; i++) { + vf = nm_setting_sriov_get_vf (s_sriov, i); + nm_sprintf_buf (key, "SRIOV_VF%u", nm_sriov_vf_get_index (vf)); + str = nm_utils_sriov_vf_to_str (vf, TRUE, NULL); + svSetValueStr (ifcfg, key, str); + g_free (str); + } +} + static gboolean write_tc_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) { @@ -2179,6 +2294,38 @@ write_tc_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) return TRUE; } +static gboolean +write_match_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) +{ + NMSettingMatch *s_match; + nm_auto_free_gstring GString *str = NULL; + guint i, num; + + svUnsetValue (ifcfg, "MATCH_INTERFACE_NAME"); + + s_match = (NMSettingMatch *) nm_connection_get_setting (connection, NM_TYPE_SETTING_MATCH); + if (!s_match) + return TRUE; + + num = nm_setting_match_get_num_interface_names (s_match); + for (i = 0; i < num; i++) { + gs_free char *to_free = NULL; + const char *name; + + if (i == 0) + str = g_string_new (""); + else + g_string_append_c (str, ' '); + name = nm_setting_match_get_interface_name (s_match, i); + g_string_append (str, _nm_utils_escape_spaces (name, &to_free)); + } + + if (str) + svSetValueStr (ifcfg, "MATCH_INTERFACE_NAME", str->str); + + return TRUE; +} + static void write_res_options (shvarFile *ifcfg, NMSettingIPConfig *s_ip, const char *var) { @@ -2212,11 +2359,11 @@ write_ip4_setting (NMConnection *connection, const char *value; char *tmp; char tag[64]; - gint j; + int j; guint i, num, n; gint64 route_metric; NMIPRouteTableSyncMode route_table; - gint priority; + int priority; int timeout; GString *searches; const char *method = NULL; @@ -2548,7 +2695,7 @@ write_ip6_setting (NMConnection *connection, NMSettingIPConfig *s_ip4; const char *value; guint i, num, num4; - gint priority; + int priority; NMIPAddress *addr; const char *dns; gint64 route_metric; @@ -2918,9 +3065,17 @@ do_write_construct (NMConnection *connection, if (!write_proxy_setting (connection, ifcfg, error)) return FALSE; + if (!write_ethtool_setting (connection, ifcfg, error)) + return FALSE; + if (!write_user_setting (connection, ifcfg, error)) return FALSE; + if (!write_match_setting (connection, ifcfg, error)) + return FALSE; + + write_sriov_setting (connection, ifcfg); + if (!write_tc_setting (connection, ifcfg, error)) return FALSE; diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c index 9120b870..fe82fbdd 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.c +++ b/src/settings/plugins/ifcfg-rh/shvar.c @@ -39,6 +39,7 @@ #include "nm-core-internal.h" #include "nm-core-utils.h" #include "nm-utils/nm-enum-utils.h" +#include "nm-utils/nm-io-utils.h" #include "c-list/src/c-list.h" /*****************************************************************************/ @@ -90,8 +91,8 @@ struct _shvarFile { * * Returns: the parsed boolean value or @fallback. */ -gint -svParseBoolean (const char *value, gint fallback) +int +svParseBoolean (const char *value, int fallback) { if (!value) return fallback; @@ -148,8 +149,8 @@ static char * _escape_ansic (const char *source) { const char *p; - gchar *dest; - gchar *q; + char *dest; + char *q; nm_assert (source); @@ -821,6 +822,7 @@ svOpenFileInternal (const char *name, gboolean create, GError **error) if (nm_utils_fd_get_contents (closefd ? nm_steal_fd (&fd) : fd, closefd, 10 * 1024 * 1024, + NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, &arena, NULL, &local) < 0) { @@ -870,8 +872,61 @@ svCreateFile (const char *name) /*****************************************************************************/ +static gboolean +_is_all_digits (const char *str) +{ + return str[0] + && NM_STRCHAR_ALL (str, ch, g_ascii_isdigit (ch)); +} + +#define IS_NUMBERED_TAG(key, tab_name) \ + ({ \ + const char *_key = (key); \ + \ + ( (strncmp (_key, tab_name, NM_STRLEN (tab_name)) == 0) \ + && _is_all_digits (&_key[NM_STRLEN (tab_name)])); \ + }) + +static gboolean +_svKeyMatchesType (const char *key, SvKeyType match_key_type) +{ + if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ANY)) + return TRUE; + + if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ROUTE_SVFORMAT)) { + if ( IS_NUMBERED_TAG (key, "ADDRESS") + || IS_NUMBERED_TAG (key, "NETMASK") + || IS_NUMBERED_TAG (key, "GATEWAY") + || IS_NUMBERED_TAG (key, "METRIC") + || IS_NUMBERED_TAG (key, "OPTIONS")) + return TRUE; + } + if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_IP4_ADDRESS)) { + if ( IS_NUMBERED_TAG (key, "IPADDR") + || IS_NUMBERED_TAG (key, "PREFIX") + || IS_NUMBERED_TAG (key, "NETMASK") + || IS_NUMBERED_TAG (key, "GATEWAY")) + return TRUE; + } + if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_USER)) { + if (g_str_has_prefix (key, "NM_USER_")) + return TRUE; + } + if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_TC)) { + if ( IS_NUMBERED_TAG (key, "QDISC") + || IS_NUMBERED_TAG (key, "FILTER")) + return TRUE; + } + if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_SRIOV_VF)) { + if (IS_NUMBERED_TAG (key, "SRIOV_VF")) + return TRUE; + } + + return FALSE; +} + GHashTable * -svGetKeys (shvarFile *s) +svGetKeys (shvarFile *s, SvKeyType match_key_type) { GHashTable *keys = NULL; CList *current; @@ -881,7 +936,9 @@ svGetKeys (shvarFile *s) c_list_for_each (current, &s->lst_head) { line = c_list_entry (current, shvarLine, lst); - if (line->key && line->line) { + if ( line->key + && line->line + && _svKeyMatchesType (line->key, match_key_type)) { /* we don't clone the keys. The keys are only valid * until @s gets modified. */ if (!keys) @@ -1044,8 +1101,8 @@ svGetValueStr_cp (shvarFile *s, const char *key) * * Returns: the parsed boolean value or @fallback. */ -gint -svGetValueBoolean (shvarFile *s, const char *key, gint fallback) +int +svGetValueBoolean (shvarFile *s, const char *key, int fallback) { gs_free char *to_free = NULL; const char *value; @@ -1120,21 +1177,6 @@ svGetValueEnum (shvarFile *s, const char *key, /*****************************************************************************/ -static gboolean -_is_all_digits (const char *str) -{ - return str[0] - && NM_STRCHAR_ALL (str, ch, g_ascii_isdigit (ch)); -} - -#define IS_NUMBERED_TAG(key, tab_name) \ - ({ \ - const char *_key = (key); \ - \ - ( (strncmp (_key, tab_name, NM_STRLEN (tab_name)) == 0) \ - && _is_all_digits (&_key[NM_STRLEN (tab_name)])); \ - }) - gboolean svUnsetAll (shvarFile *s, SvKeyType match_key_type) { @@ -1150,38 +1192,11 @@ svUnsetAll (shvarFile *s, SvKeyType match_key_type) if (!line->key) continue; - if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ANY)) - goto do_clear; - if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ROUTE_SVFORMAT)) { - if ( IS_NUMBERED_TAG (line->key, "ADDRESS") - || IS_NUMBERED_TAG (line->key, "NETMASK") - || IS_NUMBERED_TAG (line->key, "GATEWAY") - || IS_NUMBERED_TAG (line->key, "METRIC") - || IS_NUMBERED_TAG (line->key, "OPTIONS")) - goto do_clear; - } - if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_IP4_ADDRESS)) { - if ( IS_NUMBERED_TAG (line->key, "IPADDR") - || IS_NUMBERED_TAG (line->key, "PREFIX") - || IS_NUMBERED_TAG (line->key, "NETMASK") - || IS_NUMBERED_TAG (line->key, "GATEWAY")) - goto do_clear; - } - if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_USER)) { - if (g_str_has_prefix (line->key, "NM_USER_")) - goto do_clear; - } - if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_TC)) { - if ( IS_NUMBERED_TAG (line->key, "QDISC") - || IS_NUMBERED_TAG (line->key, "FILTER")) - goto do_clear; - } - - continue; -do_clear: - if (nm_clear_g_free (&line->line)) { - ASSERT_shvarLine (line); - changed = TRUE; + if (_svKeyMatchesType (line->key, match_key_type)) { + if (nm_clear_g_free (&line->line)) { + ASSERT_shvarLine (line); + changed = TRUE; + } } } diff --git a/src/settings/plugins/ifcfg-rh/shvar.h b/src/settings/plugins/ifcfg-rh/shvar.h index dbc4d950..622bb474 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.h +++ b/src/settings/plugins/ifcfg-rh/shvar.h @@ -33,6 +33,15 @@ typedef struct _shvarFile shvarFile; +typedef enum { + SV_KEY_TYPE_ANY = (1LL << 0), + SV_KEY_TYPE_ROUTE_SVFORMAT = (1LL << 1), + SV_KEY_TYPE_IP4_ADDRESS = (1LL << 2), + SV_KEY_TYPE_TC = (1LL << 3), + SV_KEY_TYPE_USER = (1LL << 4), + SV_KEY_TYPE_SRIOV_VF = (1LL << 5), +} SvKeyType; + const char *svFileGetName (const shvarFile *s); void _nmtst_svFileSetName (shvarFile *s, const char *fileName); @@ -56,15 +65,15 @@ char *svGetValue_cp (shvarFile *s, const char *key); const char *svGetValueStr (shvarFile *s, const char *key, char **to_free); char *svGetValueStr_cp (shvarFile *s, const char *key); -gint svParseBoolean (const char *value, gint def); +int svParseBoolean (const char *value, int def); -GHashTable *svGetKeys (shvarFile *s); +GHashTable *svGetKeys (shvarFile *s, SvKeyType match_key_type); /* return TRUE if <key> resolves to any truth value (e.g. "yes", "y", "true") * return FALSE if <key> resolves to any non-truth value (e.g. "no", "n", "false") * return <def> otherwise */ -gint svGetValueBoolean (shvarFile *s, const char *key, gint def); +int svGetValueBoolean (shvarFile *s, const char *key, int def); gint64 svGetValueInt64 (shvarFile *s, const char *key, guint base, gint64 min, gint64 max, gint64 fallback); @@ -85,15 +94,6 @@ gboolean svSetValueInt64_cond (shvarFile *s, const char *key, gboolean do_set, g gboolean svSetValueEnum (shvarFile *s, const char *key, GType gtype, int value); gboolean svUnsetValue (shvarFile *s, const char *key); - -typedef enum { - SV_KEY_TYPE_ANY = (1LL << 0), - SV_KEY_TYPE_ROUTE_SVFORMAT = (1LL << 1), - SV_KEY_TYPE_IP4_ADDRESS = (1LL << 2), - SV_KEY_TYPE_TC = (1LL << 3), - SV_KEY_TYPE_USER = (1LL << 4), -} SvKeyType; - gboolean svUnsetAll (shvarFile *s, SvKeyType match_key_type); /* Write the current contents iff modified. Returns FALSE on error diff --git a/src/settings/plugins/ifcfg-rh/tests/meson.build b/src/settings/plugins/ifcfg-rh/tests/meson.build index 3d72d892..0593f12d 100644 --- a/src/settings/plugins/ifcfg-rh/tests/meson.build +++ b/src/settings/plugins/ifcfg-rh/tests/meson.build @@ -6,7 +6,6 @@ exe = executable( test_unit, test_unit + '.c', dependencies: test_nm_dep, - c_args: nm_build_cflags, link_with: libnms_ifcfg_rh_core ) diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected index 8f421cfb..214f5da5 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Auto-Negotiate.cexpected @@ -1,7 +1,7 @@ -ETHTOOL_OPTS="autoneg off speed 10 duplex half" TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no +ETHTOOL_OPTS="autoneg off speed 10 duplex half" BOOTPROTO=dhcp DEFROUTE=yes IPV4_FAILURE_FATAL=no diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected index 398a3017..de66dcdd 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Wake-on-LAN.cexpected @@ -1,7 +1,7 @@ -ETHTOOL_OPTS="wol umgs sopass 00:00:00:11:22:33" TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no +ETHTOOL_OPTS="wol umgs sopass 00:00:00:11:22:33" BOOTPROTO=dhcp DEFROUTE=yes IPV4_FAILURE_FATAL=no diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_match.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_match.cexpected new file mode 100644 index 00000000..f0cd36cb --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_match.cexpected @@ -0,0 +1,11 @@ +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +MATCH_INTERFACE_NAME="ens* eth\\ 1? !veth*" +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="Test Write Wired with Match setting" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-sriov b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-sriov new file mode 100644 index 00000000..142f56e4 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-sriov @@ -0,0 +1,19 @@ +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:55 +BOOTPROTO=none +ONBOOT=yes +DNS1=4.2.2.1 +DNS2=4.2.2.2 +IPADDR=192.168.1.5 +PREFIX=24 +NETMASK=255.255.255.0 +GATEWAY=192.168.1.1 +IPV6INIT=no +NAME=ethernet-sriov +UUID=acc703b8-e751-44ce-b456-1550bdf2057e +SRIOV_TOTAL_VFS=16 +SRIOV_AUTOPROBE_DRIVERS=0 +SRIOV_VF15="max-tx-rate=200 mac=01:23:45:67:89:ab vlans=2" +SRIOV_VF12="trust=false min-tx-rate=100 vlans=1.200.ad" +SRIOV_VF3="mac=55:44:33:22:11:00 spoof-check=true" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-sriov-write.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-sriov-write.cexpected new file mode 100644 index 00000000..c882c479 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-sriov-write.cexpected @@ -0,0 +1,18 @@ +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +SRIOV_TOTAL_VFS=64 +SRIOV_AUTOPROBE_DRIVERS=1 +SRIOV_VF2="mac=55:55:55:55:55:55 vlans=3.10.ad;10" +SRIOV_VF19=spoof-check=true +BOOTPROTO=none +IPADDR=1.1.1.3 +PREFIX=24 +GATEWAY=1.1.1.1 +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="Test Write SR-IOV config" +UUID=${UUID} +DEVICE=eth0 +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_write_wired_auto_negotiate_on.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_write_wired_auto_negotiate_on.cexpected new file mode 100644 index 00000000..42608576 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_write_wired_auto_negotiate_on.cexpected @@ -0,0 +1,15 @@ +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +ETHTOOL_OPTS="autoneg on ; -K net0 rxvlan off tx on" +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME="Test Write Wired Auto-Negotiate" +UUID=${UUID} +ONBOOT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 1331391d..472bb8a6 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -43,12 +43,14 @@ #include "nm-setting-pppoe.h" #include "nm-setting-ppp.h" #include "nm-setting-vpn.h" +#include "nm-setting-ethtool.h" #include "nm-setting-gsm.h" #include "nm-setting-cdma.h" #include "nm-setting-serial.h" #include "nm-setting-vlan.h" #include "nm-setting-dcb.h" #include "nm-core-internal.h" +#include "nm-ethtool-utils.h" #include "NetworkManagerUtils.h" @@ -185,7 +187,8 @@ _assert_expected_content (NMConnection *connection, const char *filename, const if ( len_expectd != len_written || memcmp (content_expectd, content_written, len_expectd) != 0) { - if (g_getenv ("NMTST_IFCFG_RH_UPDATE_EXPECTED")) { + if ( g_getenv ("NMTST_IFCFG_RH_UPDATE_EXPECTED") + || nm_streq0 (g_getenv ("NM_TEST_REGENERATE"), "1")) { if (uuid) { gs_free char *search = g_strdup_printf ("UUID=%s\n", uuid); const char *s; @@ -1898,10 +1901,8 @@ test_read_write_802_1X_subj_matches (void) gs_unref_object NMConnection *reread = NULL; NMSetting8021x *s_8021x; - NMTST_EXPECT_NM_WARN ("*missing IEEE_8021X_CA_CERT*peap*"); connection = _connection_from_file (TEST_IFCFG_DIR"/ifcfg-test-wired-802-1X-subj-matches", NULL, TYPE_ETHERNET, NULL); - g_test_assert_expected_messages (); /* ===== 802.1x SETTING ===== */ s_8021x = nm_connection_get_setting_802_1x (connection); @@ -1919,16 +1920,12 @@ test_read_write_802_1X_subj_matches (void) g_assert_cmpstr (nm_setting_802_1x_get_phase2_altsubject_match (s_8021x, 0), ==, "x.yourdomain.tld"); g_assert_cmpstr (nm_setting_802_1x_get_phase2_altsubject_match (s_8021x, 1), ==, "y.yourdomain.tld"); - NMTST_EXPECT_NM_WARN ("*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!"); _writer_new_connec_exp (connection, TEST_SCRATCH_DIR, TEST_IFCFG_DIR"/ifcfg-System_test-wired-802-1X-subj-matches.cexpected", &testfile); - g_test_assert_expected_messages (); - NMTST_EXPECT_NM_WARN ("*missing IEEE_8021X_CA_CERT for EAP method 'peap'; this is insecure!"); reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); - g_test_assert_expected_messages (); nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); @@ -3117,8 +3114,7 @@ test_read_wifi_wpa_psk_hex (void) ssid = nm_setting_wireless_get_ssid (s_wireless); g_assert (ssid); - g_assert_cmpint (g_bytes_get_size (ssid), ==, strlen (expected_ssid)); - g_assert (memcmp (g_bytes_get_data (ssid, NULL), expected_ssid, strlen (expected_ssid)) == 0); + g_assert (nm_utils_gbytes_equal_mem (ssid, expected_ssid, strlen (expected_ssid))); /* ===== WIRELESS SECURITY SETTING ===== */ @@ -3725,6 +3721,7 @@ test_write_wired_auto_negotiate_on (void) gs_unref_object NMConnection *connection = NULL; gs_unref_object NMConnection *reread = NULL; NMSettingWired *s_wired; + NMSettingEthtool *s_ethtool; char *val; shvarFile *f; @@ -3734,8 +3731,14 @@ test_write_wired_auto_negotiate_on (void) NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL); - _writer_new_connection (connection, + s_ethtool = NM_SETTING_ETHTOOL (nm_setting_ethtool_new ()); + nm_setting_ethtool_set_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_TX, NM_TERNARY_TRUE); + nm_setting_ethtool_set_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RXVLAN, NM_TERNARY_FALSE); + nm_connection_add_setting (connection, NM_SETTING (s_ethtool)); + + _writer_new_connec_exp (connection, TEST_SCRATCH_DIR, + TEST_IFCFG_DIR"/ifcfg-test_write_wired_auto_negotiate_on.cexpected", &testfile); f = _svOpenFile (testfile); @@ -3749,7 +3752,15 @@ test_write_wired_auto_negotiate_on (void) reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); + nmtst_assert_connection_verifies_without_normalization (reread); + nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); + + s_ethtool = NM_SETTING_ETHTOOL (nm_connection_get_setting (reread, NM_TYPE_SETTING_ETHTOOL)); + g_assert (s_ethtool); + g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_TX), ==, NM_TERNARY_TRUE); + g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RXVLAN), ==, NM_TERNARY_FALSE); + g_assert_cmpint (nm_setting_ethtool_get_feature (s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_TXVLAN), ==, NM_TERNARY_DEFAULT); } static void @@ -4417,6 +4428,67 @@ test_write_wired_dhcp (void) } static void +test_write_wired_match (void) +{ + nmtst_auto_unlinkfile char *testfile = NULL; + gs_unref_object NMConnection *connection = NULL; + gs_unref_object NMConnection *reread = NULL; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingMatch *s_match; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + + connection = nm_simple_connection_new (); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, "Test Write Wired with Match setting", + NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_a (), + NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, + NULL); + + /* Wired setting */ + s_wired = (NMSettingWired *) nm_setting_wired_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + + /* IP4 setting */ + s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new (); + nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NULL); + + /* IP6 setting */ + s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new (); + nm_connection_add_setting (connection, NM_SETTING (s_ip6)); + + g_object_set (s_ip6, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NULL); + + /* Match setting */ + s_match = (NMSettingMatch *) nm_setting_match_new (); + nm_setting_match_add_interface_name (s_match, "ens*"); + nm_setting_match_add_interface_name (s_match, "eth 1?"); + nm_setting_match_add_interface_name (s_match, "!veth*"); + nm_connection_add_setting (connection, NM_SETTING (s_match)); + + nmtst_assert_connection_verifies (connection); + _writer_new_connec_exp (connection, + TEST_SCRATCH_DIR, + TEST_IFCFG_DIR"/ifcfg-Test_Write_Wired_match.cexpected", + &testfile); + reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); + nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); +} + +static void test_write_wired_dhcp_plus_ip (void) { nmtst_auto_unlinkfile char *testfile = NULL; @@ -8982,7 +9054,7 @@ test_team_reread_slave (void) "id=142\n" "ingress-priority-map=\n" "parent=enp31s0f1\n" - , "/test_team_reread_slave", NULL); + , "/test_team_reread_slave"); /* to double-check keyfile syntax, re-create the connection by hand. */ connection_2 = nmtst_create_minimal_connection ("team-slave-enp31s0f1-142", "74f435bb-ede4-415a-9d48-f580b60eba04", NM_SETTING_VLAN_SETTING_NAME, &s_con); @@ -9632,6 +9704,153 @@ test_utils_ignore (void) do_test_utils_ignored ("ignored-augtmp", "ifcfg-FooBar" AUGTMP_TAG, TRUE); } +/*****************************************************************************/ + +static void +test_sriov_read (void) +{ + gs_unref_object NMConnection *connection = NULL; + NMSettingSriov *s_sriov; + NMSriovVF *vf; + GVariant *variant; + GError *error = NULL; + char *str; + + connection = _connection_from_file (TEST_IFCFG_DIR "/ifcfg-test-sriov", + NULL, TYPE_ETHERNET,NULL); + + g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "eth0"); + + s_sriov = NM_SETTING_SRIOV (nm_connection_get_setting (connection, NM_TYPE_SETTING_SRIOV)); + g_assert (s_sriov); + + g_assert_cmpint (nm_setting_sriov_get_total_vfs (s_sriov), ==, 16); + g_assert_cmpint (nm_setting_sriov_get_num_vfs (s_sriov), ==, 3); + g_assert_cmpint (nm_setting_sriov_get_autoprobe_drivers (s_sriov), ==, NM_TERNARY_FALSE); + + /* VF 3 */ + vf = nm_setting_sriov_get_vf (s_sriov, 0); + g_assert (vf); + g_assert_cmpint (nm_sriov_vf_get_index (vf), ==, 3); + + variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_MAC); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)); + g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "55:44:33:22:11:00"); + + variant = nm_sriov_vf_get_attribute (vf, NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN)); + g_assert_cmpint (g_variant_get_boolean (variant), ==, TRUE); + + /* VF 12 */ + vf = nm_setting_sriov_get_vf (s_sriov, 1); + str = nm_utils_sriov_vf_to_str (vf, FALSE, &error); + g_assert_no_error (error); + g_assert_cmpstr (str, ==, "12 min-tx-rate=100 trust=false vlans=1.200.ad"); + g_free (str); + + /* VF 15 */ + vf = nm_setting_sriov_get_vf (s_sriov, 2); + str = nm_utils_sriov_vf_to_str (vf, FALSE, &error); + g_assert_no_error (error); + g_assert_cmpstr (str, ==, "15 mac=01:23:45:67:89:ab max-tx-rate=200 vlans=2"); + g_free (str); +} + +static void +test_sriov_write (void) +{ + nmtst_auto_unlinkfile char *testfile = NULL; + gs_unref_object NMConnection *connection = NULL; + gs_unref_object NMConnection *reread = NULL; + NMSettingConnection *s_con; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + NMSettingWired *s_wired; + NMSettingSriov *s_sriov; + NMSriovVF *vf; + gs_unref_ptrarray GPtrArray *vfs = NULL; + NMIPAddress *addr; + GError *error = NULL; + + connection = nm_simple_connection_new (); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, "Test Write SR-IOV config", + NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_a (), + NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, + NM_SETTING_CONNECTION_INTERFACE_NAME, "eth0", + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, + NULL); + + /* Wired setting */ + s_wired = (NMSettingWired *) nm_setting_wired_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + + /* IP4 setting */ + s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new (); + nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + NM_SETTING_IP_CONFIG_GATEWAY, "1.1.1.1", + NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE, + NULL); + + addr = nm_ip_address_new (AF_INET, "1.1.1.3", 24, &error); + g_assert_no_error (error); + nm_setting_ip_config_add_address (s_ip4, addr); + nm_ip_address_unref (addr); + + /* IP6 setting */ + s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new (); + nm_connection_add_setting (connection, NM_SETTING (s_ip6)); + + g_object_set (s_ip6, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NULL); + + /* SRIOV setting */ + s_sriov = (NMSettingSriov *) nm_setting_sriov_new (); + nm_connection_add_setting (connection, NM_SETTING (s_sriov)); + + vfs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_sriov_vf_unref); + + vf = nm_utils_sriov_vf_from_str ("2 mac=55:55:55:55:55:55 vlans=3.10.ad;10", &error); + nmtst_assert_success (vf, error); + g_ptr_array_add (vfs, vf); + + vf = nm_utils_sriov_vf_from_str ("19 spoof-check=true", &error); + nmtst_assert_success (vf, error); + g_ptr_array_add (vfs, vf); + + g_object_set (s_sriov, + NM_SETTING_SRIOV_TOTAL_VFS, 64, + NM_SETTING_SRIOV_VFS, vfs, + NM_SETTING_SRIOV_AUTOPROBE_DRIVERS, NM_TERNARY_TRUE, + NULL); + + nm_connection_add_setting (connection, nm_setting_proxy_new ()); + + nmtst_assert_connection_verifies_without_normalization (connection); + + _writer_new_connec_exp (connection, + TEST_SCRATCH_DIR, + TEST_IFCFG_DIR "/ifcfg-test-sriov-write.cexpected", + &testfile); + + reread = _connection_from_file (testfile, NULL, TYPE_ETHERNET, NULL); + + nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); +} + +/*****************************************************************************/ + static void test_tc_read (void) { @@ -9907,6 +10126,7 @@ int main (int argc, char **argv) g_test_add_func (TPATH "wired/write/dhcp", test_write_wired_dhcp); g_test_add_func (TPATH "wired/write-dhcp-plus-ip", test_write_wired_dhcp_plus_ip); g_test_add_func (TPATH "wired/write/dhcp-8021x-peap-mschapv2", test_write_wired_dhcp_8021x_peap_mschapv2); + g_test_add_func (TPATH "wired/write/match", test_write_wired_match); #define _add_test_write_wired_8021x_tls(testpath, scheme, flags) \ nmtst_add_test_func (testpath, test_write_wired_8021x_tls, GINT_TO_POINTER (scheme), GINT_TO_POINTER (flags)) @@ -10033,6 +10253,9 @@ int main (int argc, char **argv) g_test_add_func (TPATH "utils/path", test_utils_path); g_test_add_func (TPATH "utils/ignore", test_utils_ignore); + g_test_add_func (TPATH "sriov/read", test_sriov_read); + g_test_add_func (TPATH "sriov/write", test_sriov_write); + g_test_add_func (TPATH "tc/read", test_tc_read); g_test_add_func (TPATH "tc/write", test_tc_write); diff --git a/src/settings/plugins/ifupdown/meson.build b/src/settings/plugins/ifupdown/meson.build index fd028f4d..826c7458 100644 --- a/src/settings/plugins/ifupdown/meson.build +++ b/src/settings/plugins/ifupdown/meson.build @@ -8,13 +8,10 @@ deps = [ nm_dep ] -cflags = '-DSYSCONFDIR="@0@"'.format(nm_sysconfdir) - libnms_ifupdown_core = static_library( 'nms-ifupdown-core', sources: sources, dependencies: deps, - c_args: cflags ) sources = files( @@ -26,7 +23,6 @@ libnm_settings_plugin_ifupdown = shared_module( 'nm-settings-plugin-ifupdown', sources: sources, dependencies: deps, - c_args: cflags, link_with: libnms_ifupdown_core, link_args: ldflags_linker_script_settings, link_depends: linker_script_settings, diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-connection.c b/src/settings/plugins/ifupdown/nms-ifupdown-connection.c index c3d231fe..1b817044 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-connection.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-connection.c @@ -49,10 +49,20 @@ G_DEFINE_TYPE (NMIfupdownConnection, nm_ifupdown_connection, NM_TYPE_SETTINGS_CO /*****************************************************************************/ +#define _NMLOG_PREFIX_NAME "ifupdown" +#define _NMLOG_DOMAIN LOGD_SETTINGS +#define _NMLOG(level, ...) \ + nm_log ((level), _NMLOG_DOMAIN, NULL, NULL, \ + "%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME": " \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)) + +/*****************************************************************************/ + static gboolean supports_secrets (NMSettingsConnection *connection, const char *setting_name) { - nm_log_info (LOGD_SETTINGS, "supports_secrets() for setting_name: '%s'", setting_name); + _LOGI ("supports_secrets() for setting_name: '%s'", setting_name); return (strcmp (setting_name, NM_SETTING_WIRELESS_SECURITY_SETTING_NAME) == 0); } @@ -64,26 +74,27 @@ nm_ifupdown_connection_init (NMIfupdownConnection *connection) { } -NMIfupdownConnection* +NMIfupdownConnection * nm_ifupdown_connection_new (if_block *block) { - GObject *object; + NMIfupdownConnection *connection; GError *error = NULL; g_return_val_if_fail (block != NULL, NULL); - object = g_object_new (NM_TYPE_IFUPDOWN_CONNECTION, NULL); + connection = g_object_new (NM_TYPE_IFUPDOWN_CONNECTION, NULL); - if (!ifupdown_update_connection_from_if_block (NM_CONNECTION (object), block, &error)) { - nm_log_warn (LOGD_SETTINGS, "%s.%d - invalid connection read from /etc/network/interfaces: %s", - __FILE__, - __LINE__, - error->message); - g_object_unref (object); + /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */ + if (!ifupdown_update_connection_from_if_block (nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (connection)), + block, + &error)) { + _LOGW ("invalid connection read from /etc/network/interfaces: %s", + error->message); + g_object_unref (connection); return NULL; } - return (NMIfupdownConnection *) object; + return connection; } static void diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c index 94a65ecb..73ecc2f9 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c @@ -32,78 +32,90 @@ #include "nm-utils.h" -if_block* first; -if_block* last; +/*****************************************************************************/ -if_data* last_data; +static void _ifparser_source (if_parser *parser, const char *path, const char *en_dir, int quiet, int dir); -void add_block(const char *type, const char* name) +/*****************************************************************************/ + +#define _NMLOG_PREFIX_NAME "ifupdown" +#define _NMLOG_DOMAIN LOGD_SETTINGS +#define _NMLOG(level, ...) \ + nm_log ((level), _NMLOG_DOMAIN, NULL, NULL, \ + "%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME": " \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)) + +/*****************************************************************************/ + +static void +add_block (if_parser *parser, const char *type, const char* name) { - if_block *ret = g_slice_new0 (struct _if_block); - ret->name = g_strdup(name); - ret->type = g_strdup(type); - if (first == NULL) - first = last = ret; - else - { - last->next = ret; - last = ret; - } - last_data = NULL; + if_block *ifb; + gsize l_type, l_name; + + l_type = strlen (type) + 1; + l_name = strlen (name) + 1; + + ifb = g_malloc (sizeof (if_block) + l_type + l_name); + memcpy ((char *) ifb->name, name, l_name); + ifb->type = &ifb->name[l_name]; + memcpy ((char *) ifb->type, type, l_type); + c_list_init (&ifb->data_lst_head); + c_list_link_tail (&parser->block_lst_head, &ifb->block_lst); } -void add_data(const char *key,const char *data) +static void +add_data (if_parser *parser, const char *key, const char *data) { - if_data *ret; + if_block *last_block; + if_data *ifd; char *idx; + gsize l_key, l_data; + + last_block = c_list_last_entry (&parser->block_lst_head, if_block, block_lst); /* Check if there is a block where we can attach our data */ - if (first == NULL) + if (!last_block) return; - ret = g_slice_new0 (struct _if_data); - ret->key = g_strdup(key); + l_key = strlen (key) + 1; + l_data = strlen (data) + 1; + + ifd = g_malloc (sizeof (if_data) + l_key + l_data); + memcpy ((char *) ifd->key, key, l_key); + ifd->data = &ifd->key[l_key]; + memcpy ((char *) ifd->data, data, l_data); /* Normalize keys. Convert '_' to '-', as ifupdown accepts both variants. * When querying keys via ifparser_getkey(), use '-'. */ - while ((idx = strrchr(ret->key, '_'))) { - *idx = '-'; - } - ret->data = g_strdup(data); + idx = (char *) ifd->key; + while ((idx = strchr (idx, '_'))) + *(idx++) = '-'; - if (last->info == NULL) - { - last->info = ret; - last_data = ret; - } - else - { - last_data->next = ret; - last_data = last_data->next; - } + c_list_link_tail (&last_block->data_lst_head, &ifd->data_lst); } /* join values in src with spaces into dst; dst needs to be large enough */ -static char *join_values_with_spaces(char *dst, char **src) +static char * +join_values_with_spaces (char *dst, char **src) { if (dst != NULL) { *dst = '\0'; if (src != NULL && *src != NULL) { - strcat(dst, *src); + strcat (dst, *src); for (src++; *src != NULL; src++) { - strcat(dst, " "); - strcat(dst, *src); + strcat (dst, " "); + strcat (dst, *src); } } } - return(dst); + return (dst); } -static void _ifparser_source (const char *path, const char *en_dir, int quiet, int dir); - static void -_recursive_ifparser (const char *eni_file, int quiet) +_recursive_ifparser (if_parser *parser, const char *eni_file, int quiet) { FILE *inp; char line[255]; @@ -114,36 +126,35 @@ _recursive_ifparser (const char *eni_file, int quiet) /* Check if interfaces file exists and open it */ if (!g_file_test (eni_file, G_FILE_TEST_EXISTS)) { if (!quiet) - nm_log_warn (LOGD_SETTINGS, "interfaces file %s doesn't exist\n", eni_file); + _LOGW ("interfaces file %s doesn't exist", eni_file); return; } inp = fopen (eni_file, "re"); if (inp == NULL) { if (!quiet) - nm_log_warn (LOGD_SETTINGS, "Can't open %s\n", eni_file); + _LOGW ("Can't open %s", eni_file); return; } if (!quiet) - nm_log_info (LOGD_SETTINGS, " interface-parser: parsing file %s\n", eni_file); + _LOGI (" interface-parser: parsing file %s", eni_file); - while (!feof(inp)) - { + while (!feof (inp)) { char *token[128]; /* 255 chars can only be split into 127 tokens */ char value[255]; /* large enough to join previously split tokens */ char *safeptr; int toknum; int len = 0; - char *ptr = fgets(line+offs, 255-offs, inp); + char *ptr = fgets (line+offs, 255-offs, inp); if (ptr == NULL) break; - len = strlen(line); + len = strlen (line); /* skip over-long lines */ - if (!feof(inp) && len > 0 && line[len-1] != '\n') { + if (!feof (inp) && len > 0 && line[len-1] != '\n') { if (!skip_long_line) { if (!quiet) - nm_log_warn (LOGD_SETTINGS, "Skipping over-long-line '%s...'\n", line); + _LOGW ("Skipping over-long-line '%s...'", line); } skip_long_line = 1; continue; @@ -170,9 +181,9 @@ _recursive_ifparser (const char *eni_file, int quiet) #define SPACES " \t" /* tokenize input; */ - for (toknum = 0, token[toknum] = strtok_r(line, SPACES, &safeptr); + for (toknum = 0, token[toknum] = strtok_r (line, SPACES, &safeptr); token[toknum] != NULL; - toknum++, token[toknum] = strtok_r(NULL, SPACES, &safeptr)) + toknum++, token[toknum] = strtok_r (NULL, SPACES, &safeptr)) ; /* ignore comments and empty lines */ @@ -181,8 +192,8 @@ _recursive_ifparser (const char *eni_file, int quiet) if (toknum < 2) { if (!quiet) { - nm_log_warn (LOGD_SETTINGS, "Can't parse interface line '%s'\n", - join_values_with_spaces(value, token)); + _LOGW ("Can't parse interface line '%s'", + join_values_with_spaces (value, token)); } skip_to_block = 1; continue; @@ -193,71 +204,71 @@ _recursive_ifparser (const char *eni_file, int quiet) * Create a block for each of them except source and source-directory. */ /* iface stanza takes at least 3 parameters */ - if (strcmp(token[0], "iface") == 0) { + if (nm_streq (token[0], "iface")) { if (toknum < 4) { if (!quiet) { - nm_log_warn (LOGD_SETTINGS, "Can't parse iface line '%s'\n", - join_values_with_spaces(value, token)); + _LOGW ("Can't parse iface line '%s'", + join_values_with_spaces (value, token)); } continue; } - add_block(token[0], token[1]); + add_block (parser, token[0], token[1]); skip_to_block = 0; - add_data(token[2], join_values_with_spaces(value, token + 3)); + add_data (parser, token[2], join_values_with_spaces (value, token + 3)); } /* auto and allow-auto stanzas are equivalent, * both can take multiple interfaces as parameters: add one block for each */ - else if (strcmp(token[0], "auto") == 0 || - strcmp(token[0], "allow-auto") == 0) { + else if (NM_IN_STRSET (token[0], "auto", "allow-auto")) { int i; + for (i = 1; i < toknum; i++) - add_block("auto", token[i]); + add_block (parser, "auto", token[i]); skip_to_block = 0; } - else if (strcmp(token[0], "mapping") == 0) { - add_block(token[0], join_values_with_spaces(value, token + 1)); + else if (nm_streq (token[0], "mapping")) { + add_block (parser, token[0], join_values_with_spaces (value, token + 1)); skip_to_block = 0; } /* allow-* can take multiple interfaces as parameters: add one block for each */ - else if (strncmp(token[0],"allow-",6) == 0) { + else if (g_str_has_prefix (token[0], "allow-")) { int i; for (i = 1; i < toknum; i++) - add_block(token[0], token[i]); + add_block (parser, token[0], token[i]); skip_to_block = 0; } /* source and source-directory stanzas take one or more paths as parameters */ - else if (strcmp (token[0], "source") == 0 || strcmp (token[0], "source-directory") == 0) { + else if (NM_IN_STRSET (token[0], "source", "source-directory")) { int i; char *en_dir; skip_to_block = 0; en_dir = g_path_get_dirname (eni_file); for (i = 1; i < toknum; ++i) { - if (strcmp (token[0], "source-directory") == 0) - _ifparser_source (token[i], en_dir, quiet, TRUE); + if (nm_streq (token[0], "source-directory")) + _ifparser_source (parser, token[i], en_dir, quiet, TRUE); else - _ifparser_source (token[i], en_dir, quiet, FALSE); + _ifparser_source (parser, token[i], en_dir, quiet, FALSE); } g_free (en_dir); } else { if (skip_to_block) { if (!quiet) { - nm_log_warn (LOGD_SETTINGS, "ignoring out-of-block data '%s'\n", - join_values_with_spaces(value, token)); + _LOGW ("ignoring out-of-block data '%s'", + join_values_with_spaces (value, token)); } } else - add_data(token[0], join_values_with_spaces(value, token + 1)); + add_data (parser, token[0], join_values_with_spaces (value, token + 1)); } } - fclose(inp); + fclose (inp); if (!quiet) - nm_log_info (LOGD_SETTINGS, " interface-parser: finished parsing file %s\n", eni_file); + _LOGI (" interface-parser: finished parsing file %s", eni_file); } static void -_ifparser_source (const char *path, const char *en_dir, int quiet, int dir) +_ifparser_source (if_parser *parser, const char *path, const char *en_dir, int quiet, int dir) { char *abs_path; const char *item; @@ -272,132 +283,128 @@ _ifparser_source (const char *path, const char *en_dir, int quiet, int dir) abs_path = g_build_filename (en_dir, path, NULL); if (!quiet) - nm_log_info (LOGD_SETTINGS, " interface-parser: source line includes interfaces file(s) %s\n", abs_path); + _LOGI (" interface-parser: source line includes interfaces file(s) %s", abs_path); /* ifupdown uses WRDE_NOCMD for wordexp. */ if (wordexp (abs_path, &we, WRDE_NOCMD)) { if (!quiet) - nm_log_warn (LOGD_SETTINGS, "word expansion for %s failed\n", abs_path); + _LOGW ("word expansion for %s failed", abs_path); } else { for (i = 0; i < we.we_wordc; i++) { if (dir) { source_dir = g_dir_open (we.we_wordv[i], 0, &error); if (!source_dir) { if (!quiet) { - nm_log_warn (LOGD_SETTINGS, "Failed to open directory %s: %s", - we.we_wordv[i], error->message); + _LOGW ("Failed to open directory %s: %s", + we.we_wordv[i], error->message); } g_clear_error (&error); } else { while ((item = g_dir_read_name (source_dir))) - _ifparser_source (item, we.we_wordv[i], quiet, FALSE); + _ifparser_source (parser, item, we.we_wordv[i], quiet, FALSE); g_dir_close (source_dir); } } else - _recursive_ifparser (we.we_wordv[i], quiet); + _recursive_ifparser (parser, we.we_wordv[i], quiet); } wordfree (&we); } g_free (abs_path); } -void ifparser_init (const char *eni_file, int quiet) +if_parser * +ifparser_parse (const char *eni_file, int quiet) { - first = last = NULL; - _recursive_ifparser (eni_file, quiet); + if_parser *parser; + + parser = g_slice_new (if_parser); + c_list_init (&parser->block_lst_head); + _recursive_ifparser (parser, eni_file, quiet); + return parser; } -void _destroy_data(if_data *ifd) +static void +_destroy_data (if_data *ifd) { - if (ifd == NULL) - return; - _destroy_data(ifd->next); - g_free(ifd->key); - g_free(ifd->data); - g_slice_free(struct _if_data, ifd); - return; + c_list_unlink_stale (&ifd->data_lst); + g_free (ifd); } -void _destroy_block(if_block* ifb) +static void +_destroy_block (if_block* ifb) { - if (ifb == NULL) - return; - _destroy_block(ifb->next); - _destroy_data(ifb->info); - g_free(ifb->name); - g_free(ifb->type); - g_slice_free(struct _if_block, ifb); - return; + if_data *ifd; + + while ((ifd = c_list_first_entry (&ifb->data_lst_head, if_data, data_lst))) + _destroy_data (ifd); + c_list_unlink_stale (&ifb->block_lst); + g_free (ifb); } -void ifparser_destroy(void) +void +ifparser_destroy (if_parser *parser) { - _destroy_block(first); - first = last = NULL; + if_block *ifb; + + while ((ifb = c_list_first_entry (&parser->block_lst_head, if_block, block_lst))) + _destroy_block (ifb); + g_slice_free (if_parser, parser); } -if_block *ifparser_getfirst(void) +if_block * +ifparser_getfirst (if_parser *parser) { - return first; + return c_list_first_entry (&parser->block_lst_head, if_block, block_lst); } -int ifparser_get_num_blocks(void) +guint +ifparser_get_num_blocks (if_parser *parser) { - int i = 0; - if_block *iter = first; - - while (iter) { - i++; - iter = iter->next; - } - return i; + return c_list_length (&parser->block_lst_head); } -if_block *ifparser_getif(const char* iface) +if_block * +ifparser_getif (if_parser *parser, const char* iface) { - if_block *curr = first; - while(curr!=NULL) - { - if (strcmp(curr->type,"iface")==0 && strcmp(curr->name,iface)==0) - return curr; - curr = curr->next; + if_block *ifb; + + c_list_for_each_entry (ifb, &parser->block_lst_head, block_lst) { + if ( nm_streq (ifb->type, "iface") + && nm_streq (ifb->name, iface)) + return ifb; } return NULL; } -const char *ifparser_getkey(if_block* iface, const char *key) +static if_data * +ifparser_findkey (if_block* iface, const char *key) { - if_data *curr = iface->info; - while(curr!=NULL) - { - if (strcmp(curr->key,key)==0) - return curr->data; - curr = curr->next; + if_data *ifd; + + c_list_for_each_entry (ifd, &iface->data_lst_head, data_lst) { + if (nm_streq (ifd->key, key)) + return ifd; } return NULL; } -gboolean -ifparser_haskey(if_block* iface, const char *key) +const char * +ifparser_getkey (if_block* iface, const char *key) { - if_data *curr = iface->info; + if_data *ifd; - while (curr != NULL) { - if (strcmp (curr->key, key) == 0) - return TRUE; - curr = curr->next; - } - return FALSE; + ifd = ifparser_findkey (iface, key); + return ifd ? ifd->data : NULL; } -int ifparser_get_num_info(if_block* iface) +gboolean +ifparser_haskey (if_block* iface, const char *key) { - int i = 0; - if_data *iter = iface->info; + return !!ifparser_findkey (iface, key); +} - while (iter) { - i++; - iter = iter->next; - } - return i; +guint +ifparser_get_num_info (if_block* iface) +{ + return c_list_length (&iface->data_lst_head); } diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.h b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.h index 7e6c8e34..f367f626 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.h +++ b/src/settings/plugins/ifupdown/nms-ifupdown-interface-parser.h @@ -23,33 +23,37 @@ #ifndef _INTERFACE_PARSER_H #define _INTERFACE_PARSER_H -typedef struct _if_data -{ - char *key; - char *data; - struct _if_data *next; +#include "c-list/src/c-list.h" + +typedef struct { + CList data_lst; + const char *data; + const char key[]; } if_data; -typedef struct _if_block -{ - char *type; - char *name; - if_data *info; - struct _if_block *next; +typedef struct { + CList block_lst; + CList data_lst_head; + const char *type; + const char name[]; } if_block; -void ifparser_init(const char *eni_file, int quiet); -void ifparser_destroy(void); +typedef struct { + CList block_lst_head; +} if_parser; + +if_parser *ifparser_parse (const char *eni_file, int quiet); + +void ifparser_destroy (if_parser *parser); +NM_AUTO_DEFINE_FCN0 (if_parser *, _nm_auto_ifparser, ifparser_destroy); +#define nm_auto_ifparser nm_auto(_nm_auto_ifparser) + +if_block *ifparser_getif (if_parser *parser, const char* iface); +if_block *ifparser_getfirst (if_parser *parser); +const char *ifparser_getkey (if_block* iface, const char *key); +gboolean ifparser_haskey (if_block* iface, const char *key); -if_block *ifparser_getif(const char* iface); -if_block *ifparser_getfirst(void); -const char *ifparser_getkey(if_block* iface, const char *key); -gboolean ifparser_haskey(if_block* iface, const char *key); -int ifparser_get_num_blocks(void); -int ifparser_get_num_info(if_block* iface); +guint ifparser_get_num_blocks (if_parser *parser); +guint ifparser_get_num_info (if_block* iface); -void add_block(const char *type, const char* name); -void add_data(const char *key,const char *data); -void _destroy_data(if_data *ifd); -void _destroy_block(if_block* ifb); #endif diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-parser.c b/src/settings/plugins/ifupdown/nms-ifupdown-parser.c index 884c6591..369fa70d 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-parser.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-parser.c @@ -37,42 +37,64 @@ #include "nms-ifupdown-plugin.h" #include "nms-ifupdown-parser.h" -static const gchar* +/*****************************************************************************/ + +#define _NMLOG_PREFIX_NAME "ifupdown" +#define _NMLOG_DOMAIN LOGD_SETTINGS +#define _NMLOG(level, ...) \ + nm_log ((level), _NMLOG_DOMAIN, NULL, NULL, \ + "%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME": " \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)) + +/*****************************************************************************/ + +#define _str_has_prefix(val, prefix, require_suffix) \ + ({ \ + const char *_val = (val); \ + \ + (strncmp (_val, ""prefix"", NM_STRLEN (prefix)) == 0) \ + && ( !(require_suffix) \ + || _val[NM_STRLEN (prefix)] != '\0'); \ + }) + +static const char* _ifupdownplugin_guess_connection_type (if_block *block) { - if_data *curr = block->info; - const gchar* ret_type = NULL; - const gchar* value = ifparser_getkey(block, "inet"); - if(value && !strcmp("ppp", value)) { - ret_type = NM_SETTING_PPP_SETTING_NAME; - } + const char *ret_type = NULL; - while(!ret_type && curr) { - if(!strncmp("wireless-", curr->key, strlen("wireless-")) || - !strncmp("wpa-", curr->key, strlen("wpa-"))) { - ret_type = NM_SETTING_WIRELESS_SETTING_NAME; + if(nm_streq0 (ifparser_getkey (block, "inet"), "ppp")) + ret_type = NM_SETTING_PPP_SETTING_NAME; + else { + if_data *ifb; + + c_list_for_each_entry (ifb, &block->data_lst_head, data_lst) { + if ( _str_has_prefix (ifb->key, "wireless-", FALSE) + || _str_has_prefix (ifb->key, "wpa-", FALSE)) { + ret_type = NM_SETTING_WIRELESS_SETTING_NAME; + break; + } } - curr = curr->next; + if(!ret_type) + ret_type = NM_SETTING_WIRED_SETTING_NAME; } - if(!ret_type) - ret_type = NM_SETTING_WIRED_SETTING_NAME; - - nm_log_info (LOGD_SETTINGS, "guessed connection type (%s) = %s", block->name, ret_type); + _LOGI ("guessed connection type (%s) = %s", block->name, ret_type); return ret_type; } struct _Mapping { - const gchar *domain; + const char *domain; const gpointer target; }; static gpointer -map_by_mapping(struct _Mapping *mapping, const gchar *key) +map_by_mapping (struct _Mapping *mapping, const char *key) { struct _Mapping *curr = mapping; - while(curr->domain) { - if(!strcmp(curr->domain, key)) + + while (curr->domain) { + if (nm_streq (curr->domain, key)) return curr->target; curr++; } @@ -80,14 +102,11 @@ map_by_mapping(struct _Mapping *mapping, const gchar *key) } static void -update_wireless_setting_from_if_block(NMConnection *connection, - if_block *block) +update_wireless_setting_from_if_block (NMConnection *connection, + if_block *block) { - gint wpa_l= strlen("wpa-"); - gint wireless_l= strlen("wireless-"); - - if_data *curr = block->info; - const gchar* value = ifparser_getkey (block, "inet"); + if_data *curr; + const char *value = ifparser_getkey (block, "inet"); struct _Mapping mapping[] = { {"ssid", "ssid"}, {"essid", "ssid"}, @@ -97,27 +116,26 @@ update_wireless_setting_from_if_block(NMConnection *connection, NMSettingWireless *wireless_setting = NULL; - if(value && !strcmp("ppp", value)) { + if (nm_streq0 (value, "ppp")) return; - } - nm_log_info (LOGD_SETTINGS, "update wireless settings (%s).", block->name); - wireless_setting = NM_SETTING_WIRELESS(nm_setting_wireless_new()); + _LOGI ("update wireless settings (%s).", block->name); + wireless_setting = NM_SETTING_WIRELESS (nm_setting_wireless_new ()); + + c_list_for_each_entry (curr, &block->data_lst_head, data_lst) { + if (_str_has_prefix (curr->key, "wireless-", TRUE)) { + const char* newkey = map_by_mapping (mapping, curr->key + NM_STRLEN ("wireless-")); - while(curr) { - if(strlen(curr->key) > wireless_l && - !strncmp("wireless-", curr->key, wireless_l)) { - const gchar* newkey = map_by_mapping(mapping, curr->key+wireless_l); - nm_log_info (LOGD_SETTINGS, "wireless setting key: %s='%s'", newkey, curr->data); - if(newkey && !strcmp("ssid", newkey)) { + _LOGI ("wireless setting key: %s='%s'", newkey, curr->data); + if (nm_streq0 (newkey, "ssid")) { GBytes *ssid; - gint len = strlen(curr->data); + int len = strlen (curr->data); ssid = g_bytes_new (curr->data, len); g_object_set (wireless_setting, NM_SETTING_WIRELESS_SSID, ssid, NULL); g_bytes_unref (ssid); - nm_log_info (LOGD_SETTINGS, "setting wireless ssid = %d", len); - } else if(newkey && !strcmp("mode", newkey)) { + _LOGI ("setting wireless ssid = %d", len); + } else if (nm_streq0 (newkey, "mode")) { if (!g_ascii_strcasecmp (curr->data, "Managed") || !g_ascii_strcasecmp (curr->data, "Auto")) g_object_set (wireless_setting, NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_INFRA, NULL); else if (!g_ascii_strcasecmp (curr->data, "Ad-Hoc")) @@ -125,39 +143,37 @@ update_wireless_setting_from_if_block(NMConnection *connection, else if (!g_ascii_strcasecmp (curr->data, "Master")) g_object_set (wireless_setting, NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_AP, NULL); else - nm_log_warn (LOGD_SETTINGS, "Invalid mode '%s' (not 'Ad-Hoc', 'Ap', 'Managed', or 'Auto')", curr->data); + _LOGW ("Invalid mode '%s' (not 'Ad-Hoc', 'Ap', 'Managed', or 'Auto')", curr->data); } else { - g_object_set(wireless_setting, - newkey, curr->data, - NULL); + g_object_set (wireless_setting, + newkey, curr->data, + NULL); } - } else if(strlen(curr->key) > wpa_l && - !strncmp("wpa-", curr->key, wpa_l)) { - const gchar* newkey = map_by_mapping(mapping, curr->key+wpa_l); + } else if (_str_has_prefix (curr->key, "wpa-", TRUE)) { + const char* newkey = map_by_mapping (mapping, curr->key + NM_STRLEN ("wpa-")); - if(newkey && !strcmp("ssid", newkey)) { + if (nm_streq0 (newkey, "ssid")) { GBytes *ssid; - gint len = strlen(curr->data); + int len = strlen (curr->data); ssid = g_bytes_new (curr->data, len); g_object_set (wireless_setting, NM_SETTING_WIRELESS_SSID, ssid, NULL); g_bytes_unref (ssid); - nm_log_info (LOGD_SETTINGS, "setting wpa ssid = %d", len); - } else if(newkey) { + _LOGI ("setting wpa ssid = %d", len); + } else if (newkey) { - g_object_set(wireless_setting, - newkey, curr->data, - NULL); - nm_log_info (LOGD_SETTINGS, "setting wpa newkey(%s)=data(%s)", newkey, curr->data); + g_object_set (wireless_setting, + newkey, curr->data, + NULL); + _LOGI ("setting wpa newkey(%s)=data(%s)", newkey, curr->data); } } - curr = curr->next; } - nm_connection_add_setting(connection, (NMSetting*) wireless_setting); + nm_connection_add_setting (connection, (NMSetting*) wireless_setting); } -typedef gchar* (*IfupdownStrDupeFunc) (gpointer value, gpointer data); -typedef gpointer (*IfupdownStrToTypeFunc) (const gchar* value); +typedef char* (*IfupdownStrDupeFunc) (gconstpointer value, gpointer data); +typedef gpointer (*IfupdownStrToTypeFunc) (const char* value); static char* normalize_dupe_wireless_key (gpointer value, gpointer data) { @@ -177,7 +193,7 @@ normalize_dupe_wireless_key (gpointer value, gpointer data) { result_cur += next - delim; delim = next + 1; } - if (*delim && strlen (valuec) > GPOINTER_TO_UINT(delim - valuec)) { + if (*delim && strlen (valuec) > GPOINTER_TO_UINT (delim - valuec)) { strncpy (result_cur, delim, endc - delim); result_cur += endc - delim; } @@ -187,12 +203,12 @@ normalize_dupe_wireless_key (gpointer value, gpointer data) { static char* normalize_dupe (gpointer value, gpointer data) { - return g_strdup(value); + return g_strdup (value); } static char* normalize_tolower (gpointer value, gpointer data) { - return g_ascii_strdown(value, -1); + return g_ascii_strdown (value, -1); } static char *normalize_psk (gpointer value, gpointer data) @@ -203,25 +219,25 @@ static char *normalize_psk (gpointer value, gpointer data) } static gpointer -string_to_gpointerint(const gchar* data) +string_to_gpointerint (const char* data) { - gint result = (gint) strtol (data, NULL, 10); - return GINT_TO_POINTER(result); + int result = (int) strtol (data, NULL, 10); + return GINT_TO_POINTER (result); } static gpointer -string_to_glist_of_strings(const gchar* data) +string_to_glist_of_strings (const char* data) { GSList *ret = NULL; - gchar *string = (gchar*) data; - while(string) { - gchar* next = NULL; - if( (next = strchr(string, ' ')) || - (next = strchr(string, '\t')) || - (next = strchr(string, '\0')) ) { - - gchar *part = g_strndup(string, (next - string)); - ret = g_slist_append(ret, part); + char *string = (char*) data; + while (string) { + char* next = NULL; + if ( (next = strchr (string, ' ')) || + (next = strchr (string, '\t')) || + (next = strchr (string, '\0')) ) { + + char *part = g_strndup (string, (next - string)); + ret = g_slist_append (ret, part); if (*next) string = next+1; else @@ -234,19 +250,17 @@ string_to_glist_of_strings(const gchar* data) } static void -slist_free_all(gpointer slist) +slist_free_all (gpointer slist) { g_slist_free_full ((GSList *) slist, g_free); } static void -update_wireless_security_setting_from_if_block(NMConnection *connection, - if_block *block) +update_wireless_security_setting_from_if_block (NMConnection *connection, + if_block *block) { - gint wpa_l= strlen("wpa-"); - gint wireless_l= strlen("wireless-"); - if_data *curr = block->info; - const gchar* value = ifparser_getkey (block, "inet"); + if_data *curr; + const char* value = ifparser_getkey (block, "inet"); struct _Mapping mapping[] = { {"psk", "psk"}, {"identity", "leap-username"}, @@ -302,101 +316,93 @@ update_wireless_security_setting_from_if_block(NMConnection *connection, NMSettingWireless *s_wireless; gboolean security = FALSE; - if(value && !strcmp("ppp", value)) { + if (nm_streq0 (value, "ppp")) return; - } - - s_wireless = nm_connection_get_setting_wireless(connection); - g_return_if_fail(s_wireless); - nm_log_info (LOGD_SETTINGS, "update wireless security settings (%s).", block->name); - wireless_security_setting = - NM_SETTING_WIRELESS_SECURITY(nm_setting_wireless_security_new()); + s_wireless = nm_connection_get_setting_wireless (connection); + g_return_if_fail (s_wireless); - while(curr) { - if(strlen(curr->key) > wireless_l && - !strncmp("wireless-", curr->key, wireless_l)) { + _LOGI ("update wireless security settings (%s).", block->name); + wireless_security_setting = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ()); - gchar *property_value = NULL; + c_list_for_each_entry (curr, &block->data_lst_head, data_lst) { + if (_str_has_prefix (curr->key, "wireless-", TRUE)) { + const char *key = curr->key + NM_STRLEN ("wireless-"); + char *property_value = NULL; gpointer typed_property_value = NULL; - const gchar* newkey = map_by_mapping(mapping, curr->key+wireless_l); - IfupdownStrDupeFunc dupe_func = map_by_mapping (dupe_mapping, curr->key+wireless_l); - IfupdownStrToTypeFunc type_map_func = map_by_mapping (type_mapping, curr->key+wireless_l); - GFreeFunc free_func = map_by_mapping (free_type_mapping, curr->key+wireless_l); - if(!newkey || !dupe_func) + const char* newkey = map_by_mapping (mapping, key); + IfupdownStrDupeFunc dupe_func = map_by_mapping (dupe_mapping, key); + IfupdownStrToTypeFunc type_map_func = map_by_mapping (type_mapping, key); + GFreeFunc free_func = map_by_mapping (free_type_mapping, key); + if (!newkey || !dupe_func) goto next; property_value = (*dupe_func) (curr->data, connection); - nm_log_info (LOGD_SETTINGS, "setting wireless security key: %s=%s", - newkey, property_value); + _LOGI ("setting wireless security key: %s=%s", + newkey, property_value); if (type_map_func) { errno = 0; typed_property_value = (*type_map_func) (property_value); - if(errno) + if (errno) goto wireless_next; } - g_object_set(wireless_security_setting, - newkey, typed_property_value ?: property_value, - NULL); + g_object_set (wireless_security_setting, + newkey, typed_property_value ?: property_value, + NULL); security = TRUE; - wireless_next: - g_free(property_value); +wireless_next: + g_free (property_value); if (typed_property_value && free_func) (*free_func) (typed_property_value); - } else if(strlen(curr->key) > wpa_l && - !strncmp("wpa-", curr->key, wpa_l)) { - - gchar *property_value = NULL; + } else if (_str_has_prefix (curr->key, "wpa-", TRUE)) { + const char *key = curr->key + NM_STRLEN ("wpa-"); + char *property_value = NULL; gpointer typed_property_value = NULL; - const gchar* newkey = map_by_mapping(mapping, curr->key+wpa_l); - IfupdownStrDupeFunc dupe_func = map_by_mapping (dupe_mapping, curr->key+wpa_l); - IfupdownStrToTypeFunc type_map_func = map_by_mapping (type_mapping, curr->key+wpa_l); - GFreeFunc free_func = map_by_mapping (free_type_mapping, curr->key+wpa_l); - if(!newkey || !dupe_func) + const char* newkey = map_by_mapping (mapping, key); + IfupdownStrDupeFunc dupe_func = map_by_mapping (dupe_mapping, key); + IfupdownStrToTypeFunc type_map_func = map_by_mapping (type_mapping, key); + GFreeFunc free_func = map_by_mapping (free_type_mapping, key); + if (!newkey || !dupe_func) goto next; property_value = (*dupe_func) (curr->data, connection); - nm_log_info (LOGD_SETTINGS, "setting wpa security key: %s=%s", - newkey, -#ifdef DEBUG_SECRETS - property_value -#else /* DEBUG_SECRETS */ - !strcmp("key", newkey) || - !strcmp("leap-password", newkey) || - !strcmp("pin", newkey) || - !strcmp("psk", newkey) || - !strcmp("wep-key0", newkey) || - !strcmp("wep-key1", newkey) || - !strcmp("wep-key2", newkey) || - !strcmp("wep-key3", newkey) || - NULL ? - "<omitted>" : property_value -#endif /* DEBUG_SECRETS */ - ); + _LOGI ("setting wpa security key: %s=%s", + newkey, + NM_IN_STRSET (newkey, "key", + "leap-password", + "pin", + "psk", + "wep-key0", + "wep-key1", + "wep-key2", + "wep-key3") + ? "<omitted>" + : property_value + ); if (type_map_func) { errno = 0; typed_property_value = (*type_map_func) (property_value); - if(errno) + if (errno) goto wpa_next; } - g_object_set(wireless_security_setting, - newkey, typed_property_value ?: property_value, - NULL); + g_object_set (wireless_security_setting, + newkey, typed_property_value ?: property_value, + NULL); security = TRUE; - wpa_next: - g_free(property_value); +wpa_next: + g_free (property_value); if (free_func && typed_property_value) (*free_func) (typed_property_value); } - next: - curr = curr->next; +next: + ; } if (security) @@ -404,51 +410,52 @@ update_wireless_security_setting_from_if_block(NMConnection *connection, } static void -update_wired_setting_from_if_block(NMConnection *connection, - if_block *block) +update_wired_setting_from_if_block (NMConnection *connection, + if_block *block) { NMSettingWired *s_wired = NULL; - s_wired = NM_SETTING_WIRED(nm_setting_wired_new()); - nm_connection_add_setting(connection, NM_SETTING(s_wired)); + s_wired = NM_SETTING_WIRED (nm_setting_wired_new ()); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); } static void ifupdown_ip4_add_dns (NMSettingIPConfig *s_ip4, const char *dns) { guint32 addr; - char **list, **iter; + gs_strfreev char **list = NULL; + char **iter; if (dns == NULL) return; list = g_strsplit_set (dns, " \t", -1); for (iter = list; iter && *iter; iter++) { - g_strstrip (*iter); - if (g_ascii_isspace (*iter[0])) + if ((*iter)[0] == '\0') continue; if (!inet_pton (AF_INET, *iter, &addr)) { - nm_log_warn (LOGD_SETTINGS, " ignoring invalid nameserver '%s'", *iter); + _LOGW (" ignoring invalid nameserver '%s'", *iter); continue; } if (!nm_setting_ip_config_add_dns (s_ip4, *iter)) - nm_log_warn (LOGD_SETTINGS, " duplicate DNS domain '%s'", *iter); + _LOGW (" duplicate DNS domain '%s'", *iter); } - g_strfreev (list); } static gboolean -update_ip4_setting_from_if_block(NMConnection *connection, - if_block *block, - GError **error) +update_ip4_setting_from_if_block (NMConnection *connection, + if_block *block, + GError **error) { - NMSettingIPConfig *s_ip4 = NM_SETTING_IP_CONFIG (nm_setting_ip4_config_new()); - const char *type = ifparser_getkey(block, "inet"); - gboolean is_static = type && !strcmp("static", type); + gs_unref_object NMSettingIPConfig *s_ip4 = NM_SETTING_IP_CONFIG (nm_setting_ip4_config_new ()); + const char *type = ifparser_getkey (block, "inet"); - if (!is_static) { - g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL); + if (!nm_streq0 (type, "static")) { + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NULL); } else { guint32 tmp_mask; NMIPAddress *addr; @@ -458,7 +465,6 @@ update_ip4_setting_from_if_block(NMConnection *connection, const char *nameserver_v; const char *nameservers_v; const char *search_v; - char **list, **iter; guint32 netmask_int = 32; /* Address */ @@ -466,7 +472,7 @@ update_ip4_setting_from_if_block(NMConnection *connection, if (!address_v) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing IPv4 address"); - goto error; + return FALSE; } /* mask/prefix */ @@ -476,8 +482,8 @@ update_ip4_setting_from_if_block(NMConnection *connection, netmask_int = atoi (netmask_v); } else if (!inet_pton (AF_INET, netmask_v, &tmp_mask)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid IPv4 netmask '%s'", netmask_v); - goto error; + "Invalid IPv4 netmask '%s'", netmask_v); + return FALSE; } else { netmask_int = nm_utils_ip4_netmask_to_prefix (tmp_mask); } @@ -486,13 +492,13 @@ update_ip4_setting_from_if_block(NMConnection *connection, /* Add the new address to the setting */ addr = nm_ip_address_new (AF_INET, address_v, netmask_int, error); if (!addr) - goto error; + return FALSE; if (nm_setting_ip_config_add_address (s_ip4, addr)) { - nm_log_info (LOGD_SETTINGS, "addresses count: %d", - nm_setting_ip_config_get_num_addresses (s_ip4)); + _LOGI ("addresses count: %d", + nm_setting_ip_config_get_num_addresses (s_ip4)); } else { - nm_log_info (LOGD_SETTINGS, "ignoring duplicate IP4 address"); + _LOGI ("ignoring duplicate IP4 address"); } nm_ip_address_unref (addr); @@ -502,7 +508,7 @@ update_ip4_setting_from_if_block(NMConnection *connection, if (!nm_utils_ipaddr_valid (AF_INET, gateway_v)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid IPv4 gateway '%s'", gateway_v); - goto error; + return FALSE; } if (!nm_setting_ip_config_get_gateway (s_ip4)) g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway_v, NULL); @@ -515,70 +521,67 @@ update_ip4_setting_from_if_block(NMConnection *connection, ifupdown_ip4_add_dns (s_ip4, nameservers_v); if (!nm_setting_ip_config_get_num_dns (s_ip4)) - nm_log_info (LOGD_SETTINGS, "No dns-nameserver configured in /etc/network/interfaces"); + _LOGI ("No dns-nameserver configured in /etc/network/interfaces"); /* DNS searches */ search_v = ifparser_getkey (block, "dns-search"); if (search_v) { + gs_strfreev char **list = NULL; + char **iter; + list = g_strsplit_set (search_v, " \t", -1); for (iter = list; iter && *iter; iter++) { - g_strstrip (*iter); - if (g_ascii_isspace (*iter[0])) + if ((*iter)[0] == '\0') continue; if (!nm_setting_ip_config_add_dns_search (s_ip4, *iter)) - nm_log_warn (LOGD_SETTINGS, " duplicate DNS domain '%s'", *iter); + _LOGW (" duplicate DNS domain '%s'", *iter); } - g_strfreev (list); } g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NULL); } - nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + nm_connection_add_setting (connection, NM_SETTING (g_steal_pointer (&s_ip4))); return TRUE; - -error: - g_object_unref (s_ip4); - return FALSE; } static void ifupdown_ip6_add_dns (NMSettingIPConfig *s_ip6, const char *dns) { struct in6_addr addr; - char **list, **iter; + gs_strfreev char **list = NULL; + char **iter; if (dns == NULL) return; list = g_strsplit_set (dns, " \t", -1); for (iter = list; iter && *iter; iter++) { - g_strstrip (*iter); - if (g_ascii_isspace (*iter[0])) + if ((*iter)[0] == '\0') continue; if (!inet_pton (AF_INET6, *iter, &addr)) { - nm_log_warn (LOGD_SETTINGS, " ignoring invalid nameserver '%s'", *iter); + _LOGW (" ignoring invalid nameserver '%s'", *iter); continue; } if (!nm_setting_ip_config_add_dns (s_ip6, *iter)) - nm_log_warn (LOGD_SETTINGS, " duplicate DNS domain '%s'", *iter); + _LOGW (" duplicate DNS domain '%s'", *iter); } - g_strfreev (list); } static gboolean -update_ip6_setting_from_if_block(NMConnection *connection, - if_block *block, - GError **error) +update_ip6_setting_from_if_block (NMConnection *connection, + if_block *block, + GError **error) { - NMSettingIPConfig *s_ip6 = NM_SETTING_IP_CONFIG (nm_setting_ip6_config_new()); - const char *type = ifparser_getkey(block, "inet6"); - gboolean is_static = type && (!strcmp("static", type) || - !strcmp("v4tunnel", type)); + gs_unref_object NMSettingIPConfig *s_ip6 = NM_SETTING_IP_CONFIG (nm_setting_ip6_config_new ()); + const char *type = ifparser_getkey (block, "inet6"); - if (!is_static) { - g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); + if (!NM_IN_STRSET (type, "static", "v4tunnel")) { + g_object_set (s_ip6, + NM_SETTING_IP_CONFIG_METHOD, + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NULL); } else { NMIPAddress *addr; const char *address_v; @@ -588,31 +591,30 @@ update_ip6_setting_from_if_block(NMConnection *connection, const char *nameservers_v; const char *search_v; int prefix_int = 128; - char **list, **iter; /* Address */ - address_v = ifparser_getkey(block, "address"); + address_v = ifparser_getkey (block, "address"); if (!address_v) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Missing IPv6 address"); - goto error; + return FALSE; } /* Prefix */ - prefix_v = ifparser_getkey(block, "netmask"); + prefix_v = ifparser_getkey (block, "netmask"); if (prefix_v) prefix_int = g_ascii_strtoll (prefix_v, NULL, 10); /* Add the new address to the setting */ addr = nm_ip_address_new (AF_INET6, address_v, prefix_int, error); if (!addr) - goto error; + return FALSE; if (nm_setting_ip_config_add_address (s_ip6, addr)) { - nm_log_info (LOGD_SETTINGS, "addresses count: %d", + _LOGI ("addresses count: %d", nm_setting_ip_config_get_num_addresses (s_ip6)); } else { - nm_log_info (LOGD_SETTINGS, "ignoring duplicate IP6 address"); + _LOGI ("ignoring duplicate IP6 address"); } nm_ip_address_unref (addr); @@ -622,33 +624,34 @@ update_ip6_setting_from_if_block(NMConnection *connection, if (!nm_utils_ipaddr_valid (AF_INET6, gateway_v)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid IPv6 gateway '%s'", gateway_v); - goto error; + return FALSE; } if (!nm_setting_ip_config_get_gateway (s_ip6)) g_object_set (s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, gateway_v, NULL); } - nameserver_v = ifparser_getkey(block, "dns-nameserver"); + nameserver_v = ifparser_getkey (block, "dns-nameserver"); ifupdown_ip6_add_dns (s_ip6, nameserver_v); - nameservers_v = ifparser_getkey(block, "dns-nameservers"); + nameservers_v = ifparser_getkey (block, "dns-nameservers"); ifupdown_ip6_add_dns (s_ip6, nameservers_v); if (!nm_setting_ip_config_get_num_dns (s_ip6)) - nm_log_info (LOGD_SETTINGS, "No dns-nameserver configured in /etc/network/interfaces"); + _LOGI ("No dns-nameserver configured in /etc/network/interfaces"); /* DNS searches */ search_v = ifparser_getkey (block, "dns-search"); if (search_v) { + gs_strfreev char **list = NULL; + char **iter; + list = g_strsplit_set (search_v, " \t", -1); for (iter = list; iter && *iter; iter++) { - g_strstrip (*iter); - if (isblank (*iter[0])) + if ((*iter)[0] == '\0') continue; if (!nm_setting_ip_config_add_dns_search (s_ip6, *iter)) - nm_log_warn (LOGD_SETTINGS, " duplicate DNS domain '%s'", *iter); + _LOGW (" duplicate DNS domain '%s'", *iter); } - g_strfreev (list); } g_object_set (s_ip6, @@ -656,12 +659,8 @@ update_ip6_setting_from_if_block(NMConnection *connection, NULL); } - nm_connection_add_setting (connection, NM_SETTING (s_ip6)); + nm_connection_add_setting (connection, NM_SETTING (g_steal_pointer (&s_ip6))); return TRUE; - -error: - g_object_unref (s_ip6); - return FALSE; } gboolean @@ -669,25 +668,22 @@ ifupdown_update_connection_from_if_block (NMConnection *connection, if_block *block, GError **error) { - const char *type = NULL; - char *idstr = NULL; - char *uuid_base = NULL; - char *uuid = NULL; + const char *type; + gs_free char *idstr = NULL; + gs_free char *uuid = NULL; NMSettingConnection *s_con; gboolean success = FALSE; s_con = nm_connection_get_setting_connection (connection); - if(!s_con) { - s_con = NM_SETTING_CONNECTION (nm_setting_connection_new()); - g_assert (s_con); + if (!s_con) { + s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ()); nm_connection_add_setting (connection, NM_SETTING (s_con)); } type = _ifupdownplugin_guess_connection_type (block); idstr = g_strconcat ("Ifupdown (", block->name, ")", NULL); - uuid_base = idstr; - uuid = nm_utils_uuid_generate_from_string (uuid_base, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL); + uuid = nm_utils_uuid_generate_from_string (idstr, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL); g_object_set (s_con, NM_SETTING_CONNECTION_TYPE, type, NM_SETTING_CONNECTION_INTERFACE_NAME, block->name, @@ -696,19 +692,18 @@ ifupdown_update_connection_from_if_block (NMConnection *connection, NM_SETTING_CONNECTION_READ_ONLY, TRUE, NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, NULL); - g_free (uuid); - nm_log_info (LOGD_SETTINGS, "update_connection_setting_from_if_block: name:%s, type:%s, id:%s, uuid: %s", - block->name, type, idstr, nm_setting_connection_get_uuid (s_con)); + _LOGI ("update_connection_setting_from_if_block: name:%s, type:%s, id:%s, uuid: %s", + block->name, type, idstr, nm_setting_connection_get_uuid (s_con)); - if (!strcmp (NM_SETTING_WIRED_SETTING_NAME, type)) + if (nm_streq (type, NM_SETTING_WIRED_SETTING_NAME)) update_wired_setting_from_if_block (connection, block); - else if (!strcmp (NM_SETTING_WIRELESS_SETTING_NAME, type)) { + else if (nm_streq (type, NM_SETTING_WIRELESS_SETTING_NAME)) { update_wireless_setting_from_if_block (connection, block); update_wireless_security_setting_from_if_block (connection, block); } - if (ifparser_haskey(block, "inet6")) + if (ifparser_haskey (block, "inet6")) success = update_ip6_setting_from_if_block (connection, block, error); else success = update_ip4_setting_from_if_block (connection, block, error); @@ -716,6 +711,5 @@ ifupdown_update_connection_from_if_block (NMConnection *connection, if (success == TRUE) success = nm_connection_verify (connection, error); - g_free (idstr); return success; } diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c index 8bd72d02..88c651b8 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c @@ -29,7 +29,6 @@ #include <string.h> #include <arpa/inet.h> #include <gmodule.h> -#include <libudev.h> #include "nm-setting-connection.h" #include "nm-dbus-interface.h" @@ -42,7 +41,6 @@ #include "nm-core-internal.h" #include "NetworkManagerUtils.h" #include "nm-config.h" -#include "nm-utils/nm-udev-utils.h" #include "nms-ifupdown-interface-parser.h" #include "nms-ifupdown-connection.h" @@ -52,43 +50,27 @@ #define IFUPDOWN_UNMANAGE_WELL_KNOWN_DEFAULT TRUE -/* #define ALWAYS_UNMANAGE TRUE */ -#ifndef ALWAYS_UNMANAGE -#define ALWAYS_UNMANAGE FALSE -#endif - /*****************************************************************************/ typedef struct { - NMUdevClient *udev_client; - - GHashTable *connections; /* /e/n/i block name :: NMIfupdownConnection */ - - /* Stores all blocks/interfaces read from /e/n/i regardless of whether - * there is an NMIfupdownConnection for block. + /* Stores an entry for blocks/interfaces read from /e/n/i and (if exists) + * the NMIfupdownConnection associated with the block. */ GHashTable *eni_ifaces; - /* Stores any network interfaces the kernel knows about */ - GHashTable *kernel_ifaces; - - gboolean unmanage_well_known; + bool ifupdown_managed; } SettingsPluginIfupdownPrivate; struct _SettingsPluginIfupdown { - GObject parent; + NMSettingsPlugin parent; SettingsPluginIfupdownPrivate _priv; }; struct _SettingsPluginIfupdownClass { - GObjectClass parent; + NMSettingsPluginClass parent; }; -static void settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface); - -G_DEFINE_TYPE_EXTENDED (SettingsPluginIfupdown, settings_plugin_ifupdown, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN, - settings_plugin_interface_init)) +G_DEFINE_TYPE (SettingsPluginIfupdown, settings_plugin_ifupdown, NM_TYPE_SETTINGS_PLUGIN) #define SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE(self) _NM_GET_PRIVATE (self, SettingsPluginIfupdown, SETTINGS_IS_PLUGIN_IFUPDOWN) @@ -99,169 +81,41 @@ NM_DEFINE_SINGLETON_GETTER (SettingsPluginIfupdown, settings_plugin_ifupdown_get /*****************************************************************************/ -static void -bind_device_to_connection (SettingsPluginIfupdown *self, - struct udev_device *device, - NMIfupdownConnection *exported) -{ - NMSettingWired *s_wired; - NMSettingWireless *s_wifi; - const char *iface, *address; - - iface = udev_device_get_sysname (device); - if (!iface) { - nm_log_warn (LOGD_SETTINGS, "failed to get ifname for device."); - return; - } - - address = udev_device_get_sysattr_value (device, "address"); - if (!address || !address[0]) { - nm_log_warn (LOGD_SETTINGS, "failed to get MAC address for %s", iface); - return; - } - - if (!nm_utils_hwaddr_valid (address, ETH_ALEN)) { - nm_log_warn (LOGD_SETTINGS, "failed to parse MAC address '%s' for %s", - address, iface); - return; - } - - s_wired = nm_connection_get_setting_wired (NM_CONNECTION (exported)); - s_wifi = nm_connection_get_setting_wireless (NM_CONNECTION (exported)); - if (s_wired) { - nm_log_info (LOGD_SETTINGS, "locking wired connection setting"); - g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, address, NULL); - } else if (s_wifi) { - nm_log_info (LOGD_SETTINGS, "locking wireless connection setting"); - g_object_set (s_wifi, NM_SETTING_WIRELESS_MAC_ADDRESS, address, NULL); - } - - nm_settings_connection_update (NM_SETTINGS_CONNECTION (exported), - NULL, - NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK, - NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, - "ifupdown-new", - NULL); -} - -static void -udev_device_added (SettingsPluginIfupdown *self, struct udev_device *device) -{ - SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); - const char *iface, *path; - NMIfupdownConnection *exported; - - iface = udev_device_get_sysname (device); - path = udev_device_get_syspath (device); - if (!iface || !path) - return; - - nm_log_info (LOGD_SETTINGS, "devices added (path: %s, iface: %s)", path, iface); - - /* if we have a configured connection for this particular iface - * we want to either unmanage the device or lock it - */ - exported = g_hash_table_lookup (priv->connections, iface); - if (!exported && !g_hash_table_lookup (priv->eni_ifaces, iface)) { - nm_log_info (LOGD_SETTINGS, "device added (path: %s, iface: %s): no ifupdown configuration found.", - path, iface); - return; - } - - g_hash_table_insert (priv->kernel_ifaces, g_strdup (iface), udev_device_ref (device)); - - if (exported) - bind_device_to_connection (self, device, exported); - - if (ALWAYS_UNMANAGE || priv->unmanage_well_known) - g_signal_emit_by_name (G_OBJECT (self), NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); -} - -static void -udev_device_removed (SettingsPluginIfupdown *self, struct udev_device *device) -{ - SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); - const char *iface, *path; - - iface = udev_device_get_sysname (device); - path = udev_device_get_syspath (device); - if (!iface || !path) - return; - - nm_log_info (LOGD_SETTINGS, "devices removed (path: %s, iface: %s)", path, iface); - - if (!g_hash_table_remove (priv->kernel_ifaces, iface)) - return; - - if (ALWAYS_UNMANAGE || priv->unmanage_well_known) - g_signal_emit_by_name (G_OBJECT (self), NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); -} - -static void -udev_device_changed (SettingsPluginIfupdown *self, struct udev_device *device) -{ - SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); - const char *iface, *path; - - iface = udev_device_get_sysname (device); - path = udev_device_get_syspath (device); - if (!iface || !path) - return; - - nm_log_info (LOGD_SETTINGS, "device changed (path: %s, iface: %s)", path, iface); - - if (!g_hash_table_lookup (priv->kernel_ifaces, iface)) - return; - - if (ALWAYS_UNMANAGE || priv->unmanage_well_known) - g_signal_emit_by_name (G_OBJECT (self), NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); -} - -static void -handle_uevent (NMUdevClient *client, - struct udev_device *device, - gpointer user_data) -{ - SettingsPluginIfupdown *self = SETTINGS_PLUGIN_IFUPDOWN (user_data); - const char *subsys; - const char *action; - - action = udev_device_get_action (device); - - g_return_if_fail (action != NULL); +#define _NMLOG_PREFIX_NAME "ifupdown" +#define _NMLOG_DOMAIN LOGD_SETTINGS +#define _NMLOG(level, ...) \ + nm_log ((level), _NMLOG_DOMAIN, NULL, NULL, \ + "%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME": " \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)) - /* A bit paranoid */ - subsys = udev_device_get_subsystem (device); - g_return_if_fail (nm_streq0 (subsys, "net")); - - if (!strcmp (action, "add")) - udev_device_added (self, device); - else if (!strcmp (action, "remove")) - udev_device_removed (self, device); - else if (!strcmp (action, "change")) - udev_device_changed (self, device); -} +/*****************************************************************************/ /* Returns the plugins currently known list of connections. The returned * list is freed by the system settings service. */ static GSList* -get_connections (NMSettingsPlugin *config) +get_connections (NMSettingsPlugin *plugin) { - SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE ((SettingsPluginIfupdown *) config); - GSList *connections; - - nm_log_info (LOGD_SETTINGS, "(%d) ... get_connections.", GPOINTER_TO_UINT(config)); + SettingsPluginIfupdown *self = SETTINGS_PLUGIN_IFUPDOWN (plugin); + SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); + GSList *list = NULL; + GHashTableIter iter; + void *value; - if(priv->unmanage_well_known) { - nm_log_info (LOGD_SETTINGS, "(%d) ... get_connections (managed=false): return empty list.", GPOINTER_TO_UINT(config)); + if (!priv->ifupdown_managed) { + _LOGD ("get_connections: not connections due to managed=false"); return NULL; } - connections = _nm_utils_hash_values_to_slist (priv->connections); + g_hash_table_iter_init (&iter, priv->eni_ifaces); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + if (value) + list = g_slist_prepend (list, value); + } - nm_log_info (LOGD_SETTINGS, "(%d) connections count: %d", GPOINTER_TO_UINT(config), g_slist_length(connections)); - return connections; + _LOGD ("get_connections: %u connections", g_slist_length (list)); + return list; } /* @@ -270,202 +124,178 @@ get_connections (NMSettingsPlugin *config) * each element must be allocated using g_malloc() or its variants. */ static GSList* -get_unmanaged_specs (NMSettingsPlugin *config) +get_unmanaged_specs (NMSettingsPlugin *plugin) { - SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE ((SettingsPluginIfupdown *) config); + SettingsPluginIfupdown *self = SETTINGS_PLUGIN_IFUPDOWN (plugin); + SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); GSList *specs = NULL; GHashTableIter iter; - struct udev_device *device; const char *iface; - if (!ALWAYS_UNMANAGE && !priv->unmanage_well_known) + if (priv->ifupdown_managed) return NULL; - nm_log_info (LOGD_SETTINGS, "get unmanaged devices count: %d", - g_hash_table_size (priv->kernel_ifaces)); - - g_hash_table_iter_init (&iter, priv->kernel_ifaces); - while (g_hash_table_iter_next (&iter, (gpointer) &iface, (gpointer) &device)) { - const char *address; + _LOGD ("unmanaged-specs: unmanaged devices count %u", + g_hash_table_size (priv->eni_ifaces)); - address = udev_device_get_sysattr_value (device, "address"); - if (address) - specs = g_slist_append (specs, g_strdup_printf ("mac:%s", address)); - else - specs = g_slist_append (specs, g_strdup_printf ("interface-name:%s", iface)); - } + g_hash_table_iter_init (&iter, priv->eni_ifaces); + while (g_hash_table_iter_next (&iter, (gpointer) &iface, NULL)) + specs = g_slist_append (specs, g_strdup_printf ("interface-name:=%s", iface)); return specs; } /*****************************************************************************/ static void -_udev_device_unref (gpointer ptr) +initialize (NMSettingsPlugin *plugin) { - udev_device_unref (ptr); -} - -static void -init (NMSettingsPlugin *config) -{ - SettingsPluginIfupdown *self = SETTINGS_PLUGIN_IFUPDOWN (config); + SettingsPluginIfupdown *self = SETTINGS_PLUGIN_IFUPDOWN (plugin); SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); - GHashTable *auto_ifaces; - if_block *block = NULL; - struct udev_enumerate *enumerate; - struct udev_list_entry *keys; + gs_unref_hashtable GHashTable *auto_ifaces = NULL; + nm_auto_ifparser if_parser *parser = NULL; + if_block *block; GHashTableIter con_iter; const char *block_name; - NMIfupdownConnection *connection; - - auto_ifaces = g_hash_table_new (nm_str_hash, g_str_equal); - - if(!priv->connections) - priv->connections = g_hash_table_new (nm_str_hash, g_str_equal); - - if(!priv->kernel_ifaces) - priv->kernel_ifaces = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, _udev_device_unref); + NMIfupdownConnection *conn; - if(!priv->eni_ifaces) - priv->eni_ifaces = g_hash_table_new (nm_str_hash, g_str_equal); + parser = ifparser_parse (ENI_INTERFACES_FILE, 0); - nm_log_info (LOGD_SETTINGS, "init!"); + c_list_for_each_entry (block, &parser->block_lst_head, block_lst) { - priv->udev_client = nm_udev_client_new ((const char *[]) { "net", NULL }, - handle_uevent, self); - - /* Read in all the interfaces */ - ifparser_init (ENI_INTERFACES_FILE, 0); - block = ifparser_getfirst (); - while (block) { - if(!strcmp ("auto", block->type) || !strcmp ("allow-hotplug", block->type)) - g_hash_table_insert (auto_ifaces, block->name, GUINT_TO_POINTER (1)); - else if (!strcmp ("iface", block->type)) { - NMIfupdownConnection *exported; + if (NM_IN_STRSET (block->type, "auto", "allow-hotplug")) { + if (!auto_ifaces) + auto_ifaces = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, NULL); + g_hash_table_add (auto_ifaces, g_strdup (block->name)); + continue; + } + if (nm_streq (block->type, "iface")) { /* Bridge configuration */ - if(!strncmp ("br", block->name, 2)) { + if (g_str_has_prefix (block_name, "br")) { /* Try to find bridge ports */ const char *ports = ifparser_getkey (block, "bridge-ports"); + if (ports) { - int i; + guint i; int state = 0; - char **port_ifaces; + gs_strfreev char **port_ifaces = NULL; - nm_log_info (LOGD_SETTINGS, "found bridge ports %s for %s", ports, block->name); + _LOGD ("parse: found bridge ports %s for %s", ports, block->name); port_ifaces = g_strsplit_set (ports, " \t", -1); - for (i = 0; i < g_strv_length (port_ifaces); i++) { - char *token = port_ifaces[i]; + for (i = 0; port_ifaces[i]; i++) { + const char *token = port_ifaces[i]; + /* Skip crazy stuff like regex or all */ - if (!strcmp ("all", token)) { + if (nm_streq (token, "all")) continue; - } + /* Small SM to skip everything inside regex */ - if (!strcmp ("regex", token)) { + if (nm_streq (token, "regex")) { state++; continue; } - if (!strcmp ("noregex", token)) { + if (nm_streq (token, "noregex")) { state--; continue; } + if (nm_streq (token, "none")) + continue; if (state == 0 && strlen (token) > 0) { - nm_log_info (LOGD_SETTINGS, "adding bridge port %s to eni_ifaces", token); - g_hash_table_insert (priv->eni_ifaces, g_strdup (token), "known"); + conn = g_hash_table_lookup (priv->eni_ifaces, block->name); + if (!conn) { + _LOGD ("parse: adding bridge port \"%s\"", token); + g_hash_table_insert (priv->eni_ifaces, g_strdup (token), NULL); + } else { + _LOGD ("parse: adding bridge port \"%s\" (have connection %s)", token, + nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (conn))); + } } } - g_strfreev (port_ifaces); } - goto next; + continue; } /* Skip loopback configuration */ - if(!strcmp ("lo", block->name)) { - goto next; - } + if (nm_streq (block->name, "lo")) + continue; /* Remove any connection for this block that was previously found */ - exported = g_hash_table_lookup (priv->connections, block->name); - if (exported) { - nm_log_info (LOGD_SETTINGS, "deleting %s from connections", block->name); - nm_settings_connection_delete (NM_SETTINGS_CONNECTION (exported), NULL); - g_hash_table_remove (priv->connections, block->name); + conn = g_hash_table_lookup (priv->eni_ifaces, block->name); + if (conn) { + _LOGD ("parse: replace connection \"%s\" (%s)", + block->name, + nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (conn))); + nm_settings_connection_delete (NM_SETTINGS_CONNECTION (conn), NULL); + g_hash_table_remove (priv->eni_ifaces, block->name); } /* add the new connection */ - exported = nm_ifupdown_connection_new (block); - if (exported) { - nm_log_info (LOGD_SETTINGS, "adding %s to connections", block->name); - g_hash_table_insert (priv->connections, block->name, exported); + conn = nm_ifupdown_connection_new (block); + if (conn) { + _LOGD ("parse: adding connection \"%s\" (%s)", block->name, + nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (conn))); + } else + _LOGD ("parse: adding place holder for connection \"%s\"", block->name); + g_hash_table_insert (priv->eni_ifaces, g_strdup (block->name), conn); + continue; + } + + if (nm_streq (block->type, "mapping")) { + conn = g_hash_table_lookup (priv->eni_ifaces, block->name); + if (!conn) { + _LOGD ("parse: adding mapping \"%s\"", block->name); + g_hash_table_insert (priv->eni_ifaces, g_strdup (block->name), NULL); + } else { + _LOGD ("parse: adding mapping \"%s\" (have connection %s)", block->name, + nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (conn))); } - nm_log_info (LOGD_SETTINGS, "adding iface %s to eni_ifaces", block->name); - g_hash_table_insert (priv->eni_ifaces, block->name, "known"); - } else if (!strcmp ("mapping", block->type)) { - g_hash_table_insert (priv->eni_ifaces, block->name, "known"); - nm_log_info (LOGD_SETTINGS, "adding mapping %s to eni_ifaces", block->name); + continue; } - next: - block = block->next; } /* Make 'auto' interfaces autoconnect=TRUE */ - g_hash_table_iter_init (&con_iter, priv->connections); - while (g_hash_table_iter_next (&con_iter, (gpointer) &block_name, (gpointer) &connection)) { + g_hash_table_iter_init (&con_iter, priv->eni_ifaces); + while (g_hash_table_iter_next (&con_iter, (gpointer) &block_name, (gpointer) &conn)) { NMSettingConnection *setting; - if (g_hash_table_lookup (auto_ifaces, block_name)) { - setting = nm_connection_get_setting_connection (NM_CONNECTION (connection)); - g_object_set (setting, NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NULL); - nm_log_info (LOGD_SETTINGS, "autoconnect"); - } + if ( !conn + || !auto_ifaces + || !g_hash_table_contains (auto_ifaces, block_name)) + continue; + + /* FIXME(copy-on-write-connection): avoid modifying NMConnection instances and share them via copy-on-write. */ + setting = nm_connection_get_setting_connection (nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (conn))); + g_object_set (setting, NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NULL); } - g_hash_table_destroy (auto_ifaces); /* Check the config file to find out whether to manage interfaces */ - priv->unmanage_well_known = !nm_config_data_get_value_boolean (NM_CONFIG_GET_DATA_ORIG, - NM_CONFIG_KEYFILE_GROUP_IFUPDOWN, - NM_CONFIG_KEYFILE_KEY_IFUPDOWN_MANAGED, - !IFUPDOWN_UNMANAGE_WELL_KNOWN_DEFAULT); - nm_log_info (LOGD_SETTINGS, "management mode: %s", priv->unmanage_well_known ? "unmanaged" : "managed"); - - /* Add well-known interfaces */ - enumerate = nm_udev_client_enumerate_new (priv->udev_client); - udev_enumerate_scan_devices (enumerate); - keys = udev_enumerate_get_list_entry (enumerate); - for (; keys; keys = udev_list_entry_get_next (keys)) { - struct udev_device *udevice; - - udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate), - udev_list_entry_get_name (keys)); - if (udevice) { - udev_device_added (self, udevice); - udev_device_unref (udevice); - } - } - udev_enumerate_unref (enumerate); + priv->ifupdown_managed = nm_config_data_get_value_boolean (NM_CONFIG_GET_DATA_ORIG, + NM_CONFIG_KEYFILE_GROUP_IFUPDOWN, + NM_CONFIG_KEYFILE_KEY_IFUPDOWN_MANAGED, + !IFUPDOWN_UNMANAGE_WELL_KNOWN_DEFAULT); + _LOGI ("management mode: %s", priv->ifupdown_managed ? "managed" : "unmanaged"); /* Now if we're running in managed mode, let NM know there are new connections */ - if (!priv->unmanage_well_known) { - GList *con_list = g_hash_table_get_values (priv->connections); - GList *cl_iter; - - for (cl_iter = con_list; cl_iter; cl_iter = g_list_next (cl_iter)) { - g_signal_emit_by_name (self, - NM_SETTINGS_PLUGIN_CONNECTION_ADDED, - NM_SETTINGS_CONNECTION (cl_iter->data)); + if (priv->ifupdown_managed) { + GHashTableIter iter; + + g_hash_table_iter_init (&iter, priv->eni_ifaces); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) conn)) { + _nm_settings_plugin_emit_signal_connection_added (NM_SETTINGS_PLUGIN (self), + NM_SETTINGS_CONNECTION (conn)); } - g_list_free (con_list); } - - nm_log_info (LOGD_SETTINGS, "end _init."); } /*****************************************************************************/ static void -settings_plugin_ifupdown_init (SettingsPluginIfupdown *plugin) +settings_plugin_ifupdown_init (SettingsPluginIfupdown *self) { + SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); + + priv->eni_ifaces = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref); } static void @@ -474,35 +304,28 @@ dispose (GObject *object) SettingsPluginIfupdown *plugin = SETTINGS_PLUGIN_IFUPDOWN (object); SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (plugin); - g_clear_pointer (&priv->kernel_ifaces, g_hash_table_destroy); g_clear_pointer (&priv->eni_ifaces, g_hash_table_destroy); - priv->udev_client = nm_udev_client_unref (priv->udev_client); - G_OBJECT_CLASS (settings_plugin_ifupdown_parent_class)->dispose (object); } static void -settings_plugin_ifupdown_class_init (SettingsPluginIfupdownClass *req_class) +settings_plugin_ifupdown_class_init (SettingsPluginIfupdownClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (req_class); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMSettingsPluginClass *plugin_class = NM_SETTINGS_PLUGIN_CLASS (klass); object_class->dispose = dispose; -} -static void -settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) -{ - plugin_iface->init = init; - plugin_iface->get_connections = get_connections; - plugin_iface->get_unmanaged_specs = get_unmanaged_specs; + plugin_class->initialize = initialize; + plugin_class->get_connections = get_connections; + plugin_class->get_unmanaged_specs = get_unmanaged_specs; } /*****************************************************************************/ -G_MODULE_EXPORT GObject * +G_MODULE_EXPORT NMSettingsPlugin * nm_settings_plugin_factory (void) { - return G_OBJECT (g_object_ref (settings_plugin_ifupdown_get ())); + return NM_SETTINGS_PLUGIN (g_object_ref (settings_plugin_ifupdown_get ())); } - diff --git a/src/settings/plugins/ifupdown/tests/meson.build b/src/settings/plugins/ifupdown/tests/meson.build index ee3b6a34..5a2383d9 100644 --- a/src/settings/plugins/ifupdown/tests/meson.build +++ b/src/settings/plugins/ifupdown/tests/meson.build @@ -4,7 +4,6 @@ exe = executable( test_unit, test_unit + '.c', dependencies: test_nm_dep, - c_args: nm_build_cflags, link_with: libnms_ifupdown_core ) diff --git a/src/settings/plugins/ifupdown/tests/test-ifupdown.c b/src/settings/plugins/ifupdown/tests/test-ifupdown.c index 18bad65e..82ee1c4a 100644 --- a/src/settings/plugins/ifupdown/tests/test-ifupdown.c +++ b/src/settings/plugins/ifupdown/tests/test-ifupdown.c @@ -130,46 +130,50 @@ expected_free (Expected *e) } static void -compare_expected_to_ifparser (Expected *e) +compare_expected_to_ifparser (if_parser *parser, Expected *e) { if_block *n; GSList *biter, *kiter; - g_assert_cmpint (g_slist_length (e->blocks), ==, ifparser_get_num_blocks ()); + g_assert_cmpint (g_slist_length (e->blocks), ==, ifparser_get_num_blocks (parser)); - for (n = ifparser_getfirst (), biter = e->blocks; - n && biter; - n = n->next, biter = g_slist_next (biter)) { + biter = e->blocks; + c_list_for_each_entry (n, &parser->block_lst_head, block_lst) { if_data *m; ExpectedBlock *b = biter->data; g_assert (b->type && n->type); g_assert_cmpstr (b->type, ==, n->type); - g_assert (b->name && n->name); + g_assert (b->name); g_assert_cmpstr (b->name, ==, n->name); g_assert_cmpint (g_slist_length (b->keys), ==, ifparser_get_num_info (n)); - for (m = n->info, kiter = b->keys; - m && kiter; - m = m->next, kiter = g_slist_next (kiter)) { + kiter = b->keys; + c_list_for_each_entry (m, &n->data_lst_head, data_lst) { ExpectedKey *k = kiter->data; - g_assert (k->key && m->key); + g_assert (k->key); g_assert_cmpstr (k->key, ==, m->key); g_assert (k->data && m->data); g_assert_cmpstr (k->data, ==, m->data); + + kiter = g_slist_next (kiter); } + g_assert (!kiter); + + biter = g_slist_next (biter); } + g_assert (!biter); } static void -dump_blocks (void) +dump_blocks (if_parser *parser) { if_block *n; g_message ("\n***************************************************"); - for (n = ifparser_getfirst (); n != NULL; n = n->next) { + c_list_for_each_entry (n, &parser->block_lst_head, block_lst) { if_data *m; // each block start with its type & name @@ -178,8 +182,8 @@ dump_blocks (void) // each key-value pair within a block is indented & separated by a tab // (single quotes used to show typ & name baoundaries) - for (m = n->info; m != NULL; m = m->next) - g_print("\t'%s'\t'%s'\n", m->key, m->data); + c_list_for_each_entry (m, &n->data_lst_head, data_lst) + g_print("\t'%s'\t'%s'\n", m->key, m->data); // blocks are separated by an empty line g_print("\n"); @@ -187,21 +191,24 @@ dump_blocks (void) g_message ("##################################################\n"); } -static void -init_ifparser_with_file (const char *path, const char *file) +static if_parser * +init_ifparser_with_file (const char *file) { - char *tmp; + if_parser *parser; + gs_free char *tmp = NULL; - tmp = g_strdup_printf ("%s/%s", path, file); - ifparser_init (tmp, 1); - g_free (tmp); + tmp = g_strdup_printf ("%s/%s", TEST_DIR, file); + parser = ifparser_parse (tmp, 1); + g_assert (parser); + return parser; } static void -test1_ignore_line_before_first_block (const char *path) +test1_ignore_line_before_first_block (void) { Expected *e; ExpectedBlock *b; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test1"); e = expected_new (); b = expected_block_new ("auto", "eth0"); @@ -210,35 +217,33 @@ test1_ignore_line_before_first_block (const char *path) expected_add_block (e, b); expected_block_add_key (b, expected_key_new ("inet", "dhcp")); - init_ifparser_with_file (path, "test1"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } static void -test2_wrapped_line (const char *path) +test2_wrapped_line (void) { Expected *e; ExpectedBlock *b; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test2"); e = expected_new (); b = expected_block_new ("auto", "lo"); expected_add_block (e, b); - init_ifparser_with_file (path, "test2"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } static void -test3_wrapped_multiline_multiarg (const char *path) +test3_wrapped_multiline_multiarg (void) { Expected *e; ExpectedBlock *b; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test3"); e = expected_new (); b = expected_block_new ("allow-hotplug", "eth0"); @@ -248,35 +253,33 @@ test3_wrapped_multiline_multiarg (const char *path) b = expected_block_new ("allow-hotplug", "bnep0"); expected_add_block (e, b); - init_ifparser_with_file (path, "test3"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } static void -test4_allow_auto_is_auto (const char *path) +test4_allow_auto_is_auto (void) { Expected *e; ExpectedBlock *b; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test4"); e = expected_new (); b = expected_block_new ("auto", "eth0"); expected_add_block (e, b); - init_ifparser_with_file (path, "test4"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } static void -test5_allow_auto_multiarg (const char *path) +test5_allow_auto_multiarg (void) { Expected *e; ExpectedBlock *b; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test5"); e = expected_new (); b = expected_block_new ("allow-hotplug", "eth0"); @@ -284,52 +287,50 @@ test5_allow_auto_multiarg (const char *path) b = expected_block_new ("allow-hotplug", "wlan0"); expected_add_block (e, b); - init_ifparser_with_file (path, "test5"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } static void -test6_mixed_whitespace (const char *path) +test6_mixed_whitespace (void) { Expected *e; ExpectedBlock *b; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test6"); e = expected_new (); b = expected_block_new ("iface", "lo"); expected_block_add_key (b, expected_key_new ("inet", "loopback")); expected_add_block (e, b); - init_ifparser_with_file (path, "test6"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } static void -test7_long_line (const char *path) +test7_long_line (void) { - init_ifparser_with_file (path, "test7"); - g_assert_cmpint (ifparser_get_num_blocks (), ==, 0); - ifparser_destroy (); + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test7"); + + g_assert_cmpint (ifparser_get_num_blocks (parser), ==, 0); } static void -test8_long_line_wrapped (const char *path) +test8_long_line_wrapped (void) { - init_ifparser_with_file (path, "test8"); - g_assert_cmpint (ifparser_get_num_blocks (), ==, 0); - ifparser_destroy (); + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test8"); + + g_assert_cmpint (ifparser_get_num_blocks (parser), ==, 0); } static void -test9_wrapped_lines_in_block (const char *path) +test9_wrapped_lines_in_block (void) { Expected *e; ExpectedBlock *b; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test9"); e = expected_new (); b = expected_block_new ("iface", "eth0"); @@ -340,18 +341,17 @@ test9_wrapped_lines_in_block (const char *path) expected_block_add_key (b, expected_key_new ("broadcast", "10.250.2.63")); expected_block_add_key (b, expected_key_new ("gateway", "10.250.2.50")); - init_ifparser_with_file (path, "test9"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } static void -test11_complex_wrap (const char *path) +test11_complex_wrap (void) { Expected *e; ExpectedBlock *b; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test11"); e = expected_new (); b = expected_block_new ("iface", "pppoe"); @@ -359,18 +359,17 @@ test11_complex_wrap (const char *path) expected_block_add_key (b, expected_key_new ("inet", "manual")); expected_block_add_key (b, expected_key_new ("pre-up", "/sbin/ifconfig eth0 up")); - init_ifparser_with_file (path, "test11"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } static void -test12_complex_wrap_split_word (const char *path) +test12_complex_wrap_split_word (void) { Expected *e; ExpectedBlock *b; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test12"); e = expected_new (); b = expected_block_new ("iface", "pppoe"); @@ -378,36 +377,34 @@ test12_complex_wrap_split_word (const char *path) expected_block_add_key (b, expected_key_new ("inet", "manual")); expected_block_add_key (b, expected_key_new ("up", "ifup ppp0=dsl")); - init_ifparser_with_file (path, "test12"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } static void -test13_more_mixed_whitespace (const char *path) +test13_more_mixed_whitespace (void) { Expected *e; ExpectedBlock *b; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test13"); e = expected_new (); b = expected_block_new ("iface", "dsl"); expected_block_add_key (b, expected_key_new ("inet", "ppp")); expected_add_block (e, b); - init_ifparser_with_file (path, "test13"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } static void -test14_mixed_whitespace_block_start (const char *path) +test14_mixed_whitespace_block_start (void) { Expected *e; ExpectedBlock *b; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test14"); e = expected_new (); b = expected_block_new ("iface", "wlan0"); @@ -420,47 +417,43 @@ test14_mixed_whitespace_block_start (const char *path) expected_block_add_key (b, expected_key_new ("inet", "dhcp")); expected_add_block (e, b); - init_ifparser_with_file (path, "test14"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } static void -test15_trailing_space (const char *path) +test15_trailing_space (void) { Expected *e; ExpectedBlock *b; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test15"); e = expected_new (); b = expected_block_new ("iface", "bnep0"); expected_block_add_key (b, expected_key_new ("inet", "static")); expected_add_block (e, b); - init_ifparser_with_file (path, "test15"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } static void -test16_missing_newline (const char *path) +test16_missing_newline (void) { Expected *e; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test16"); e = expected_new (); expected_add_block (e, expected_block_new ("mapping", "eth0")); - init_ifparser_with_file (path, "test16"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } static void -test17_read_static_ipv4 (const char *path) +test17_read_static_ipv4 (void) { NMConnection *connection; NMSettingConnection *s_con; @@ -470,13 +463,13 @@ test17_read_static_ipv4 (const char *path) gboolean success; NMIPAddress *ip4_addr; if_block *block = NULL; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test17-wired-static-verify-ip4"); - init_ifparser_with_file (path, "test17-wired-static-verify-ip4"); - block = ifparser_getfirst (); + block = ifparser_getfirst (parser); connection = nm_simple_connection_new(); g_assert (connection); - ifupdown_update_connection_from_if_block(connection, block, &error); + ifupdown_update_connection_from_if_block (connection, block, &error); g_assert_no_error (error); success = nm_connection_verify (connection, &error); @@ -511,12 +504,11 @@ test17_read_static_ipv4 (const char *path) g_assert_cmpstr (nm_setting_ip_config_get_dns_search (s_ip4, 0), ==, "example.com"); g_assert_cmpstr (nm_setting_ip_config_get_dns_search (s_ip4, 1), ==, "foo.example.com"); - ifparser_destroy (); g_object_unref (connection); } static void -test18_read_static_ipv6 (const char *path) +test18_read_static_ipv6 (void) { NMConnection *connection; NMSettingConnection *s_con; @@ -526,12 +518,12 @@ test18_read_static_ipv6 (const char *path) gboolean success; NMIPAddress *ip6_addr; if_block *block = NULL; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test18-wired-static-verify-ip6"); - init_ifparser_with_file (path, "test18-wired-static-verify-ip6"); - block = ifparser_getfirst (); + block = ifparser_getfirst (parser); connection = nm_simple_connection_new(); g_assert (connection); - ifupdown_update_connection_from_if_block(connection, block, &error); + ifupdown_update_connection_from_if_block (connection, block, &error); g_assert_no_error (error); success = nm_connection_verify (connection, &error); @@ -566,12 +558,11 @@ test18_read_static_ipv6 (const char *path) g_assert_cmpstr (nm_setting_ip_config_get_dns_search (s_ip6, 0), ==, "example.com"); g_assert_cmpstr (nm_setting_ip_config_get_dns_search (s_ip6, 1), ==, "foo.example.com"); - ifparser_destroy (); g_object_unref (connection); } static void -test19_read_static_ipv4_plen (const char *path) +test19_read_static_ipv4_plen (void) { NMConnection *connection; NMSettingIPConfig *s_ip4; @@ -579,12 +570,12 @@ test19_read_static_ipv4_plen (const char *path) NMIPAddress *ip4_addr; if_block *block = NULL; gboolean success; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test19-wired-static-verify-ip4-plen"); - init_ifparser_with_file (path, "test19-wired-static-verify-ip4-plen"); - block = ifparser_getfirst (); + block = ifparser_getfirst (parser); connection = nm_simple_connection_new(); g_assert (connection); - ifupdown_update_connection_from_if_block(connection, block, &error); + ifupdown_update_connection_from_if_block (connection, block, &error); g_assert_no_error (error); success = nm_connection_verify (connection, &error); @@ -601,15 +592,15 @@ test19_read_static_ipv4_plen (const char *path) g_assert_cmpstr (nm_ip_address_get_address (ip4_addr), ==, "10.0.0.3"); g_assert_cmpint (nm_ip_address_get_prefix (ip4_addr), ==, 8); - ifparser_destroy (); g_object_unref (connection); } static void -test20_source_stanza (const char *path) +test20_source_stanza (void) { Expected *e; ExpectedBlock *b; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test20-source-stanza"); e = expected_new (); @@ -625,18 +616,17 @@ test20_source_stanza (const char *path) expected_add_block (e, b); expected_block_add_key (b, expected_key_new ("inet", "dhcp")); - init_ifparser_with_file (path, "test20-source-stanza"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } static void -test21_source_dir_stanza (const char *path) +test21_source_dir_stanza (void) { Expected *e; ExpectedBlock *b; + nm_auto_ifparser if_parser *parser = init_ifparser_with_file ("test21-source-dir-stanza"); e = expected_new (); @@ -646,10 +636,8 @@ test21_source_dir_stanza (const char *path) expected_add_block (e, b); expected_block_add_key (b, expected_key_new ("inet", "dhcp")); - init_ifparser_with_file (path, "test21-source-dir-stanza"); - compare_expected_to_ifparser (e); + compare_expected_to_ifparser (parser, e); - ifparser_destroy (); expected_free (e); } @@ -660,49 +648,28 @@ main (int argc, char **argv) { nmtst_init_assert_logging (&argc, &argv, "WARN", "DEFAULT"); - if (0) - dump_blocks (); - - g_test_add_data_func ("/ifupdate/ignore_line_before_first_block", TEST_DIR, - (GTestDataFunc) test1_ignore_line_before_first_block); - g_test_add_data_func ("/ifupdate/wrapped_line", TEST_DIR, - (GTestDataFunc) test2_wrapped_line); - g_test_add_data_func ("/ifupdate/wrapped_multiline_multiarg", TEST_DIR, - (GTestDataFunc) test3_wrapped_multiline_multiarg); - g_test_add_data_func ("/ifupdate/allow_auto_is_auto", TEST_DIR, - (GTestDataFunc) test4_allow_auto_is_auto); - g_test_add_data_func ("/ifupdate/allow_auto_multiarg", TEST_DIR, - (GTestDataFunc) test5_allow_auto_multiarg); - g_test_add_data_func ("/ifupdate/mixed_whitespace", TEST_DIR, - (GTestDataFunc) test6_mixed_whitespace); - g_test_add_data_func ("/ifupdate/long_line", TEST_DIR, - (GTestDataFunc) test7_long_line); - g_test_add_data_func ("/ifupdate/long_line_wrapped", TEST_DIR, - (GTestDataFunc) test8_long_line_wrapped); - g_test_add_data_func ("/ifupdate/wrapped_lines_in_block", TEST_DIR, - (GTestDataFunc) test9_wrapped_lines_in_block); - g_test_add_data_func ("/ifupdate/complex_wrap", TEST_DIR, - (GTestDataFunc) test11_complex_wrap); - g_test_add_data_func ("/ifupdate/complex_wrap_split_word", TEST_DIR, - (GTestDataFunc) test12_complex_wrap_split_word); - g_test_add_data_func ("/ifupdate/more_mixed_whitespace", TEST_DIR, - (GTestDataFunc) test13_more_mixed_whitespace); - g_test_add_data_func ("/ifupdate/mixed_whitespace_block_start", TEST_DIR, - (GTestDataFunc) test14_mixed_whitespace_block_start); - g_test_add_data_func ("/ifupdate/trailing_space", TEST_DIR, - (GTestDataFunc) test15_trailing_space); - g_test_add_data_func ("/ifupdate/missing_newline", TEST_DIR, - (GTestDataFunc) test16_missing_newline); - g_test_add_data_func ("/ifupdate/read_static_ipv4", TEST_DIR, - (GTestDataFunc) test17_read_static_ipv4); - g_test_add_data_func ("/ifupdate/read_static_ipv6", TEST_DIR, - (GTestDataFunc) test18_read_static_ipv6); - g_test_add_data_func ("/ifupdate/read_static_ipv4_plen", TEST_DIR, - (GTestDataFunc) test19_read_static_ipv4_plen); - g_test_add_data_func ("/ifupdate/source_stanza", TEST_DIR, - (GTestDataFunc) test20_source_stanza); - g_test_add_data_func ("/ifupdate/source_dir_stanza", TEST_DIR, - (GTestDataFunc) test21_source_dir_stanza); + (void) dump_blocks; + + g_test_add_func ("/ifupdate/ignore_line_before_first_block", test1_ignore_line_before_first_block); + g_test_add_func ("/ifupdate/wrapped_line", test2_wrapped_line); + g_test_add_func ("/ifupdate/wrapped_multiline_multiarg", test3_wrapped_multiline_multiarg); + g_test_add_func ("/ifupdate/allow_auto_is_auto", test4_allow_auto_is_auto); + g_test_add_func ("/ifupdate/allow_auto_multiarg", test5_allow_auto_multiarg); + g_test_add_func ("/ifupdate/mixed_whitespace", test6_mixed_whitespace); + g_test_add_func ("/ifupdate/long_line", test7_long_line); + g_test_add_func ("/ifupdate/long_line_wrapped", test8_long_line_wrapped); + g_test_add_func ("/ifupdate/wrapped_lines_in_block", test9_wrapped_lines_in_block); + g_test_add_func ("/ifupdate/complex_wrap", test11_complex_wrap); + g_test_add_func ("/ifupdate/complex_wrap_split_word", test12_complex_wrap_split_word); + g_test_add_func ("/ifupdate/more_mixed_whitespace", test13_more_mixed_whitespace); + g_test_add_func ("/ifupdate/mixed_whitespace_block_start", test14_mixed_whitespace_block_start); + g_test_add_func ("/ifupdate/trailing_space", test15_trailing_space); + g_test_add_func ("/ifupdate/missing_newline", test16_missing_newline); + g_test_add_func ("/ifupdate/read_static_ipv4", test17_read_static_ipv4); + g_test_add_func ("/ifupdate/read_static_ipv6", test18_read_static_ipv6); + g_test_add_func ("/ifupdate/read_static_ipv4_plen", test19_read_static_ipv4_plen); + g_test_add_func ("/ifupdate/source_stanza", test20_source_stanza); + g_test_add_func ("/ifupdate/source_dir_stanza", test21_source_dir_stanza); return g_test_run (); } diff --git a/src/settings/plugins/keyfile/nms-keyfile-connection.c b/src/settings/plugins/keyfile/nms-keyfile-connection.c index 5f72a9fa..7511f206 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-connection.c +++ b/src/settings/plugins/keyfile/nms-keyfile-connection.c @@ -66,6 +66,7 @@ commit_changes (NMSettingsConnection *connection, nm_assert (!out_logmsg_change || !*out_logmsg_change); if (!nms_keyfile_writer_connection (new_connection, + TRUE, nm_settings_connection_get_filename (connection), NM_FLAGS_ALL (commit_reason, NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION | NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED), @@ -75,9 +76,7 @@ commit_changes (NMSettingsConnection *connection, error)) return FALSE; - /* Update the filename if it changed */ - if ( path - && g_strcmp0 (path, nm_settings_connection_get_filename (connection)) != 0) { + if (!nm_streq0 (path, nm_settings_connection_get_filename (connection))) { gs_free char *old_path = g_strdup (nm_settings_connection_get_filename (connection)); nm_settings_connection_set_filename (connection, path); @@ -125,6 +124,7 @@ nms_keyfile_connection_init (NMSKeyfileConnection *connection) NMSKeyfileConnection * nms_keyfile_connection_new (NMConnection *source, const char *full_path, + const char *profile_dir, GError **error) { GObject *object; @@ -132,17 +132,19 @@ nms_keyfile_connection_new (NMConnection *source, const char *uuid; gboolean update_unsaved = TRUE; - g_assert (source || full_path); + nm_assert (source || full_path); + nm_assert (!full_path || full_path[0] == '/'); + nm_assert (!profile_dir || profile_dir[0] == '/'); /* If we're given a connection already, prefer that instead of re-reading */ if (source) tmp = g_object_ref (source); else { - tmp = nms_keyfile_reader_from_file (full_path, error); + tmp = nms_keyfile_reader_from_file (full_path, profile_dir, error); if (!tmp) return NULL; - uuid = nm_connection_get_uuid (NM_CONNECTION (tmp)); + uuid = nm_connection_get_uuid (tmp); if (!uuid) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Connection in file %s had no UUID", full_path); @@ -154,9 +156,9 @@ nms_keyfile_connection_new (NMConnection *source, update_unsaved = FALSE; } - object = (GObject *) g_object_new (NMS_TYPE_KEYFILE_CONNECTION, - NM_SETTINGS_CONNECTION_FILENAME, full_path, - NULL); + object = g_object_new (NMS_TYPE_KEYFILE_CONNECTION, + NM_SETTINGS_CONNECTION_FILENAME, full_path, + NULL); /* Update our settings with what was read from the file */ if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (object), diff --git a/src/settings/plugins/keyfile/nms-keyfile-connection.h b/src/settings/plugins/keyfile/nms-keyfile-connection.h index f96d7590..0773ced0 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-connection.h +++ b/src/settings/plugins/keyfile/nms-keyfile-connection.h @@ -37,7 +37,8 @@ typedef struct _NMSKeyfileConnectionClass NMSKeyfileConnectionClass; GType nms_keyfile_connection_get_type (void); NMSKeyfileConnection *nms_keyfile_connection_new (NMConnection *source, - const char *filename, + const char *full_path, + const char *profile_dir, GError **error); #endif /* __NMS_KEYFILE_CONNECTION_H__ */ diff --git a/src/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/settings/plugins/keyfile/nms-keyfile-plugin.c index 3723db94..346b78c0 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-plugin.c +++ b/src/settings/plugins/keyfile/nms-keyfile-plugin.c @@ -56,19 +56,15 @@ typedef struct { } NMSKeyfilePluginPrivate; struct _NMSKeyfilePlugin { - GObject parent; + NMSettingsPlugin parent; NMSKeyfilePluginPrivate _priv; }; struct _NMSKeyfilePluginClass { - GObjectClass parent; + NMSettingsPluginClass parent; }; -static void settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface); - -G_DEFINE_TYPE_EXTENDED (NMSKeyfilePlugin, nms_keyfile_plugin, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN, - settings_plugin_interface_init)) +G_DEFINE_TYPE (NMSKeyfilePlugin, nms_keyfile_plugin, NM_TYPE_SETTINGS_PLUGIN) #define NMS_KEYFILE_PLUGIN_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSKeyfilePlugin, NMS_IS_KEYFILE_PLUGIN) @@ -85,10 +81,10 @@ G_DEFINE_TYPE_EXTENDED (NMSKeyfilePlugin, nms_keyfile_plugin, G_TYPE_OBJECT, 0, /*****************************************************************************/ static void -connection_removed_cb (NMSettingsConnection *obj, gpointer user_data) +connection_removed_cb (NMSettingsConnection *sett_conn, NMSKeyfilePlugin *self) { - g_hash_table_remove (NMS_KEYFILE_PLUGIN_GET_PRIVATE ((NMSKeyfilePlugin *) user_data)->connections, - nm_connection_get_uuid (NM_CONNECTION (obj))); + g_hash_table_remove (NMS_KEYFILE_PLUGIN_GET_PRIVATE (self)->connections, + nm_settings_connection_get_uuid (sett_conn)); } /* Monitoring */ @@ -106,7 +102,7 @@ remove_connection (NMSKeyfilePlugin *self, NMSKeyfileConnection *connection) g_object_ref (connection); g_signal_handlers_disconnect_by_func (connection, connection_removed_cb, self); removed = g_hash_table_remove (NMS_KEYFILE_PLUGIN_GET_PRIVATE (self)->connections, - nm_connection_get_uuid (NM_CONNECTION (connection))); + nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (connection))); nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection)); g_object_unref (connection); @@ -175,6 +171,7 @@ update_connection (NMSKeyfilePlugin *self, NMSKeyfileConnection *connection_by_uuid; GError *local = NULL; const char *uuid; + int dir_len; g_return_val_if_fail (!source || NM_IS_CONNECTION (source), NULL); g_return_val_if_fail (full_path || source, NULL); @@ -182,7 +179,23 @@ update_connection (NMSKeyfilePlugin *self, if (full_path) _LOGD ("loading from file \"%s\"...", full_path); - connection_new = nms_keyfile_connection_new (source, full_path, &local); + if (g_str_has_prefix (full_path, nms_keyfile_utils_get_path ())) { + dir_len = strlen (nms_keyfile_utils_get_path ()); + } else if (g_str_has_prefix (full_path, NM_CONFIG_KEYFILE_PATH_IN_MEMORY)) { + dir_len = NM_STRLEN (NM_CONFIG_KEYFILE_PATH_IN_MEMORY); + } else { + /* Just make sure the file name is not going go pass the following check. */ + dir_len = strlen (full_path); + } + + if ( full_path[dir_len] != '/' + || strchr (full_path + dir_len + 1, '/') != NULL) { + g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "File not in recognized system-connections directory"); + return FALSE; + } + + connection_new = nms_keyfile_connection_new (source, full_path, nms_keyfile_utils_get_path (), &local); if (!connection_new) { /* Error; remove the connection */ if (source) @@ -197,7 +210,7 @@ update_connection (NMSKeyfilePlugin *self, return NULL; } - uuid = nm_connection_get_uuid (NM_CONNECTION (connection_new)); + uuid = nm_settings_connection_get_uuid (NM_SETTINGS_CONNECTION (connection_new)); connection_by_uuid = g_hash_table_lookup (priv->connections, uuid); if ( connection @@ -240,8 +253,8 @@ update_connection (NMSKeyfilePlugin *self, old_path = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection_by_uuid)); - if (nm_connection_compare (NM_CONNECTION (connection_by_uuid), - NM_CONNECTION (connection_new), + if (nm_connection_compare (nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (connection_by_uuid)), + nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (connection_new)), NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS | NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) { /* Nothing to do... except updating the path. */ @@ -259,7 +272,7 @@ update_connection (NMSKeyfilePlugin *self, _LOGI ("update and persist "NMS_KEYFILE_CONNECTION_LOG_FMT, NMS_KEYFILE_CONNECTION_LOG_ARG (connection_new)); if (!nm_settings_connection_update (NM_SETTINGS_CONNECTION (connection_by_uuid), - NM_CONNECTION (connection_new), + nm_settings_connection_get_connection (NM_SETTINGS_CONNECTION (connection_new)), NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP_SAVED, NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, "keyfile-update", @@ -287,8 +300,10 @@ update_connection (NMSKeyfilePlugin *self, if (!source) { /* Only raise the signal if we were called without source, i.e. if we read the connection from file. * Otherwise, we were called by add_connection() which does not expect the signal. */ - g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, connection_new); + _nm_settings_plugin_emit_signal_connection_added (NM_SETTINGS_PLUGIN (self), + NM_SETTINGS_CONNECTION (connection_new)); } + return connection_new; } } @@ -307,7 +322,7 @@ dir_changed (GFileMonitor *monitor, gboolean exists; full_path = g_file_get_path (file); - if (nms_keyfile_utils_should_ignore_file (full_path)) { + if (nms_keyfile_utils_should_ignore_file (full_path, FALSE)) { g_free (full_path); return; } @@ -341,13 +356,14 @@ config_changed_cb (NMConfig *config, NMConfigData *old_data, NMSKeyfilePlugin *self) { - gs_free char *old_value = NULL, *new_value = NULL; + gs_free char *old_value = NULL; + gs_free char *new_value = NULL; old_value = nm_config_data_get_value (old_data, NM_CONFIG_KEYFILE_GROUP_KEYFILE, NM_CONFIG_KEYFILE_KEY_KEYFILE_UNMANAGED_DEVICES, NM_CONFIG_GET_VALUE_TYPE_SPEC); new_value = nm_config_data_get_value (config_data, NM_CONFIG_KEYFILE_GROUP_KEYFILE, NM_CONFIG_KEYFILE_KEY_KEYFILE_UNMANAGED_DEVICES, NM_CONFIG_GET_VALUE_TYPE_SPEC); - if (g_strcmp0 (old_value, new_value) != 0) - g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); + if (!nm_streq0 (old_value, new_value)) + _nm_settings_plugin_emit_signal_unmanaged_specs_changed (NM_SETTINGS_PLUGIN (self)); } static void @@ -412,13 +428,35 @@ _sort_paths (const char **f1, const char **f2, GHashTable *paths) } static void +_read_dir (GPtrArray *filenames, + const char *path, + gboolean require_extension) +{ + GDir *dir; + const char *item; + GError *error = NULL; + + dir = g_dir_open (path, 0, &error); + if (!dir) { + _LOGD ("cannot read directory '%s': %s", path, error->message); + g_clear_error (&error); + return; + } + + while ((item = g_dir_read_name (dir))) { + if (nms_keyfile_utils_should_ignore_file (item, require_extension)) + continue; + g_ptr_array_add (filenames, g_build_filename (path, item, NULL)); + } + g_dir_close (dir); +} + + +static void read_connections (NMSettingsPlugin *config) { NMSKeyfilePlugin *self = NMS_KEYFILE_PLUGIN (config); NMSKeyfilePluginPrivate *priv = NMS_KEYFILE_PLUGIN_GET_PRIVATE (self); - GDir *dir; - GError *error = NULL; - const char *item; GHashTable *alive_connections; GHashTableIter iter; NMSKeyfileConnection *connection; @@ -427,24 +465,12 @@ read_connections (NMSettingsPlugin *config) GPtrArray *filenames; GHashTable *paths; - dir = g_dir_open (nms_keyfile_utils_get_path (), 0, &error); - if (!dir) { - _LOGW ("cannot read directory '%s': %s", - nms_keyfile_utils_get_path (), - error->message); - g_clear_error (&error); - return; - } + filenames = g_ptr_array_new_with_free_func (g_free); - alive_connections = g_hash_table_new (nm_direct_hash, NULL); + _read_dir (filenames, NM_CONFIG_KEYFILE_PATH_IN_MEMORY, TRUE); + _read_dir (filenames, nms_keyfile_utils_get_path (), FALSE); - filenames = g_ptr_array_new_with_free_func (g_free); - while ((item = g_dir_read_name (dir))) { - if (nms_keyfile_utils_should_ignore_file (item)) - continue; - g_ptr_array_add (filenames, g_build_filename (nms_keyfile_utils_get_path (), item, NULL)); - } - g_dir_close (dir); + alive_connections = g_hash_table_new (nm_direct_hash, NULL); /* While reloading, we don't replace connections that we already loaded while * iterating over the files. @@ -497,19 +523,61 @@ get_connections (NMSettingsPlugin *config) } static gboolean +_file_is_in_path (const char *abs_filename, + const char *abs_path) +{ + gsize l; + + /* FIXME: ensure that both paths are at least normalized (coalescing ".", + * duplicate '/', and trailing '/'). */ + + nm_assert (abs_filename && abs_filename[0] == '/'); + nm_assert (abs_path && abs_path[0] == '/'); + + l = strlen (abs_path); + if (strncmp (abs_filename, abs_path, l) != 0) + return FALSE; + + abs_filename += l; + while (abs_filename[0] == '/') + abs_filename++; + + if (!abs_filename[0]) + return FALSE; + + if (strchr (abs_filename, '/')) + return FALSE; + + return TRUE; +} + +static gboolean load_connection (NMSettingsPlugin *config, const char *filename) { NMSKeyfilePlugin *self = NMS_KEYFILE_PLUGIN ((NMSKeyfilePlugin *) config); NMSKeyfileConnection *connection; - int dir_len = strlen (nms_keyfile_utils_get_path ()); + gboolean require_extension; - if ( strncmp (filename, nms_keyfile_utils_get_path (), dir_len) != 0 - || filename[dir_len] != '/' - || strchr (filename + dir_len + 1, '/') != NULL) + /* the test whether to require a file extension tries to figure out whether + * the provided filename is inside /etc or /run. + * + * However, on Posix a filename just resolves to an Inode, and there can + * be any kind of paths that point to the same Inode. It's not generally possible + * to check for that (unless, we would stat all files in the target directory + * and see whether their inode matches). + * + * So, when loading the file do something simpler: require that the path + * starts with the well-known prefix. This rejects symlinks or hard links + * which would actually also point to the same file. */ + if (_file_is_in_path (filename, nms_keyfile_utils_get_path ())) + require_extension = FALSE; + else if (_file_is_in_path (filename, NM_CONFIG_KEYFILE_PATH_IN_MEMORY)) + require_extension = TRUE; + else return FALSE; - if (nms_keyfile_utils_should_ignore_file (filename + dir_len + 1)) + if (nms_keyfile_utils_should_ignore_file (filename, require_extension)) return FALSE; connection = update_connection (self, NULL, filename, find_by_path (self, filename), TRUE, NULL, NULL); @@ -533,16 +601,16 @@ add_connection (NMSettingsPlugin *config, gs_free char *path = NULL; gs_unref_object NMConnection *reread = NULL; - if (save_to_disk) { - if (!nms_keyfile_writer_connection (connection, - NULL, - FALSE, - &path, - &reread, - NULL, - error)) - return NULL; - } + if (!nms_keyfile_writer_connection (connection, + save_to_disk, + NULL, + FALSE, + &path, + &reread, + NULL, + error)) + return NULL; + return NM_SETTINGS_CONNECTION (update_connection (self, reread ?: connection, path, NULL, FALSE, NULL, error)); } @@ -616,20 +684,17 @@ dispose (GObject *object) } static void -nms_keyfile_plugin_class_init (NMSKeyfilePluginClass *req_class) +nms_keyfile_plugin_class_init (NMSKeyfilePluginClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (req_class); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMSettingsPluginClass *plugin_class = NM_SETTINGS_PLUGIN_CLASS (klass); object_class->constructed = constructed; - object_class->dispose = dispose; -} + object_class->dispose = dispose; -static void -settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) -{ - plugin_iface->get_connections = get_connections; - plugin_iface->load_connection = load_connection; - plugin_iface->reload_connections = reload_connections; - plugin_iface->add_connection = add_connection; - plugin_iface->get_unmanaged_specs = get_unmanaged_specs; + plugin_class->get_connections = get_connections; + plugin_class->load_connection = load_connection; + plugin_class->reload_connections = reload_connections; + plugin_class->add_connection = add_connection; + plugin_class->get_unmanaged_specs = get_unmanaged_specs; } diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.c b/src/settings/plugins/keyfile/nms-keyfile-reader.c index cb4b8379..580a857a 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-reader.c +++ b/src/settings/plugins/keyfile/nms-keyfile-reader.c @@ -28,6 +28,7 @@ #include "nm-keyfile-internal.h" #include "NetworkManagerUtils.h" +#include "nms-keyfile-utils.h" /*****************************************************************************/ @@ -102,53 +103,87 @@ _handler_read (GKeyFile *keyfile, NMConnection * nms_keyfile_reader_from_keyfile (GKeyFile *key_file, const char *filename, + const char *base_dir, + const char *profile_dir, gboolean verbose, GError **error) { + NMConnection *connection; HandlerReadData data = { .verbose = verbose, }; + gs_free char *base_dir_free = NULL; + gs_free char *profile_filename_free = NULL; + gs_free char *filename_id = NULL; + const char *profile_filename = NULL; + + nm_assert (filename && filename[0]); + nm_assert (!base_dir || base_dir[0] == '/'); + nm_assert (!profile_dir || profile_dir[0] == '/'); + + if (base_dir) + nm_assert (!strchr (filename, '/')); + else { + const char *s; + + nm_assert (filename[0] == '/'); + + /* @base_dir may be NULL, in which case @filename must be an absolute path, + * and the directory is taken as the @base_dir. */ + s = strrchr (filename, '/'); + base_dir = nm_strndup_a (255, filename, s - filename, &base_dir_free); + if ( !profile_dir + || nm_streq (base_dir, profile_dir)) + profile_filename = filename; + filename = &s[1]; + } + + connection = nm_keyfile_read (key_file, base_dir, _handler_read, &data, error); + if (!connection) + return NULL; + + if (g_str_has_suffix (filename, NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION)) { + gsize l = strlen (filename); - return nm_keyfile_read (key_file, filename, NULL, _handler_read, &data, error); + if (l > NM_STRLEN (NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION)) + filename_id = g_strndup (filename, l - NM_STRLEN (NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION)); + } + + nm_keyfile_read_ensure_id (connection, filename_id ?: filename); + + if (!profile_filename) { + profile_filename_free = g_build_filename (profile_dir ?: base_dir, filename, NULL); + profile_filename = profile_filename_free; + } + nm_keyfile_read_ensure_uuid (connection, profile_filename); + + return connection; } NMConnection * -nms_keyfile_reader_from_file (const char *filename, GError **error) +nms_keyfile_reader_from_file (const char *full_filename, + const char *profile_dir, + GError **error) { - GKeyFile *key_file; - struct stat statbuf; + gs_unref_keyfile GKeyFile *key_file = NULL; NMConnection *connection = NULL; GError *verify_error = NULL; - if (stat (filename, &statbuf) != 0 || !S_ISREG (statbuf.st_mode)) { - g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "File did not exist or was not a regular file"); - return NULL; - } + nm_assert (full_filename && full_filename[0] == '/'); + nm_assert (!profile_dir || profile_dir[0] == '/'); - if (!NM_FLAGS_HAS (nm_utils_get_testing (), NM_UTILS_TEST_NO_KEYFILE_OWNER_CHECK)) { - if (statbuf.st_mode & 0077) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "File permissions (%o) were insecure", - statbuf.st_mode); - return NULL; - } - - if (statbuf.st_uid != 0) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "File owner (%o) is insecure", - statbuf.st_mode); - return NULL; - } - } + if (!nms_keyfile_utils_check_file_permissions (full_filename, + NULL, + error)) + return NULL; key_file = g_key_file_new (); - if (!g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, error)) - goto out; + if (!g_key_file_load_from_file (key_file, full_filename, G_KEY_FILE_NONE, error)) + return NULL; - connection = nms_keyfile_reader_from_keyfile (key_file, filename, TRUE, error); + connection = nms_keyfile_reader_from_keyfile (key_file, full_filename, NULL, profile_dir, TRUE, error); if (!connection) - goto out; + return NULL; /* Normalize and verify the connection */ if (!nm_connection_normalize (connection, NULL, NULL, &verify_error)) { @@ -160,8 +195,6 @@ nms_keyfile_reader_from_file (const char *filename, GError **error) connection = NULL; } -out: - g_key_file_free (key_file); return connection; } diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.h b/src/settings/plugins/keyfile/nms-keyfile-reader.h index b60c1e69..c0fb06d1 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-reader.h +++ b/src/settings/plugins/keyfile/nms-keyfile-reader.h @@ -26,9 +26,13 @@ NMConnection *nms_keyfile_reader_from_keyfile (GKeyFile *key_file, const char *filename, + const char *base_dir, + const char *profile_dir, gboolean verbose, GError **error); -NMConnection *nms_keyfile_reader_from_file (const char *filename, GError **error); +NMConnection *nms_keyfile_reader_from_file (const char *full_filename, + const char *profile_dir, + GError **error); #endif /* __NMS_KEYFILE_READER_H__ */ diff --git a/src/settings/plugins/keyfile/nms-keyfile-utils.c b/src/settings/plugins/keyfile/nms-keyfile-utils.c index 03f06670..c3bfcdee 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-utils.c +++ b/src/settings/plugins/keyfile/nms-keyfile-utils.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include <string.h> +#include <sys/stat.h> #include "nm-setting-wired.h" #include "nm-setting-wireless.h" @@ -55,18 +56,11 @@ check_mkstemp_suffix (const char *path) } static gboolean -check_prefix (const char *base, const char *tag) +check_prefix_dot (const char *base) { - int len, tag_len; + nm_assert (base && base[0]); - g_return_val_if_fail (base != NULL, TRUE); - g_return_val_if_fail (tag != NULL, TRUE); - - len = strlen (base); - tag_len = strlen (tag); - if ((len > tag_len) && !g_ascii_strncasecmp (base, tag, tag_len)) - return TRUE; - return FALSE; + return base[0] == '.'; } static gboolean @@ -90,7 +84,7 @@ check_suffix (const char *base, const char *tag) #define DER_TAG ".der" gboolean -nms_keyfile_utils_should_ignore_file (const char *filename) +nms_keyfile_utils_should_ignore_file (const char *filename, gboolean require_extension) { gs_free char *base = NULL; @@ -101,7 +95,7 @@ nms_keyfile_utils_should_ignore_file (const char *filename) /* Ignore hidden and backup files */ /* should_ignore_file() must mirror escape_filename() */ - if (check_prefix (base, ".") || check_suffix (base, "~")) + if (check_prefix_dot (base) || check_suffix (base, "~")) return TRUE; /* Ignore temporary files */ if (check_mkstemp_suffix (base)) @@ -110,18 +104,87 @@ nms_keyfile_utils_should_ignore_file (const char *filename) if (check_suffix (base, PEM_TAG) || check_suffix (base, DER_TAG)) return TRUE; + if (require_extension) { + gsize l = strlen (base); + + if ( l <= NM_STRLEN (NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION) + || !g_str_has_suffix (base, NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION)) + return TRUE; + } + return FALSE; } +/*****************************************************************************/ + +gboolean +nms_keyfile_utils_check_file_permissions_stat (const struct stat *st, + GError **error) +{ + g_return_val_if_fail (st, FALSE); + + if (!S_ISREG (st->st_mode)) { + g_set_error_literal (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "file is not a regular file"); + return FALSE; + } + + if (!NM_FLAGS_HAS (nm_utils_get_testing (), NM_UTILS_TEST_NO_KEYFILE_OWNER_CHECK)) { + if (st->st_uid != 0) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "File owner (%lld) is insecure", + (long long) st->st_uid); + return FALSE; + } + + if (st->st_mode & 0077) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "File permissions (%03o) are insecure", + st->st_mode); + return FALSE; + } + } + + return TRUE; +} + +gboolean +nms_keyfile_utils_check_file_permissions (const char *filename, + struct stat *out_st, + GError **error) +{ + struct stat st; + int errsv; + + g_return_val_if_fail (filename && filename[0] == '/', FALSE); + + if (stat (filename, &st) != 0) { + errsv = errno; + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "cannot access file: %s", g_strerror (errsv)); + return FALSE; + } + + if (!nms_keyfile_utils_check_file_permissions_stat (&st, error)) + return FALSE; + + NM_SET_OUT (out_st, st); + return TRUE; +} + +/*****************************************************************************/ + char * -nms_keyfile_utils_escape_filename (const char *filename) +nms_keyfile_utils_escape_filename (const char *filename, + gboolean with_extension) { GString *str; const char *f = filename; - const char ESCAPE_CHAR = '*'; - /* keyfile used to escape with '*', do not change that behavior. - * But for newly added escapings, use '_' instead. */ + * + * But for newly added escapings, use '_' instead. + * Also, @with_extension is new-style. */ + const char ESCAPE_CHAR = with_extension ? '_' : '*'; const char ESCAPE_CHAR2 = '_'; g_return_val_if_fail (filename && filename[0], NULL); @@ -138,7 +201,7 @@ nms_keyfile_utils_escape_filename (const char *filename) /* escape_filename() must avoid anything that should_ignore_file() would reject. * We can escape here more aggressivly then what we would read back. */ - if (check_prefix (str->str, ".")) + if (check_prefix_dot (str->str)) str->str[0] = ESCAPE_CHAR2; if (check_suffix (str->str, "~")) str->str[str->len - 1] = ESCAPE_CHAR2; @@ -147,6 +210,9 @@ nms_keyfile_utils_escape_filename (const char *filename) || check_suffix (str->str, DER_TAG)) g_string_append_c (str, ESCAPE_CHAR2); + if (with_extension) + g_string_append (str, NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION); + return g_string_free (str, FALSE);; } diff --git a/src/settings/plugins/keyfile/nms-keyfile-utils.h b/src/settings/plugins/keyfile/nms-keyfile-utils.h index cd3f42b9..297dd4ea 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-utils.h +++ b/src/settings/plugins/keyfile/nms-keyfile-utils.h @@ -23,16 +23,28 @@ #include "NetworkManagerUtils.h" +#define NM_CONFIG_KEYFILE_PATH_IN_MEMORY NMRUNDIR "/system-connections" + +#define NMS_KEYFILE_PATH_SUFFIX_NMCONNECTION ".nmconnection" + #define NMS_KEYFILE_CONNECTION_LOG_PATH(path) ((path) ?: "in-memory") #define NMS_KEYFILE_CONNECTION_LOG_FMT "%s (%s,\"%s\")" -#define NMS_KEYFILE_CONNECTION_LOG_ARG(con) NMS_KEYFILE_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_connection_get_uuid ((NMConnection *) (con)), nm_connection_get_id ((NMConnection *) (con)) +#define NMS_KEYFILE_CONNECTION_LOG_ARG(con) NMS_KEYFILE_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_settings_connection_get_uuid ((NMSettingsConnection *) (con)), nm_settings_connection_get_id ((NMSettingsConnection *) (con)) #define NMS_KEYFILE_CONNECTION_LOG_FMTD "%s (%s,\"%s\",%p)" -#define NMS_KEYFILE_CONNECTION_LOG_ARGD(con) NMS_KEYFILE_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_connection_get_uuid ((NMConnection *) (con)), nm_connection_get_id ((NMConnection *) (con)), (con) +#define NMS_KEYFILE_CONNECTION_LOG_ARGD(con) NMS_KEYFILE_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_settings_connection_get_uuid ((NMSettingsConnection *) (con)), nm_settings_connection_get_id ((NMSettingsConnection *) (con)), (con) -gboolean nms_keyfile_utils_should_ignore_file (const char *filename); +gboolean nms_keyfile_utils_should_ignore_file (const char *filename, gboolean require_extension); -char *nms_keyfile_utils_escape_filename (const char *filename); +char *nms_keyfile_utils_escape_filename (const char *filename, gboolean with_extension); const char *nms_keyfile_utils_get_path (void); +struct stat; +gboolean nms_keyfile_utils_check_file_permissions_stat (const struct stat *st, + GError **error); + +gboolean nms_keyfile_utils_check_file_permissions (const char *filename, + struct stat *out_st, + GError **error); + #endif /* __NMS_KEYFILE_UTILS_H__ */ diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.c b/src/settings/plugins/keyfile/nms-keyfile-writer.c index 270a217e..df26ea60 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-writer.c +++ b/src/settings/plugins/keyfile/nms-keyfile-writer.c @@ -34,6 +34,8 @@ #include "nms-keyfile-utils.h" #include "nms-keyfile-reader.h" +#include "nm-utils/nm-io-utils.h" + /*****************************************************************************/ typedef struct { @@ -127,7 +129,7 @@ cert_writer (NMConnection *connection, new_path = g_strdup_printf ("%s/%s-%s.%s", info->keyfile_dir, nm_connection_get_uuid (connection), cert_data->vtable->file_suffix, ext); - success = nm_utils_file_set_contents (new_path, (const gchar *) blob_data, + success = nm_utils_file_set_contents (new_path, (const char *) blob_data, blob_len, 0600, &local); if (success) { /* Write the path value to the keyfile. @@ -170,6 +172,8 @@ _handler_write (NMConnection *connection, static gboolean _internal_write_connection (NMConnection *connection, const char *keyfile_dir, + const char *profile_dir, + gboolean with_extension, uid_t owner_uid, pid_t owner_grp, const char *existing_path, @@ -187,10 +191,14 @@ _internal_write_connection (NMConnection *connection, WriteInfo info = { 0 }; GError *local_err = NULL; int errsv; + gboolean rename = force_rename; g_return_val_if_fail (!out_path || !*out_path, FALSE); g_return_val_if_fail (keyfile_dir && keyfile_dir[0] == '/', FALSE); + if (existing_path && !g_str_has_prefix (existing_path, keyfile_dir)) + rename = TRUE; + switch (_nm_connection_verify (connection, error)) { case NM_SETTING_VERIFY_NORMALIZABLE: nm_assert_not_reached (); @@ -219,10 +227,10 @@ _internal_write_connection (NMConnection *connection, /* If we have existing file path, use it. Else generate one from * connection's ID. */ - if (existing_path != NULL && !force_rename) { + if (existing_path != NULL && !rename) { path = g_strdup (existing_path); } else { - char *filename_escaped = nms_keyfile_utils_escape_filename (id); + char *filename_escaped = nms_keyfile_utils_escape_filename (id, with_extension); path = g_build_filename (keyfile_dir, filename_escaped, NULL); g_free (filename_escaped); @@ -248,7 +256,7 @@ _internal_write_connection (NMConnection *connection, else filename = g_strdup_printf ("%s-%s-%u", id, nm_connection_get_uuid (connection), i); - filename_escaped = nms_keyfile_utils_escape_filename (filename); + filename_escaped = nms_keyfile_utils_escape_filename (filename, with_extension); g_free (path); path = g_strdup_printf ("%s/%s", keyfile_dir, filename_escaped); @@ -297,17 +305,12 @@ _internal_write_connection (NMConnection *connection, return FALSE; } - if (out_path && g_strcmp0 (existing_path, path)) { - *out_path = path; /* pass path out to caller */ - path = NULL; - } - if (out_reread || out_reread_same) { gs_unref_object NMConnection *reread = NULL; gboolean reread_same = FALSE; - reread = nms_keyfile_reader_from_keyfile (key_file, path, FALSE, NULL); + reread = nms_keyfile_reader_from_keyfile (key_file, path, NULL, profile_dir, FALSE, NULL); nm_assert (NM_IS_CONNECTION (reread)); @@ -333,11 +336,14 @@ _internal_write_connection (NMConnection *connection, NM_SET_OUT (out_reread_same, reread_same); } + NM_SET_OUT (out_path, g_steal_pointer (&path)); + return TRUE; } gboolean nms_keyfile_writer_connection (NMConnection *connection, + gboolean save_to_disk, const char *existing_path, gboolean force_rename, char **out_path, @@ -345,9 +351,19 @@ nms_keyfile_writer_connection (NMConnection *connection, gboolean *out_reread_same, GError **error) { + const char *keyfile_dir; + + if (save_to_disk) + keyfile_dir = nms_keyfile_utils_get_path (); + else + keyfile_dir = NM_CONFIG_KEYFILE_PATH_IN_MEMORY; + return _internal_write_connection (connection, + keyfile_dir, nms_keyfile_utils_get_path (), - 0, 0, + TRUE, + 0, + 0, existing_path, force_rename, out_path, @@ -368,7 +384,10 @@ nms_keyfile_writer_test_connection (NMConnection *connection, { return _internal_write_connection (connection, keyfile_dir, - owner_uid, owner_grp, + keyfile_dir, + FALSE, + owner_uid, + owner_grp, NULL, FALSE, out_path, diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.h b/src/settings/plugins/keyfile/nms-keyfile-writer.h index ac41dfa2..030fb7cc 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-writer.h +++ b/src/settings/plugins/keyfile/nms-keyfile-writer.h @@ -25,6 +25,7 @@ #include "nm-connection.h" gboolean nms_keyfile_writer_connection (NMConnection *connection, + gboolean save_to_disk, const char *existing_path, gboolean force_rename, char **out_path, diff --git a/src/settings/plugins/keyfile/tests/meson.build b/src/settings/plugins/keyfile/tests/meson.build index 33aaa264..8b94b256 100644 --- a/src/settings/plugins/keyfile/tests/meson.build +++ b/src/settings/plugins/keyfile/tests/meson.build @@ -6,7 +6,6 @@ exe = executable( test_unit, test_unit + '.c', dependencies: test_nm_dep, - c_args: nm_build_cflags, ) test( diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c index a3045f7d..4a0e01b3 100644 --- a/src/settings/plugins/keyfile/tests/test-keyfile.c +++ b/src/settings/plugins/keyfile/tests/test-keyfile.c @@ -65,37 +65,32 @@ check_ip_route (NMSettingIPConfig *config, int idx, const char *destination, int g_assert_cmpint (nm_ip_route_get_metric (route), ==, metric); } -static NMConnection * -keyfile_read_connection_from_file (const char *filename) -{ - gs_free_error GError *error = NULL; - NMConnection *connection; - - g_assert (filename); - - connection = nms_keyfile_reader_from_file (filename, &error); - g_assert_no_error (error); - - nmtst_assert_connection_verifies_without_normalization (connection); - - return connection; -} +#define keyfile_read_connection_from_file(full_filename) \ +({ \ + gs_free_error GError *_error = NULL; \ + NMConnection *_connection; \ + \ + g_assert (full_filename && full_filename[0] == '/'); \ + \ + _connection = nms_keyfile_reader_from_file (full_filename, \ + NULL, \ + (nmtst_get_rand_int () % 2) ? &_error : NULL); \ + nmtst_assert_success (_connection, _error); \ + nmtst_assert_connection_verifies_without_normalization (_connection); \ + \ + _connection; \ +}) static void assert_reread (NMConnection *connection, gboolean normalize_connection, const char *testfile) { gs_unref_object NMConnection *reread = NULL; gs_unref_object NMConnection *connection_clone = NULL; - GError *error = NULL; - GError **p_error = (nmtst_get_rand_int () % 2) ? &error : NULL; NMSettingConnection *s_con; g_assert (NM_IS_CONNECTION (connection)); - g_assert (testfile && testfile[0]); - reread = nms_keyfile_reader_from_file (testfile, p_error); - g_assert_no_error (error); - g_assert (NM_IS_CONNECTION (reread)); + reread = keyfile_read_connection_from_file (testfile); if ( !normalize_connection && (s_con = nm_connection_get_setting_connection (connection)) @@ -229,10 +224,8 @@ test_read_valid_wired_connection (void) NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; NMIPRoute *route; - gs_free_error GError *error = NULL; const char *mac; char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; - gboolean success; NMTST_EXPECT_NM_INFO ("*ipv4.addresses:*semicolon at the end*addresses1*"); NMTST_EXPECT_NM_INFO ("*ipv4.addresses:*semicolon at the end*addresses2*"); @@ -249,16 +242,9 @@ test_read_valid_wired_connection (void) NMTST_EXPECT_NM_INFO ("*ipv6.address*semicolon at the end*address7*"); NMTST_EXPECT_NM_INFO ("*ipv6.routes*semicolon at the end*routes1*"); NMTST_EXPECT_NM_INFO ("*ipv6.route*semicolon at the end*route6*"); - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection", &error); - g_assert_no_error (error); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection"); g_test_assert_expected_messages (); - g_assert (connection); - - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); - /* ===== CONNECTION SETTING ===== */ s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "Test Wired Connection"); @@ -266,7 +252,6 @@ test_read_valid_wired_connection (void) g_assert_cmpuint (nm_setting_connection_get_timestamp (s_con), ==, 6654332); g_assert (nm_setting_connection_get_autoconnect (s_con)); - /* ===== WIRED SETTING ===== */ s_wired = nm_connection_get_setting_wired (connection); g_assert (s_wired); @@ -275,7 +260,6 @@ test_read_valid_wired_connection (void) g_assert (nm_utils_hwaddr_matches (mac, -1, expected_mac_address, sizeof (expected_mac_address))); g_assert_cmpint (nm_setting_wired_get_mtu (s_wired), ==, 1400); - /* ===== IPv4 SETTING ===== */ s_ip4 = nm_connection_get_setting_ip4_config (connection); g_assert (s_ip4); g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); @@ -324,7 +308,6 @@ test_read_valid_wired_connection (void) nmtst_assert_route_attribute_boolean (route, NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, TRUE); nmtst_assert_route_attribute_string (route, NM_IP_ROUTE_ATTRIBUTE_SRC, "7.7.7.7"); - /* ===== IPv6 SETTING ===== */ s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); @@ -535,32 +518,22 @@ test_read_ip6_wired_connection (void) NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; - gs_free_error GError *error = NULL; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection_IP6", NULL); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection_IP6"); - /* ===== CONNECTION SETTING ===== */ s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "Test Wired Connection IP6"); g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, "4e80a56d-c99f-4aad-a6dd-b449bc398c57"); - /* ===== WIRED SETTING ===== */ s_wired = nm_connection_get_setting_wired (connection); g_assert (s_wired); - /* ===== IPv4 SETTING ===== */ s_ip4 = nm_connection_get_setting_ip4_config (connection); g_assert (s_ip4); g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_DISABLED); g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 0); - /* ===== IPv6 SETTING ===== */ s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_MANUAL); @@ -638,28 +611,20 @@ test_read_wired_mac_case (void) gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; NMSettingWired *s_wired; - gs_free_error GError *error = NULL; const char *mac; char expected_mac_address[ETH_ALEN] = { 0x00, 0x11, 0xaa, 0xbb, 0xcc, 0x55 }; - gboolean success; NMTST_EXPECT_NM_INFO ("*ipv4.addresses*semicolon at the end*addresses1*"); NMTST_EXPECT_NM_INFO ("*ipv4.addresses*semicolon at the end*addresses2*"); NMTST_EXPECT_NM_INFO ("*ipv6.routes*semicolon at the end*routes1*"); - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection_MAC_Case", NULL); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wired_Connection_MAC_Case"); g_test_assert_expected_messages (); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); - /* ===== CONNECTION SETTING ===== */ s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "Test Wired Connection MAC Case"); g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, "4e80a56d-c99f-4aad-a6dd-b449bc398c57"); - /* ===== WIRED SETTING ===== */ s_wired = nm_connection_get_setting_wired (connection); g_assert (s_wired); mac = nm_setting_wired_get_mac_address (s_wired); @@ -672,29 +637,19 @@ test_read_mac_old_format (void) { gs_unref_object NMConnection *connection = NULL; NMSettingWired *s_wired; - gs_free_error GError *error = NULL; - gboolean success; const char *mac; char expected_mac[ETH_ALEN] = { 0x00, 0x11, 0xaa, 0xbb, 0xcc, 0x55 }; char expected_cloned_mac[ETH_ALEN] = { 0x00, 0x16, 0xaa, 0xbb, 0xcc, 0xfe }; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_MAC_Old_Format", &error); - g_assert_no_error (error); - g_assert (connection); - - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_MAC_Old_Format"); s_wired = nm_connection_get_setting_wired (connection); g_assert (s_wired); - /* MAC address */ mac = nm_setting_wired_get_mac_address (s_wired); g_assert (mac); g_assert (nm_utils_hwaddr_matches (mac, -1, expected_mac, ETH_ALEN)); - /* Cloned MAC address */ mac = nm_setting_wired_get_cloned_mac_address (s_wired); g_assert (mac); g_assert (nm_utils_hwaddr_matches (mac, -1, expected_cloned_mac, ETH_ALEN)); @@ -705,20 +660,12 @@ test_read_mac_ib_old_format (void) { gs_unref_object NMConnection *connection = NULL; NMSettingInfiniband *s_ib; - gs_free_error GError *error = NULL; - gboolean success; const char *mac; guint8 expected_mac[INFINIBAND_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, - 0x77, 0x88, 0x99, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, - 0x90 }; + 0x77, 0x88, 0x99, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, + 0x90 }; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_MAC_IB_Old_Format", &error); - g_assert_no_error (error); - g_assert (connection); - - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_MAC_IB_Old_Format"); s_ib = nm_connection_get_setting_infiniband (connection); g_assert (s_ib); @@ -736,18 +683,11 @@ test_read_valid_wireless_connection (void) NMSettingConnection *s_con; NMSettingWireless *s_wireless; NMSettingIPConfig *s_ip4; - gs_free_error GError *error = NULL; const char *bssid; const guint8 expected_bssid[ETH_ALEN] = { 0x00, 0x1a, 0x33, 0x44, 0x99, 0x82 }; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wireless_Connection", NULL); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wireless_Connection"); - /* ===== CONNECTION SETTING ===== */ s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "Test Wireless Connection"); @@ -755,14 +695,12 @@ test_read_valid_wireless_connection (void) g_assert_cmpuint (nm_setting_connection_get_timestamp (s_con), ==, 1226604314); g_assert (nm_setting_connection_get_autoconnect (s_con) == FALSE); - /* ===== WIRELESS SETTING ===== */ s_wireless = nm_connection_get_setting_wireless (connection); g_assert (s_wireless); bssid = nm_setting_wireless_get_bssid (s_wireless); g_assert (bssid); g_assert (nm_utils_hwaddr_matches (bssid, -1, expected_bssid, sizeof (expected_bssid))); - /* ===== IPv4 SETTING ===== */ s_ip4 = nm_connection_get_setting_ip4_config (connection); g_assert (s_ip4); g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); @@ -838,24 +776,19 @@ test_read_string_ssid (void) { gs_unref_object NMConnection *connection = NULL; NMSettingWireless *s_wireless; - gs_free_error GError *error = NULL; GBytes *ssid; const guint8 *ssid_data; gsize ssid_len; const char *expected_ssid = "blah blah ssid 1234"; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_String_SSID", NULL); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_String_SSID"); - /* ===== WIRELESS SETTING ===== */ s_wireless = nm_connection_get_setting_wireless (connection); g_assert (s_wireless); + ssid = nm_setting_wireless_get_ssid (s_wireless); g_assert (ssid); + ssid_data = g_bytes_get_data (ssid, &ssid_len); g_assert_cmpmem (ssid_data, ssid_len, expected_ssid, strlen (expected_ssid)); } @@ -922,22 +855,13 @@ test_read_intlist_ssid (void) { gs_unref_object NMConnection *connection = NULL; NMSettingWireless *s_wifi; - gs_free_error GError *error = NULL; - gboolean success; GBytes *ssid; const guint8 *ssid_data; gsize ssid_len; const char *expected_ssid = "blah1234"; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Intlist_SSID", &error); - g_assert_no_error (error); - g_assert (connection); - - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Intlist_SSID"); - /* SSID */ s_wifi = nm_connection_get_setting_wireless (connection); g_assert (s_wifi); @@ -960,7 +884,7 @@ test_write_intlist_ssid (void) unsigned char tmpssid[] = { 65, 49, 50, 51, 0, 50, 50 }; gs_free_error GError *error = NULL; gs_unref_keyfile GKeyFile *keyfile = NULL; - gint *intlist; + int *intlist; gsize len = 0, i; connection = nm_simple_connection_new (); @@ -1015,30 +939,17 @@ test_read_intlike_ssid (void) { gs_unref_object NMConnection *connection = NULL; NMSettingWireless *s_wifi; - gs_free_error GError *error = NULL; - gboolean success; GBytes *ssid; - const guint8 *ssid_data; - gsize ssid_len; const char *expected_ssid = "101"; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Intlike_SSID", &error); - g_assert_no_error (error); - g_assert (connection); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Intlike_SSID"); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); - - /* SSID */ s_wifi = nm_connection_get_setting_wireless (connection); g_assert (s_wifi); ssid = nm_setting_wireless_get_ssid (s_wifi); - g_assert (ssid != NULL); - ssid_data = g_bytes_get_data (ssid, &ssid_len); - g_assert_cmpint (ssid_len, ==, strlen (expected_ssid)); - g_assert_cmpint (memcmp (ssid_data, expected_ssid, strlen (expected_ssid)), ==, 0); + g_assert (ssid); + g_assert (nm_utils_gbytes_equal_mem (ssid, expected_ssid, strlen (expected_ssid))); } static void @@ -1046,30 +957,17 @@ test_read_intlike_ssid_2 (void) { gs_unref_object NMConnection *connection = NULL; NMSettingWireless *s_wifi; - gs_free_error GError *error = NULL; - gboolean success; GBytes *ssid; - const guint8 *ssid_data; - gsize ssid_len; const char *expected_ssid = "11;12;13;"; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Intlike_SSID_2", &error); - g_assert_no_error (error); - g_assert (connection); - - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Intlike_SSID_2"); - /* SSID */ s_wifi = nm_connection_get_setting_wireless (connection); g_assert (s_wifi); ssid = nm_setting_wireless_get_ssid (s_wifi); - g_assert (ssid != NULL); - ssid_data = g_bytes_get_data (ssid, &ssid_len); - g_assert_cmpint (ssid_len, ==, strlen (expected_ssid)); - g_assert_cmpint (memcmp (ssid_data, expected_ssid, strlen (expected_ssid)), ==, 0); + g_assert (ssid); + g_assert (nm_utils_gbytes_equal_mem (ssid, expected_ssid, strlen (expected_ssid))); } static void @@ -1197,24 +1095,16 @@ test_read_bt_dun_connection (void) NMSettingBluetooth *s_bluetooth; NMSettingSerial *s_serial; NMSettingGsm *s_gsm; - gs_free_error GError *error = NULL; const char *bdaddr; const guint8 expected_bdaddr[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/ATT_Data_Connect_BT", NULL); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/ATT_Data_Connect_BT"); - /* ===== CONNECTION SETTING ===== */ s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "AT&T Data Connect BT"); g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, "089130ab-ce28-46e4-ad77-d44869b03d19"); - /* ===== BLUETOOTH SETTING ===== */ s_bluetooth = nm_connection_get_setting_bluetooth (connection); g_assert (s_bluetooth); bdaddr = nm_setting_bluetooth_get_bdaddr (s_bluetooth); @@ -1222,14 +1112,12 @@ test_read_bt_dun_connection (void) g_assert (nm_utils_hwaddr_matches (bdaddr, -1, expected_bdaddr, sizeof (expected_bdaddr))); g_assert_cmpstr (nm_setting_bluetooth_get_connection_type (s_bluetooth), ==, NM_SETTING_BLUETOOTH_TYPE_DUN); - /* ===== GSM SETTING ===== */ s_gsm = nm_connection_get_setting_gsm (connection); g_assert (s_gsm); g_assert_cmpstr (nm_setting_gsm_get_apn (s_gsm), ==, "ISP.CINGULAR"); g_assert_cmpstr (nm_setting_gsm_get_username (s_gsm), ==, "ISP@CINGULARGPRS.COM"); g_assert_cmpstr (nm_setting_gsm_get_password (s_gsm), ==, "CINGULAR1"); - /* ===== SERIAL SETTING ===== */ s_serial = nm_connection_get_setting_serial (connection); g_assert (s_serial); g_assert (nm_setting_serial_get_parity (s_serial) == NM_SETTING_SERIAL_PARITY_ODD); @@ -1302,28 +1190,17 @@ test_read_gsm_connection (void) NMSettingConnection *s_con; NMSettingSerial *s_serial; NMSettingGsm *s_gsm; - gs_free_error GError *error = NULL; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/ATT_Data_Connect_Plain", &error); - g_assert_no_error (error); - g_assert (connection); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/ATT_Data_Connect_Plain"); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); - - /* ===== CONNECTION SETTING ===== */ s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "AT&T Data Connect"); g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_GSM_SETTING_NAME); - /* ===== BLUETOOTH SETTING ===== */ /* Plain GSM, so no BT setting expected */ g_assert (nm_connection_get_setting_bluetooth (connection) == NULL); - /* ===== GSM SETTING ===== */ s_gsm = nm_connection_get_setting_gsm (connection); g_assert (s_gsm); g_assert_cmpstr (nm_setting_gsm_get_apn (s_gsm), ==, "ISP.CINGULAR"); @@ -1335,7 +1212,6 @@ test_read_gsm_connection (void) g_assert_cmpstr (nm_setting_gsm_get_sim_id (s_gsm), ==, "89148000000060671234"); g_assert_cmpstr (nm_setting_gsm_get_sim_operator_id (s_gsm), ==, "310260"); - /* ===== SERIAL SETTING ===== */ s_serial = nm_connection_get_setting_serial (connection); g_assert (s_serial); g_assert_cmpint (nm_setting_serial_get_parity (s_serial), ==, NM_SETTING_SERIAL_PARITY_ODD); @@ -1401,25 +1277,16 @@ test_read_wired_8021x_tls_blob_connection (void) gs_unref_object NMConnection *connection = NULL; NMSettingWired *s_wired; NMSetting8021x *s_8021x; - gs_free_error GError *error = NULL; const char *tmp; - gboolean success; GBytes *blob; NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.client-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*"); NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.private-key: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*"); - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Blob", &error); - g_assert_no_error (error); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Blob"); - /* ===== Wired Setting ===== */ s_wired = nm_connection_get_setting_wired (connection); g_assert (s_wired != NULL); - /* ===== 802.1x Setting ===== */ s_8021x = nm_connection_get_setting_802_1x (connection); g_assert (s_8021x != NULL); @@ -1459,25 +1326,16 @@ test_read_wired_8021x_tls_bad_path_connection (void) gs_unref_object NMConnection *connection = NULL; NMSettingWired *s_wired; NMSetting8021x *s_8021x; - gs_free_error GError *error = NULL; const char *tmp; char *tmp2; - gboolean success; NMTST_EXPECT_NM_WARN ("*does not exist*"); - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Path_Missing", &error); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Path_Missing"); g_test_assert_expected_messages (); - g_assert_no_error (error); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); - /* ===== Wired Setting ===== */ s_wired = nm_connection_get_setting_wired (connection); g_assert (s_wired != NULL); - /* ===== 802.1x Setting ===== */ s_8021x = nm_connection_get_setting_802_1x (connection); g_assert (s_8021x != NULL); @@ -1513,25 +1371,16 @@ test_read_wired_8021x_tls_old_connection (void) gs_unref_object NMConnection *connection = NULL; NMSettingWired *s_wired; NMSetting8021x *s_8021x; - gs_free_error GError *error = NULL; const char *tmp; - gboolean success; NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.ca-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/CA/eaptest_ca_cert.pem' does not exist*"); NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.client-cert: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*"); NMTST_EXPECT_NM_WARN ("keyfile: 802-1x.private-key: certificate or key file '/CASA/dcbw/Desktop/certinfra/client.pem' does not exist*"); - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Old", &error); - g_assert_no_error (error); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_Old"); - /* ===== Wired Setting ===== */ s_wired = nm_connection_get_setting_wired (connection); g_assert (s_wired != NULL); - /* ===== 802.1x Setting ===== */ s_8021x = nm_connection_get_setting_802_1x (connection); g_assert (s_8021x != NULL); @@ -1561,23 +1410,14 @@ test_read_wired_8021x_tls_new_connection (void) gs_unref_object NMConnection *connection = NULL; NMSettingWired *s_wired; NMSetting8021x *s_8021x; - gs_free_error GError *error = NULL; const char *tmp; char *tmp2; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_New", &error); - g_assert_no_error (error); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Wired_TLS_New"); - /* ===== Wired Setting ===== */ s_wired = nm_connection_get_setting_wired (connection); g_assert (s_wired != NULL); - /* ===== 802.1x Setting ===== */ s_8021x = nm_connection_get_setting_802_1x (connection); g_assert (s_8021x != NULL); @@ -1698,7 +1538,6 @@ test_write_wired_8021x_tls_connection_path (void) char *tmp, *tmp2; gboolean success; gs_free char *testfile = NULL; - gs_free_error GError *error = NULL; gs_unref_keyfile GKeyFile *keyfile = NULL; gboolean relative = FALSE; gboolean reread_same = FALSE; @@ -1715,12 +1554,7 @@ test_write_wired_8021x_tls_connection_path (void) g_clear_object (&reread); /* Read the connection back in and compare it to the one we just wrote out */ - reread = nms_keyfile_reader_from_file (testfile, &error); - if (!reread) { - g_assert (error); - g_warning ("Failed to re-read test connection: %s", error->message); - g_assert (reread); - } + reread = keyfile_read_connection_from_file (testfile); success = nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT); if (!reread) { @@ -1786,8 +1620,8 @@ test_write_wired_8021x_tls_connection_blob (void) char *new_priv_key; const char *uuid; gboolean reread_same = FALSE; - gs_free_error GError *error = NULL; - GBytes *password_raw = NULL; + GBytes *password_raw; + #define PASSWORD_RAW "password-raw\0test" connection = create_wired_tls_connection (NM_SETTING_802_1X_CK_SCHEME_BLOB); @@ -1830,12 +1664,7 @@ test_write_wired_8021x_tls_connection_blob (void) g_assert (g_file_test (new_priv_key, G_FILE_TEST_EXISTS)); /* Read the connection back in and compare it to the one we just wrote out */ - reread = nms_keyfile_reader_from_file (testfile, &error); - if (!reread) { - g_assert (error); - g_warning ("Failed to re-read test connection: %s", error->message); - g_assert (reread); - } + reread = keyfile_read_connection_from_file (testfile); /* Ensure the re-read connection's certificates use the path scheme */ s_8021x = nm_connection_get_setting_802_1x (reread); @@ -1846,8 +1675,7 @@ test_write_wired_8021x_tls_connection_blob (void) password_raw = nm_setting_802_1x_get_password_raw (s_8021x); g_assert (password_raw); - g_assert (g_bytes_get_size (password_raw) == NM_STRLEN (PASSWORD_RAW)); - g_assert (!memcmp (g_bytes_get_data (password_raw, NULL), PASSWORD_RAW, NM_STRLEN (PASSWORD_RAW))); + g_assert (nm_utils_gbytes_equal_mem (password_raw, PASSWORD_RAW, NM_STRLEN (PASSWORD_RAW))); unlink (testfile); @@ -1876,29 +1704,20 @@ test_read_infiniband_connection (void) gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; NMSettingInfiniband *s_ib; - gs_free_error GError *error = NULL; const char *mac; guint8 expected_mac[INFINIBAND_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, - 0x77, 0x88, 0x99, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, - 0x90 }; + 0x77, 0x88, 0x99, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, + 0x90 }; const char *expected_id = "Test InfiniBand Connection"; const char *expected_uuid = "4e80a56d-c99f-4aad-a6dd-b449bc398c57"; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_InfiniBand_Connection", &error); - g_assert_no_error (error); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_InfiniBand_Connection"); - /* Connection setting */ s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, expected_id); g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, expected_uuid); - /* InfiniBand setting */ s_ib = nm_connection_get_setting_infiniband (connection); g_assert (s_ib); @@ -1966,31 +1785,21 @@ test_read_bridge_main (void) NMSettingConnection *s_con; NMSettingIPConfig *s_ip4; NMSettingBridge *s_bridge; - gs_free_error GError *error = NULL; const char *expected_id = "Test Bridge Main"; const char *expected_uuid = "8f061643-fe41-4d4c-a8d9-097d26e2ad3a"; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Bridge_Main", &error); - g_assert_no_error (error); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Bridge_Main"); - /* Connection setting */ s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, expected_id); g_assert_cmpstr (nm_setting_connection_get_uuid (s_con), ==, expected_uuid); g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, "br0"); - /* IPv4 setting */ s_ip4 = nm_connection_get_setting_ip4_config (connection); g_assert (s_ip4); g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - /* Bridge setting */ s_bridge = nm_connection_get_setting_bridge (connection); g_assert (s_bridge); g_assert_cmpuint (nm_setting_bridge_get_forward_delay (s_bridge), ==, 2); @@ -2063,19 +1872,11 @@ test_read_bridge_component (void) NMSettingWired *s_wired; const char *mac; guint8 expected_mac[ETH_ALEN] = { 0x00, 0x22, 0x15, 0x59, 0x62, 0x97 }; - gs_free_error GError *error = NULL; const char *expected_id = "Test Bridge Component"; const char *expected_uuid = "d7b4f96c-c45e-4298-bef8-f48574f8c1c0"; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_Bridge_Component", &error); - g_assert_no_error (error); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_Bridge_Component"); - /* Connection setting */ s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, expected_id); @@ -2083,14 +1884,12 @@ test_read_bridge_component (void) g_assert_cmpstr (nm_setting_connection_get_master (s_con), ==, "br0"); g_assert (nm_setting_connection_is_slave_type (s_con, NM_SETTING_BRIDGE_SETTING_NAME)); - /* Wired setting */ s_wired = nm_connection_get_setting_wired (connection); g_assert (s_wired); mac = nm_setting_wired_get_mac_address (s_wired); g_assert (mac); g_assert (nm_utils_hwaddr_matches (mac, -1, expected_mac, sizeof (expected_mac))); - /* BridgePort setting */ s_port = nm_connection_get_setting_bridge_port (connection); g_assert (s_port); g_assert (nm_setting_bridge_port_get_hairpin_mode (s_port)); @@ -2155,17 +1954,9 @@ test_read_new_wired_group_name (void) NMSettingWired *s_wired; const char *mac; guint8 expected_mac[ETH_ALEN] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; - gs_free_error GError *error = NULL; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR"/Test_New_Wired_Group_Name", &error); - g_assert_no_error (error); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR"/Test_New_Wired_Group_Name"); - /* Wired setting */ s_wired = nm_connection_get_setting_wired (connection); g_assert (s_wired); g_assert_cmpint (nm_setting_wired_get_mtu (s_wired), ==, 1400); @@ -2186,7 +1977,7 @@ test_write_new_wired_group_name (void) gs_free char *testfile = NULL; gs_free_error GError *error = NULL; char *s; - gint mtu; + int mtu; connection = nm_simple_connection_new (); g_assert (connection); @@ -2234,32 +2025,19 @@ test_read_new_wireless_group_names (void) NMSettingWireless *s_wifi; NMSettingWirelessSecurity *s_wsec; GBytes *ssid; - const guint8 *ssid_data; - gsize ssid_len; const char *expected_ssid = "foobar"; - gs_free_error GError *error = NULL; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR"/Test_New_Wireless_Group_Names", &error); - g_assert_no_error (error); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR"/Test_New_Wireless_Group_Names"); - /* Wifi setting */ s_wifi = nm_connection_get_setting_wireless (connection); g_assert (s_wifi); ssid = nm_setting_wireless_get_ssid (s_wifi); g_assert (ssid); - ssid_data = g_bytes_get_data (ssid, &ssid_len); - g_assert_cmpint (ssid_len, ==, strlen (expected_ssid)); - g_assert_cmpint (memcmp (ssid_data, expected_ssid, ssid_len), ==, 0); + g_assert (nm_utils_gbytes_equal_mem (ssid, expected_ssid, strlen (expected_ssid))); g_assert_cmpstr (nm_setting_wireless_get_mode (s_wifi), ==, NM_SETTING_WIRELESS_MODE_INFRA); - /* Wifi security setting */ s_wsec = nm_connection_get_setting_wireless_security (connection); g_assert (s_wsec); g_assert_cmpstr (nm_setting_wireless_security_get_key_mgmt (s_wsec), ==, "wpa-psk"); @@ -2344,17 +2122,9 @@ test_read_missing_vlan_setting (void) { gs_unref_object NMConnection *connection = NULL; NMSettingVlan *s_vlan; - gs_free_error GError *error = NULL; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR"/Test_Missing_Vlan_Setting", &error); - g_assert_no_error (error); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR"/Test_Missing_Vlan_Setting"); - /* Ensure the VLAN setting exists */ s_vlan = nm_connection_get_setting_vlan (connection); g_assert (s_vlan); g_assert_cmpint (nm_setting_vlan_get_id (s_vlan), ==, 0); @@ -2366,17 +2136,9 @@ test_read_missing_vlan_flags (void) { gs_unref_object NMConnection *connection = NULL; NMSettingVlan *s_vlan; - gs_free_error GError *error = NULL; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR"/Test_Missing_Vlan_Flags", &error); - g_assert_no_error (error); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR"/Test_Missing_Vlan_Flags"); - /* Ensure the VLAN setting exists */ s_vlan = nm_connection_get_setting_vlan (connection); g_assert (s_vlan); @@ -2389,19 +2151,15 @@ static void test_read_missing_id_uuid (void) { gs_unref_object NMConnection *connection = NULL; - gs_free_error GError *error = NULL; - gboolean success; + gs_free char *expected_uuid = NULL; + const char *FILENAME = TEST_KEYFILES_DIR"/Test_Missing_ID_UUID"; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR"/Test_Missing_ID_UUID", &error); - g_assert_no_error (error); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + expected_uuid = _nm_utils_uuid_generate_from_strings ("keyfile", FILENAME, NULL); + + connection = keyfile_read_connection_from_file (FILENAME); - /* Ensure the ID and UUID properties are there */ g_assert_cmpstr (nm_connection_get_id (connection), ==, "Test_Missing_ID_UUID"); - g_assert (nm_connection_get_uuid (connection)); + g_assert_cmpstr (nm_connection_get_uuid (connection), ==, expected_uuid); } static void @@ -2489,17 +2247,9 @@ test_read_enum_property (void) { gs_unref_object NMConnection *connection = NULL; NMSettingIPConfig *s_ip6; - gs_free_error GError *error = NULL; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR"/Test_Enum_Property", &error); - g_assert_no_error (error); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR"/Test_Enum_Property"); - /* IPv6 setting */ s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); g_assert_cmpint (nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6)), ==, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR); @@ -2549,17 +2299,9 @@ test_read_flags_property (void) { gs_unref_object NMConnection *connection = NULL; NMSettingGsm *s_gsm; - gs_free_error GError *error = NULL; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR"/Test_Flags_Property", &error); - g_assert_no_error (error); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR"/Test_Flags_Property"); - /* GSM setting */ s_gsm = nm_connection_get_setting_gsm (connection); g_assert (s_gsm); g_assert_cmpint (nm_setting_gsm_get_password_flags (s_gsm), ==, @@ -2612,14 +2354,8 @@ test_read_tc_config (void) NMTCQdisc *qdisc1, *qdisc2; NMTCAction *action1, *action2; NMTCTfilter *tfilter1, *tfilter2; - gs_free_error GError *error = NULL; - gboolean success; - connection = nms_keyfile_reader_from_file (TEST_KEYFILES_DIR "/Test_TC_Config", NULL); - g_assert (connection); - success = nm_connection_verify (connection, &error); - g_assert_no_error (error); - g_assert (success); + connection = keyfile_read_connection_from_file (TEST_KEYFILES_DIR "/Test_TC_Config"); s_tc = nm_connection_get_setting_tc_config (connection); g_assert (s_tc); @@ -2724,49 +2460,51 @@ test_write_tc_config (void) /*****************************************************************************/ static void -_escape_filename (const char *filename, gboolean would_be_ignored) +_escape_filename (gboolean with_extension, const char *filename, gboolean would_be_ignored) { gs_free char *esc = NULL; g_assert (filename && filename[0]); - if (!!would_be_ignored != !!nms_keyfile_utils_should_ignore_file (filename)) { + if (!!would_be_ignored != !!nms_keyfile_utils_should_ignore_file (filename, with_extension)) { if (would_be_ignored) g_error ("We expect filename \"%s\" to be ignored, but it isn't", filename); else g_error ("We expect filename \"%s\" not to be ignored, but it is", filename); } - esc = nms_keyfile_utils_escape_filename (filename); + esc = nms_keyfile_utils_escape_filename (filename, with_extension); g_assert (esc && esc[0]); g_assert (!strchr (esc, '/')); - if (nms_keyfile_utils_should_ignore_file (esc)) + if (nms_keyfile_utils_should_ignore_file (esc, with_extension)) g_error ("Escaping filename \"%s\" yielded \"%s\", but this is ignored", filename, esc); } static void test_nm_keyfile_plugin_utils_escape_filename (void) { - _escape_filename ("ab", FALSE); - _escape_filename (".vim-file.swp", TRUE); - _escape_filename (".vim-file.Swp", TRUE); - _escape_filename (".vim-file.SWP", TRUE); - _escape_filename (".vim-file.swpx", TRUE); - _escape_filename (".vim-file.Swpx", TRUE); - _escape_filename (".vim-file.SWPX", TRUE); - _escape_filename (".pem-file.pem", TRUE); - _escape_filename (".pem-file.Pem", TRUE); - _escape_filename (".pem-file.PEM", TRUE); - _escape_filename (".pem-file.der", TRUE); - _escape_filename (".pem-file.Der", TRUE); - _escape_filename (".mkstemp.ABCEDF", TRUE); - _escape_filename (".mkstemp.abcdef", TRUE); - _escape_filename (".mkstemp.123456", TRUE); - _escape_filename (".mkstemp.A23456", TRUE); - _escape_filename (".#emacs-locking", TRUE); - _escape_filename ("file-with-tilde~", TRUE); - _escape_filename (".file-with-dot", TRUE); + _escape_filename (FALSE, "ab", FALSE); + _escape_filename (FALSE, ".vim-file.swp", TRUE); + _escape_filename (FALSE, ".vim-file.Swp", TRUE); + _escape_filename (FALSE, ".vim-file.SWP", TRUE); + _escape_filename (FALSE, ".vim-file.swpx", TRUE); + _escape_filename (FALSE, ".vim-file.Swpx", TRUE); + _escape_filename (FALSE, ".vim-file.SWPX", TRUE); + _escape_filename (FALSE, ".pem-file.pem", TRUE); + _escape_filename (FALSE, ".pem-file.Pem", TRUE); + _escape_filename (FALSE, ".pem-file.PEM", TRUE); + _escape_filename (FALSE, ".pem-file.der", TRUE); + _escape_filename (FALSE, ".pem-file.Der", TRUE); + _escape_filename (FALSE, ".mkstemp.ABCEDF", TRUE); + _escape_filename (FALSE, ".mkstemp.abcdef", TRUE); + _escape_filename (FALSE, ".mkstemp.123456", TRUE); + _escape_filename (FALSE, ".mkstemp.A23456", TRUE); + _escape_filename (FALSE, ".#emacs-locking", TRUE); + _escape_filename (FALSE, "file-with-tilde~", TRUE); + _escape_filename (FALSE, ".file-with-dot", TRUE); + + _escape_filename (TRUE, "lala", TRUE); } /*****************************************************************************/ diff --git a/src/supplicant/nm-supplicant-config.c b/src/supplicant/nm-supplicant-config.c index 80db5baa..043b5550 100644 --- a/src/supplicant/nm-supplicant-config.c +++ b/src/supplicant/nm-supplicant-config.c @@ -89,23 +89,17 @@ config_option_free (ConfigOption *opt) } static void -blob_free (GByteArray *array) -{ - g_byte_array_free (array, TRUE); -} - -static void nm_supplicant_config_init (NMSupplicantConfig * self) { NMSupplicantConfigPrivate *priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self); priv->config = g_hash_table_new_full (nm_str_hash, g_str_equal, - (GDestroyNotify) g_free, + g_free, (GDestroyNotify) config_option_free); priv->blobs = g_hash_table_new_full (nm_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) blob_free); + g_free, + (GDestroyNotify) g_bytes_unref); priv->ap_scan = 1; priv->dispose_has_run = FALSE; @@ -198,7 +192,6 @@ nm_supplicant_config_add_blob (NMSupplicantConfig *self, ConfigOption *old_opt; ConfigOption *opt; OptType type; - GByteArray *blob; const guint8 *data; gsize data_len; @@ -226,9 +219,6 @@ nm_supplicant_config_add_blob (NMSupplicantConfig *self, return FALSE; } - blob = g_byte_array_sized_new (data_len); - g_byte_array_append (blob, data, data_len); - opt = g_slice_new0 (ConfigOption); opt->value = g_strdup_printf ("blob://%s", blobid); opt->len = strlen (opt->value); @@ -237,7 +227,9 @@ nm_supplicant_config_add_blob (NMSupplicantConfig *self, nm_log_info (LOGD_SUPPLICANT, "Config: added '%s' value '%s'", key, opt->value); g_hash_table_insert (priv->config, g_strdup (key), opt); - g_hash_table_insert (priv->blobs, g_strdup (blobid), blob); + g_hash_table_insert (priv->blobs, + g_strdup (blobid), + g_bytes_ref (value)); return TRUE; } @@ -491,6 +483,12 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, if (is_ap) { if (!nm_supplicant_config_add_option (self, "mode", "2", -1, NULL, error)) return FALSE; + + if ( nm_setting_wireless_get_hidden (setting) + && !nm_supplicant_config_add_option (self, + "ignore_broadcast_ssid", "1", + -1, NULL, error)) + return FALSE; } if ((is_adhoc || is_ap) && fixed_freq) { @@ -949,7 +947,7 @@ add_pkcs11_uri_with_pin (NMSupplicantConfig *self, const NMSettingSecretFlags pin_flags, GError **error) { - gs_strfreev gchar **split = NULL; + gs_strfreev char **split = NULL; gs_free char *tmp = NULL; gs_free char *tmp_log = NULL; gs_free char *pin_qattr = NULL; @@ -1009,6 +1007,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, guint32 frag, hdrs; gs_free char *frag_str = NULL; NMSetting8021xAuthFlags phase1_auth_flags; + nm_auto_free_gstring GString *eap_str = NULL; g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE); g_return_val_if_fail (setting != NULL, FALSE); @@ -1045,20 +1044,38 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, priv->ap_scan = 0; } - if (!ADD_STRING_LIST_VAL (self, setting, 802_1x, eap_method, eap_methods, "eap", ' ', TRUE, NULL, error)) - return FALSE; - - /* Check EAP method for special handling: PEAP + GTC, FAST */ + /* Build the "eap" option string while we check for EAP methods needing + * special handling: PEAP + GTC, FAST, external */ + eap_str = g_string_new (NULL); num_eap = nm_setting_802_1x_get_num_eap_methods (setting); for (i = 0; i < num_eap; i++) { const char *method = nm_setting_802_1x_get_eap_method (setting, i); - if (method && (strcasecmp (method, "fast") == 0)) { + if (nm_streq (method, "fast")) { fast = TRUE; priv->fast_required = TRUE; } + + if (nm_streq (method, "external")) { + if (num_eap == 1) { + g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "Connection settings managed externally to NM, connection" + " cannot be used with wpa_supplicant"); + return FALSE; + } + continue; + } + + if (eap_str->len) + g_string_append_c (eap_str, ' '); + g_string_append (eap_str, method); } + g_string_ascii_up (eap_str); + if ( eap_str->len + && !nm_supplicant_config_add_option (self, "eap", eap_str->str, -1, NULL, error)) + return FALSE; + /* Adjust the fragment size according to MTU, but do not set it higher than 1280-14 * for better compatibility */ hdrs = 14; /* EAPOL + EAP-TLS */ diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index e16e3130..5237acb2 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -1579,7 +1579,7 @@ assoc_add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat GHashTable *blobs; GHashTableIter iter; const char *blob_name; - GByteArray *blob_data; + GBytes *blob_data; assoc_data = add_network_data->assoc_data; if (assoc_data) @@ -1637,8 +1637,7 @@ assoc_add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat "AddBlob", g_variant_new ("(s@ay)", blob_name, - g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - blob_data->data, blob_data->len, 1)), + nm_utils_gbytes_to_variant_ay (blob_data)), G_DBUS_CALL_FLAGS_NONE, -1, priv->assoc_data->cancellable, @@ -1790,7 +1789,9 @@ scan_request_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) } void -nm_supplicant_interface_request_scan (NMSupplicantInterface *self, const GPtrArray *ssids) +nm_supplicant_interface_request_scan (NMSupplicantInterface *self, + GBytes *const*ssids, + guint ssids_len) { NMSupplicantInterfacePrivate *priv; GVariantBuilder builder; @@ -1804,15 +1805,14 @@ nm_supplicant_interface_request_scan (NMSupplicantInterface *self, const GPtrArr g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_add (&builder, "{sv}", "Type", g_variant_new_string ("active")); g_variant_builder_add (&builder, "{sv}", "AllowRoam", g_variant_new_boolean (FALSE)); - if (ssids) { + if (ssids_len > 0) { GVariantBuilder ssids_builder; g_variant_builder_init (&ssids_builder, G_VARIANT_TYPE_BYTESTRING_ARRAY); - for (i = 0; i < ssids->len; i++) { - GByteArray *ssid = g_ptr_array_index (ssids, i); + for (i = 0; i < ssids_len; i++) { + nm_assert (ssids[i]); g_variant_builder_add (&ssids_builder, "@ay", - g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - ssid->data, ssid->len, 1)); + nm_utils_gbytes_to_variant_ay (ssids[i])); } g_variant_builder_add (&builder, "{sv}", "SSIDs", g_variant_builder_end (&ssids_builder)); } diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h index 31272b3c..0365fdcd 100644 --- a/src/supplicant/nm-supplicant-interface.h +++ b/src/supplicant/nm-supplicant-interface.h @@ -100,7 +100,9 @@ void nm_supplicant_interface_disconnect (NMSupplicantInterface * iface); const char *nm_supplicant_interface_get_object_path (NMSupplicantInterface * iface); -void nm_supplicant_interface_request_scan (NMSupplicantInterface * self, const GPtrArray *ssids); +void nm_supplicant_interface_request_scan (NMSupplicantInterface *self, + GBytes *const*ssids, + guint ssids_len); NMSupplicantInterfaceState nm_supplicant_interface_get_state (NMSupplicantInterface * self); diff --git a/src/supplicant/nm-supplicant-settings-verify.c b/src/supplicant/nm-supplicant-settings-verify.c index 317afff9..1e25675d 100644 --- a/src/supplicant/nm-supplicant-settings-verify.c +++ b/src/supplicant/nm-supplicant-settings-verify.c @@ -151,6 +151,7 @@ static const struct Opt opt_table[] = { { "mka_ckn", TYPE_BYTES, 0, 65536, FALSE, NULL }, { "macsec_port", TYPE_INT, 1, 65534, FALSE, NULL }, { "ieee80211w", TYPE_INT, 0, 2, FALSE, NULL }, + { "ignore_broadcast_ssid", TYPE_INT, 0, 2, FALSE, NULL }, }; static gboolean @@ -220,7 +221,7 @@ validate_type_keyword (const struct Opt * opt, const guint32 len) { char **allowed; - gchar **candidates = NULL; + char **candidates = NULL; char **candidate; gboolean found = FALSE; diff --git a/src/supplicant/tests/meson.build b/src/supplicant/tests/meson.build index b8bad7f3..5e4cbdbe 100644 --- a/src/supplicant/tests/meson.build +++ b/src/supplicant/tests/meson.build @@ -4,7 +4,6 @@ exe = executable( test_unit, test_unit + '.c', dependencies: test_nm_dep, - c_args: nm_build_cflags, ) test( diff --git a/src/systemd/meson.build b/src/systemd/meson.build index 0c7d0aec..870721b0 100644 --- a/src/systemd/meson.build +++ b/src/systemd/meson.build @@ -2,6 +2,7 @@ sources = files( 'sd-adapt/nm-sd-adapt.c', 'src/basic/alloc-util.c', 'src/basic/escape.c', + 'src/basic/env-util.c', 'src/basic/ether-addr-util.c', 'src/basic/extract-word.c', 'src/basic/fd-util.c', diff --git a/src/systemd/nm-sd.c b/src/systemd/nm-sd.c index e05b345b..cbef91d1 100644 --- a/src/systemd/nm-sd.c +++ b/src/systemd/nm-sd.c @@ -35,7 +35,7 @@ typedef struct SDEventSource { } SDEventSource; static gboolean -event_prepare (GSource *source, gint *timeout_) +event_prepare (GSource *source, int *timeout_) { return sd_event_prepare (((SDEventSource *) source)->event) > 0; } diff --git a/src/systemd/sd-adapt/libudev.h b/src/systemd/sd-adapt/libudev.h deleted file mode 100644 index 8c49f075..00000000 --- a/src/systemd/sd-adapt/libudev.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -/* dummy header */ - -struct udev_device; diff --git a/src/systemd/sd-adapt/nm-sd-adapt.h b/src/systemd/sd-adapt/nm-sd-adapt.h index 380cbc60..e163eeda 100644 --- a/src/systemd/sd-adapt/nm-sd-adapt.h +++ b/src/systemd/sd-adapt/nm-sd-adapt.h @@ -26,10 +26,6 @@ #include <sys/resource.h> #include <time.h> -#ifndef CLOCK_BOOTTIME -#define CLOCK_BOOTTIME 7 -#endif - #if defined(HAVE_DECL_REALLOCARRAY) && HAVE_DECL_REALLOCARRAY == 1 #define HAVE_REALLOCARRAY 1 #else @@ -180,15 +176,6 @@ sd_notify (int unset_environment, const char *state) #define MAX_HANDLE_SZ 128 #endif -/* - * Some toolchains (E.G. uClibc 0.9.33 and earlier) don't export - * CLOCK_BOOTTIME even though the kernel supports it, so provide a - * local definition - */ -#ifndef CLOCK_BOOTTIME -#define CLOCK_BOOTTIME 7 -#endif - #include "sd-id128.h" #include "sparse-endian.h" #include "async.h" diff --git a/src/systemd/sd-adapt/env-util.h b/src/systemd/sd-adapt/sd-device.h index 637892c2..637892c2 100644 --- a/src/systemd/sd-adapt/env-util.h +++ b/src/systemd/sd-adapt/sd-device.h diff --git a/src/systemd/sd-adapt/udev-util.h b/src/systemd/sd-adapt/udev-util.h deleted file mode 100644 index 637892c2..00000000 --- a/src/systemd/sd-adapt/udev-util.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/systemd/sd-adapt/udev.h b/src/systemd/sd-adapt/udev.h deleted file mode 100644 index 419abcbf..00000000 --- a/src/systemd/sd-adapt/udev.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -/* dummy header */ - -#include "libudev.h" -#include "strv.h" diff --git a/src/systemd/src/basic/env-util.c b/src/systemd/src/basic/env-util.c new file mode 100644 index 00000000..52d12a8a --- /dev/null +++ b/src/systemd/src/basic/env-util.c @@ -0,0 +1,791 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "nm-sd-adapt.h" + +#include <errno.h> +#include <limits.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "alloc-util.h" +#include "env-util.h" +#include "escape.h" +#include "extract-word.h" +#include "macro.h" +#include "parse-util.h" +#include "string-util.h" +#include "strv.h" +#include "utf8.h" + +#if 0 /* NM_IGNORED */ +#define VALID_CHARS_ENV_NAME \ + DIGITS LETTERS \ + "_" + +#ifndef ARG_MAX +#define ARG_MAX ((size_t) sysconf(_SC_ARG_MAX)) +#endif + +static bool env_name_is_valid_n(const char *e, size_t n) { + const char *p; + + if (!e) + return false; + + if (n <= 0) + return false; + + if (e[0] >= '0' && e[0] <= '9') + return false; + + /* POSIX says the overall size of the environment block cannot + * be > ARG_MAX, an individual assignment hence cannot be + * either. Discounting the equal sign and trailing NUL this + * hence leaves ARG_MAX-2 as longest possible variable + * name. */ + if (n > ARG_MAX - 2) + return false; + + for (p = e; p < e + n; p++) + if (!strchr(VALID_CHARS_ENV_NAME, *p)) + return false; + + return true; +} + +bool env_name_is_valid(const char *e) { + if (!e) + return false; + + return env_name_is_valid_n(e, strlen(e)); +} + +bool env_value_is_valid(const char *e) { + if (!e) + return false; + + if (!utf8_is_valid(e)) + return false; + + /* bash allows tabs and newlines in environment variables, and so + * should we */ + if (string_has_cc(e, "\t\n")) + return false; + + /* POSIX says the overall size of the environment block cannot + * be > ARG_MAX, an individual assignment hence cannot be + * either. Discounting the shortest possible variable name of + * length 1, the equal sign and trailing NUL this hence leaves + * ARG_MAX-3 as longest possible variable value. */ + if (strlen(e) > ARG_MAX - 3) + return false; + + return true; +} + +bool env_assignment_is_valid(const char *e) { + const char *eq; + + eq = strchr(e, '='); + if (!eq) + return false; + + if (!env_name_is_valid_n(e, eq - e)) + return false; + + if (!env_value_is_valid(eq + 1)) + return false; + + /* POSIX says the overall size of the environment block cannot + * be > ARG_MAX, hence the individual variable assignments + * cannot be either, but let's leave room for one trailing NUL + * byte. */ + if (strlen(e) > ARG_MAX - 1) + return false; + + return true; +} + +bool strv_env_is_valid(char **e) { + char **p, **q; + + STRV_FOREACH(p, e) { + size_t k; + + if (!env_assignment_is_valid(*p)) + return false; + + /* Check if there are duplicate assginments */ + k = strcspn(*p, "="); + STRV_FOREACH(q, p + 1) + if (strneq(*p, *q, k) && (*q)[k] == '=') + return false; + } + + return true; +} + +bool strv_env_name_is_valid(char **l) { + char **p, **q; + + STRV_FOREACH(p, l) { + if (!env_name_is_valid(*p)) + return false; + + STRV_FOREACH(q, p + 1) + if (streq(*p, *q)) + return false; + } + + return true; +} + +bool strv_env_name_or_assignment_is_valid(char **l) { + char **p, **q; + + STRV_FOREACH(p, l) { + if (!env_assignment_is_valid(*p) && !env_name_is_valid(*p)) + return false; + + STRV_FOREACH(q, p + 1) + if (streq(*p, *q)) + return false; + } + + return true; +} + +static int env_append(char **r, char ***k, char **a) { + assert(r); + assert(k); + + if (!a) + return 0; + + /* Add the entries of a to *k unless they already exist in *r + * in which case they are overridden instead. This assumes + * there is enough space in the r array. */ + + for (; *a; a++) { + char **j; + size_t n; + + n = strcspn(*a, "="); + + if ((*a)[n] == '=') + n++; + + for (j = r; j < *k; j++) + if (strneq(*j, *a, n)) + break; + + if (j >= *k) + (*k)++; + else + free(*j); + + *j = strdup(*a); + if (!*j) + return -ENOMEM; + } + + return 0; +} + +char **strv_env_merge(size_t n_lists, ...) { + size_t n = 0; + char **l, **k, **r; + va_list ap; + size_t i; + + /* Merges an arbitrary number of environment sets */ + + va_start(ap, n_lists); + for (i = 0; i < n_lists; i++) { + l = va_arg(ap, char**); + n += strv_length(l); + } + va_end(ap); + + r = new(char*, n+1); + if (!r) + return NULL; + + k = r; + + va_start(ap, n_lists); + for (i = 0; i < n_lists; i++) { + l = va_arg(ap, char**); + if (env_append(r, &k, l) < 0) + goto fail; + } + va_end(ap); + + *k = NULL; + + return r; + +fail: + va_end(ap); + strv_free(r); + + return NULL; +} + +static bool env_match(const char *t, const char *pattern) { + assert(t); + assert(pattern); + + /* pattern a matches string a + * a matches a= + * a matches a=b + * a= matches a= + * a=b matches a=b + * a= does not match a + * a=b does not match a= + * a=b does not match a + * a=b does not match a=c */ + + if (streq(t, pattern)) + return true; + + if (!strchr(pattern, '=')) { + size_t l = strlen(pattern); + + return strneq(t, pattern, l) && t[l] == '='; + } + + return false; +} + +static bool env_entry_has_name(const char *entry, const char *name) { + const char *t; + + assert(entry); + assert(name); + + t = startswith(entry, name); + if (!t) + return false; + + return *t == '='; +} + +char **strv_env_delete(char **x, size_t n_lists, ...) { + size_t n, i = 0; + char **k, **r; + va_list ap; + + /* Deletes every entry from x that is mentioned in the other + * string lists */ + + n = strv_length(x); + + r = new(char*, n+1); + if (!r) + return NULL; + + STRV_FOREACH(k, x) { + size_t v; + + va_start(ap, n_lists); + for (v = 0; v < n_lists; v++) { + char **l, **j; + + l = va_arg(ap, char**); + STRV_FOREACH(j, l) + if (env_match(*k, *j)) + goto skip; + } + va_end(ap); + + r[i] = strdup(*k); + if (!r[i]) { + strv_free(r); + return NULL; + } + + i++; + continue; + + skip: + va_end(ap); + } + + r[i] = NULL; + + assert(i <= n); + + return r; +} + +char **strv_env_unset(char **l, const char *p) { + + char **f, **t; + + if (!l) + return NULL; + + assert(p); + + /* Drops every occurrence of the env var setting p in the + * string list. Edits in-place. */ + + for (f = t = l; *f; f++) { + + if (env_match(*f, p)) { + free(*f); + continue; + } + + *(t++) = *f; + } + + *t = NULL; + return l; +} + +char **strv_env_unset_many(char **l, ...) { + + char **f, **t; + + if (!l) + return NULL; + + /* Like strv_env_unset() but applies many at once. Edits in-place. */ + + for (f = t = l; *f; f++) { + bool found = false; + const char *p; + va_list ap; + + va_start(ap, l); + + while ((p = va_arg(ap, const char*))) { + if (env_match(*f, p)) { + found = true; + break; + } + } + + va_end(ap); + + if (found) { + free(*f); + continue; + } + + *(t++) = *f; + } + + *t = NULL; + return l; +} + +int strv_env_replace(char ***l, char *p) { + char **f; + const char *t, *name; + + assert(p); + + /* Replace first occurrence of the env var or add a new one in the + * string list. Drop other occurences. Edits in-place. Does not copy p. + * p must be a valid key=value assignment. + */ + + t = strchr(p, '='); + assert(t); + + name = strndupa(p, t - p); + + for (f = *l; f && *f; f++) + if (env_entry_has_name(*f, name)) { + free_and_replace(*f, p); + strv_env_unset(f + 1, *f); + return 0; + } + + /* We didn't find a match, we need to append p or create a new strv */ + if (strv_push(l, p) < 0) + return -ENOMEM; + return 1; +} + +char **strv_env_set(char **x, const char *p) { + + char **k; + _cleanup_strv_free_ char **r = NULL; + char* m[2] = { (char*) p, NULL }; + + /* Overrides the env var setting of p, returns a new copy */ + + r = new(char*, strv_length(x)+2); + if (!r) + return NULL; + + k = r; + if (env_append(r, &k, x) < 0) + return NULL; + + if (env_append(r, &k, m) < 0) + return NULL; + + *k = NULL; + + return TAKE_PTR(r); +} + +char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) { + char **i; + + assert(name); + + if (k <= 0) + return NULL; + + STRV_FOREACH_BACKWARDS(i, l) + if (strneq(*i, name, k) && + (*i)[k] == '=') + return *i + k + 1; + + if (flags & REPLACE_ENV_USE_ENVIRONMENT) { + const char *t; + + t = strndupa(name, k); + return getenv(t); + }; + + return NULL; +} + +char *strv_env_get(char **l, const char *name) { + assert(name); + + return strv_env_get_n(l, name, strlen(name), 0); +} + +char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) { + char **p, **q; + int k = 0; + + STRV_FOREACH(p, e) { + size_t n; + bool duplicate = false; + + if (!env_assignment_is_valid(*p)) { + if (invalid_callback) + invalid_callback(*p, userdata); + free(*p); + continue; + } + + n = strcspn(*p, "="); + STRV_FOREACH(q, p + 1) + if (strneq(*p, *q, n) && (*q)[n] == '=') { + duplicate = true; + break; + } + + if (duplicate) { + free(*p); + continue; + } + + e[k++] = *p; + } + + if (e) + e[k] = NULL; + + return e; +} + +char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) { + enum { + WORD, + CURLY, + VARIABLE, + VARIABLE_RAW, + TEST, + DEFAULT_VALUE, + ALTERNATE_VALUE, + } state = WORD; + + const char *e, *word = format, *test_value; + char *k; + _cleanup_free_ char *r = NULL; + size_t i, len; + int nest = 0; + + assert(format); + + for (e = format, i = 0; *e && i < n; e ++, i ++) + switch (state) { + + case WORD: + if (*e == '$') + state = CURLY; + break; + + case CURLY: + if (*e == '{') { + k = strnappend(r, word, e-word-1); + if (!k) + return NULL; + + free_and_replace(r, k); + + word = e-1; + state = VARIABLE; + nest++; + } else if (*e == '$') { + k = strnappend(r, word, e-word); + if (!k) + return NULL; + + free_and_replace(r, k); + + word = e+1; + state = WORD; + + } else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_CHARS_ENV_NAME, *e)) { + k = strnappend(r, word, e-word-1); + if (!k) + return NULL; + + free_and_replace(r, k); + + word = e-1; + state = VARIABLE_RAW; + + } else + state = WORD; + break; + + case VARIABLE: + if (*e == '}') { + const char *t; + + t = strv_env_get_n(env, word+2, e-word-2, flags); + + k = strappend(r, t); + if (!k) + return NULL; + + free_and_replace(r, k); + + word = e+1; + state = WORD; + } else if (*e == ':') { + if (!(flags & REPLACE_ENV_ALLOW_EXTENDED)) + /* Treat this as unsupported syntax, i.e. do no replacement */ + state = WORD; + else { + len = e-word-2; + state = TEST; + } + } + break; + + case TEST: + if (*e == '-') + state = DEFAULT_VALUE; + else if (*e == '+') + state = ALTERNATE_VALUE; + else { + state = WORD; + break; + } + + test_value = e+1; + break; + + case DEFAULT_VALUE: /* fall through */ + case ALTERNATE_VALUE: + assert(flags & REPLACE_ENV_ALLOW_EXTENDED); + + if (*e == '{') { + nest++; + break; + } + + if (*e != '}') + break; + + nest--; + if (nest == 0) { + const char *t; + _cleanup_free_ char *v = NULL; + + t = strv_env_get_n(env, word+2, len, flags); + + if (t && state == ALTERNATE_VALUE) + t = v = replace_env_n(test_value, e-test_value, env, flags); + else if (!t && state == DEFAULT_VALUE) + t = v = replace_env_n(test_value, e-test_value, env, flags); + + k = strappend(r, t); + if (!k) + return NULL; + + free_and_replace(r, k); + + word = e+1; + state = WORD; + } + break; + + case VARIABLE_RAW: + assert(flags & REPLACE_ENV_ALLOW_BRACELESS); + + if (!strchr(VALID_CHARS_ENV_NAME, *e)) { + const char *t; + + t = strv_env_get_n(env, word+1, e-word-1, flags); + + k = strappend(r, t); + if (!k) + return NULL; + + free_and_replace(r, k); + + word = e--; + i--; + state = WORD; + } + break; + } + + if (state == VARIABLE_RAW) { + const char *t; + + assert(flags & REPLACE_ENV_ALLOW_BRACELESS); + + t = strv_env_get_n(env, word+1, e-word-1, flags); + return strappend(r, t); + } else + return strnappend(r, word, e-word); +} + +char **replace_env_argv(char **argv, char **env) { + char **ret, **i; + size_t k = 0, l = 0; + + l = strv_length(argv); + + ret = new(char*, l+1); + if (!ret) + return NULL; + + STRV_FOREACH(i, argv) { + + /* If $FOO appears as single word, replace it by the split up variable */ + if ((*i)[0] == '$' && !IN_SET((*i)[1], '{', '$')) { + char *e; + char **w, **m = NULL; + size_t q; + + e = strv_env_get(env, *i+1); + if (e) { + int r; + + r = strv_split_extract(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_QUOTES); + if (r < 0) { + ret[k] = NULL; + strv_free(ret); + return NULL; + } + } else + m = NULL; + + q = strv_length(m); + l = l + q - 1; + + w = reallocarray(ret, l + 1, sizeof(char *)); + if (!w) { + ret[k] = NULL; + strv_free(ret); + strv_free(m); + return NULL; + } + + ret = w; + if (m) { + memcpy(ret + k, m, q * sizeof(char*)); + free(m); + } + + k += q; + continue; + } + + /* If ${FOO} appears as part of a word, replace it by the variable as-is */ + ret[k] = replace_env(*i, env, 0); + if (!ret[k]) { + strv_free(ret); + return NULL; + } + k++; + } + + ret[k] = NULL; + return ret; +} +#endif /* NM_IGNORED */ + +int getenv_bool(const char *p) { + const char *e; + + e = getenv(p); + if (!e) + return -ENXIO; + + return parse_boolean(e); +} + +#if 0 /* NM_IGNORED */ +int getenv_bool_secure(const char *p) { + const char *e; + + e = secure_getenv(p); + if (!e) + return -ENXIO; + + return parse_boolean(e); +} + +int serialize_environment(FILE *f, char **environment) { + char **e; + + STRV_FOREACH(e, environment) { + _cleanup_free_ char *ce; + + ce = cescape(*e); + if (!ce) + return -ENOMEM; + + fprintf(f, "env=%s\n", ce); + } + + /* caller should call ferror() */ + + return 0; +} + +int deserialize_environment(char ***environment, const char *line) { + char *uce; + int r; + + assert(line); + assert(environment); + + assert(startswith(line, "env=")); + r = cunescape(line + 4, 0, &uce); + if (r < 0) + return r; + + return strv_env_replace(environment, uce); +} +#endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/env-util.h b/src/systemd/src/basic/env-util.h new file mode 100644 index 00000000..174433ea --- /dev/null +++ b/src/systemd/src/basic/env-util.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> + +#include "macro.h" +#include "string.h" + +bool env_name_is_valid(const char *e); +bool env_value_is_valid(const char *e); +bool env_assignment_is_valid(const char *e); + +enum { + REPLACE_ENV_USE_ENVIRONMENT = 1u, + REPLACE_ENV_ALLOW_BRACELESS = 2u, + REPLACE_ENV_ALLOW_EXTENDED = 4u, +}; + +char *replace_env_n(const char *format, size_t n, char **env, unsigned flags); +char **replace_env_argv(char **argv, char **env); + +static inline char *replace_env(const char *format, char **env, unsigned flags) { + return replace_env_n(format, strlen(format), env, flags); +} + +bool strv_env_is_valid(char **e); +#define strv_env_clean(l) strv_env_clean_with_callback(l, NULL, NULL) +char **strv_env_clean_with_callback(char **l, void (*invalid_callback)(const char *p, void *userdata), void *userdata); + +bool strv_env_name_is_valid(char **l); +bool strv_env_name_or_assignment_is_valid(char **l); + +char **strv_env_merge(size_t n_lists, ...); +char **strv_env_delete(char **x, size_t n_lists, ...); /* New copy */ + +char **strv_env_set(char **x, const char *p); /* New copy ... */ +char **strv_env_unset(char **l, const char *p); /* In place ... */ +char **strv_env_unset_many(char **l, ...) _sentinel_; +int strv_env_replace(char ***l, char *p); /* In place ... */ + +char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) _pure_; +char *strv_env_get(char **x, const char *n) _pure_; + +int getenv_bool(const char *p); +int getenv_bool_secure(const char *p); + +int serialize_environment(FILE *f, char **environment); +int deserialize_environment(char ***environment, const char *line); diff --git a/src/systemd/src/basic/ether-addr-util.c b/src/systemd/src/basic/ether-addr-util.c index 6f946c3e..ed92bc60 100644 --- a/src/systemd/src/basic/ether-addr-util.c +++ b/src/systemd/src/basic/ether-addr-util.c @@ -1,7 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2014 Tom Gundersen -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/basic/ether-addr-util.h b/src/systemd/src/basic/ether-addr-util.h index f02cefea..3be03700 100644 --- a/src/systemd/src/basic/ether-addr-util.h +++ b/src/systemd/src/basic/ether-addr-util.h @@ -1,10 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - Copyright © 2014 Tom Gundersen -***/ - #include <net/ethernet.h> #include <stdbool.h> diff --git a/src/systemd/src/basic/fd-util.h b/src/systemd/src/basic/fd-util.h index 8adc959d..00303a7e 100644 --- a/src/systemd/src/basic/fd-util.h +++ b/src/systemd/src/basic/fd-util.h @@ -78,8 +78,12 @@ int acquire_data_fd(const void *data, size_t size, unsigned flags); int fd_duplicate_data_fd(int fd); /* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */ -#define ERRNO_IS_DISCONNECT(r) \ - IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH) +/* The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases. + * See the icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources */ +#define ERRNO_IS_DISCONNECT(r) \ + IN_SET(r, \ + ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, \ + ENETUNREACH, EHOSTUNREACH, ENOPROTOOPT, EHOSTDOWN, ENONET) /* Resource exhaustion, could be our fault or general system trouble */ #define ERRNO_IS_RESOURCE(r) \ diff --git a/src/systemd/src/basic/fileio.c b/src/systemd/src/basic/fileio.c index 2d3aef2c..3978c3a7 100644 --- a/src/systemd/src/basic/fileio.c +++ b/src/systemd/src/basic/fileio.c @@ -1235,9 +1235,13 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { const char *fn; char *t; - assert(p); assert(ret); + if (isempty(p)) + return -EINVAL; + if (path_equal(p, "/")) + return -EINVAL; + /* * Turns this: * /foo/bar/waldo @@ -1269,9 +1273,13 @@ int tempfn_random(const char *p, const char *extra, char **ret) { uint64_t u; unsigned i; - assert(p); assert(ret); + if (isempty(p)) + return -EINVAL; + if (path_equal(p, "/")) + return -EINVAL; + /* * Turns this: * /foo/bar/waldo @@ -1330,7 +1338,10 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) { if (!t) return -ENOMEM; - x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra); + if (isempty(p)) + x = stpcpy(stpcpy(t, ".#"), extra); + else + x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra); u = random_u64(); for (i = 0; i < 16; i++) { @@ -1417,7 +1428,8 @@ int open_tmpfile_unlinkable(const char *directory, int flags) { r = tmp_dir(&directory); if (r < 0) return r; - } + } else if (isempty(directory)) + return -EINVAL; /* Returns an unlinked temporary file that cannot be linked into the file system anymore */ @@ -1452,22 +1464,14 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) { * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */ - { - _cleanup_free_ char *dn = NULL; - - dn = dirname_malloc(target); - if (!dn) - return -ENOMEM; - - fd = open(dn, O_TMPFILE|flags, 0640); - if (fd >= 0) { - *ret_path = NULL; - return fd; - } - - log_debug_errno(errno, "Failed to use O_TMPFILE on %s: %m", dn); + fd = open_parent(target, O_TMPFILE|flags, 0640); + if (fd >= 0) { + *ret_path = NULL; + return fd; } + log_debug_errno(fd, "Failed to use O_TMPFILE for %s: %m", target); + r = tempfn_random(target, NULL, &tmp); if (r < 0) return r; diff --git a/src/systemd/src/basic/fs-util.c b/src/systemd/src/basic/fs-util.c index e3ae9916..8c19e9c7 100644 --- a/src/systemd/src/basic/fs-util.c +++ b/src/systemd/src/basic/fs-util.c @@ -442,6 +442,31 @@ int mkfifo_atomic(const char *path, mode_t mode) { return 0; } +int mkfifoat_atomic(int dirfd, const char *path, mode_t mode) { + _cleanup_free_ char *t = NULL; + int r; + + assert(path); + + if (path_is_absolute(path)) + return mkfifo_atomic(path, mode); + + /* We're only interested in the (random) filename. */ + r = tempfn_random_child("", NULL, &t); + if (r < 0) + return r; + + if (mkfifoat(dirfd, t, mode) < 0) + return -errno; + + if (renameat(dirfd, t, dirfd, path) < 0) { + unlink_noerrno(t); + return -errno; + } + + return 0; +} + int get_files_in_directory(const char *path, char ***list) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; @@ -679,7 +704,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (!original_root && !ret && (flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_OPEN|CHASE_STEP)) == CHASE_OPEN) { /* Shortcut the CHASE_OPEN case if the caller isn't interested in the actual path and has no root set * and doesn't care about any of the other special features we provide either. */ - r = open(path, O_PATH|O_CLOEXEC); + r = open(path, O_PATH|O_CLOEXEC|((flags & CHASE_NOFOLLOW) ? O_NOFOLLOW : 0)); if (r < 0) return -errno; @@ -834,7 +859,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0) return -EREMOTE; - if (S_ISLNK(st.st_mode)) { + if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) { char *joined; _cleanup_free_ char *destination = NULL; @@ -1165,7 +1190,7 @@ int unlinkat_deallocate(int fd, const char *name, int flags) { } int fsync_directory_of_file(int fd) { - _cleanup_free_ char *path = NULL, *dn = NULL; + _cleanup_free_ char *path = NULL; _cleanup_close_ int dfd = -1; int r; @@ -1191,17 +1216,41 @@ int fsync_directory_of_file(int fd) { if (!path_is_absolute(path)) return -EINVAL; - dn = dirname_malloc(path); - if (!dn) - return -ENOMEM; - - dfd = open(dn, O_RDONLY|O_CLOEXEC|O_DIRECTORY); + dfd = open_parent(path, O_CLOEXEC, 0); if (dfd < 0) - return -errno; + return dfd; if (fsync(dfd) < 0) return -errno; return 0; } + +int open_parent(const char *path, int flags, mode_t mode) { + _cleanup_free_ char *parent = NULL; + int fd; + + if (isempty(path)) + return -EINVAL; + if (path_equal(path, "/")) /* requesting the parent of the root dir is fishy, let's prohibit that */ + return -EINVAL; + + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; + + /* Let's insist on O_DIRECTORY since the parent of a file or directory is a directory. Except if we open an + * O_TMPFILE file, because in that case we are actually create a regular file below the parent directory. */ + + if ((flags & O_PATH) == O_PATH) + flags |= O_DIRECTORY; + else if ((flags & O_TMPFILE) != O_TMPFILE) + flags |= O_DIRECTORY|O_RDONLY; + + fd = open(parent, flags, mode); + if (fd < 0) + return -errno; + + return fd; +} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/fs-util.h b/src/systemd/src/basic/fs-util.h index 28566773..4b656258 100644 --- a/src/systemd/src/basic/fs-util.h +++ b/src/systemd/src/basic/fs-util.h @@ -42,6 +42,7 @@ int symlink_idempotent(const char *from, const char *to); int symlink_atomic(const char *from, const char *to); int mknod_atomic(const char *path, mode_t mode, dev_t dev); int mkfifo_atomic(const char *path, mode_t mode); +int mkfifoat_atomic(int dir_fd, const char *path, mode_t mode); int get_files_in_directory(const char *path, char ***list); @@ -72,6 +73,7 @@ enum { CHASE_OPEN = 1 << 4, /* If set, return an O_PATH object to the final component */ CHASE_TRAIL_SLASH = 1 << 5, /* If set, any trailing slash will be preserved */ CHASE_STEP = 1 << 6, /* If set, just execute a single step of the normalization */ + CHASE_NOFOLLOW = 1 << 7, /* Only valid with CHASE_OPEN: when the path's right-most component refers to symlink return O_PATH fd of the symlink, rather than following it. */ }; /* How many iterations to execute before returning -ELOOP */ @@ -103,3 +105,5 @@ void unlink_tempfilep(char (*p)[]); int unlinkat_deallocate(int fd, const char *name, int flags); int fsync_directory_of_file(int fd); + +int open_parent(const char *path, int flags, mode_t mode); diff --git a/src/systemd/src/basic/hash-funcs.c b/src/systemd/src/basic/hash-funcs.c index 7ed35cb1..fc2c4f78 100644 --- a/src/systemd/src/basic/hash-funcs.c +++ b/src/systemd/src/basic/hash-funcs.c @@ -1,7 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2014 Michal Schmidt -***/ #include "nm-sd-adapt.h" @@ -78,7 +75,7 @@ void trivial_hash_func(const void *p, struct siphash *state) { } int trivial_compare_func(const void *a, const void *b) { - return a < b ? -1 : (a > b ? 1 : 0); + return CMP(a, b); } const struct hash_ops trivial_hash_ops = { @@ -94,7 +91,7 @@ int uint64_compare_func(const void *_a, const void *_b) { uint64_t a, b; a = *(const uint64_t*) _a; b = *(const uint64_t*) _b; - return a < b ? -1 : (a > b ? 1 : 0); + return CMP(a, b); } const struct hash_ops uint64_hash_ops = { @@ -112,7 +109,7 @@ int devt_compare_func(const void *_a, const void *_b) { dev_t a, b; a = *(const dev_t*) _a; b = *(const dev_t*) _b; - return a < b ? -1 : (a > b ? 1 : 0); + return CMP(a, b); } const struct hash_ops devt_hash_ops = { diff --git a/src/systemd/src/basic/hash-funcs.h b/src/systemd/src/basic/hash-funcs.h index 3715c56e..fa45cfe2 100644 --- a/src/systemd/src/basic/hash-funcs.h +++ b/src/systemd/src/basic/hash-funcs.h @@ -1,10 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - Copyright © 2014 Michal Schmidt -***/ - #include "macro.h" #include "siphash24.h" diff --git a/src/systemd/src/basic/hashmap.c b/src/systemd/src/basic/hashmap.c index c91f8bd2..cfddeafe 100644 --- a/src/systemd/src/basic/hashmap.c +++ b/src/systemd/src/basic/hashmap.c @@ -1,7 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2014 Michal Schmidt -***/ #include "nm-sd-adapt.h" @@ -11,8 +8,9 @@ #include <string.h> #include "alloc-util.h" -#include "hashmap.h" +#include "env-util.h" #include "fileio.h" +#include "hashmap.h" #include "macro.h" #include "mempool.h" #include "process-util.h" @@ -771,20 +769,31 @@ static void reset_direct_storage(HashmapBase *h) { memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets); } +static bool use_pool(void) { + static int b = -1; + + if (!is_main_thread()) + return false; + + if (b < 0) + b = getenv_bool("SYSTEMD_MEMPOOL") != 0; + + return b; +} + static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) { HashmapBase *h; const struct hashmap_type_info *hi = &hashmap_type_info[type]; - bool use_pool; + bool up; - use_pool = is_main_thread(); - - h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size); + up = use_pool(); + h = up ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size); if (!h) return NULL; h->type = type; - h->from_pool = use_pool; + h->from_pool = up; h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops; if (type == HASHMAP_TYPE_ORDERED) { @@ -862,9 +871,11 @@ static void hashmap_free_no_clear(HashmapBase *h) { assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0); #endif - if (h->from_pool) + if (h->from_pool) { + /* Ensure that the object didn't get migrated between threads. */ + assert_se(is_main_thread()); mempool_free_tile(hashmap_type_info[h->type].mempool, h); - else + } else free(h); } diff --git a/src/systemd/src/basic/hashmap.h b/src/systemd/src/basic/hashmap.h index d1d1b9c8..274afb39 100644 --- a/src/systemd/src/basic/hashmap.h +++ b/src/systemd/src/basic/hashmap.h @@ -1,10 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - Copyright © 2014 Michal Schmidt -***/ - #include <limits.h> #include <stdbool.h> #include <stddef.h> diff --git a/src/systemd/src/basic/in-addr-util.c b/src/systemd/src/basic/in-addr-util.c index d945567a..19d0db25 100644 --- a/src/systemd/src/basic/in-addr-util.c +++ b/src/systemd/src/basic/in-addr-util.c @@ -576,4 +576,27 @@ int in_addr_prefix_from_string_auto( return 0; } + +void in_addr_data_hash_func(const void *p, struct siphash *state) { + const struct in_addr_data *a = p; + + siphash24_compress(&a->family, sizeof(a->family), state); + siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state); +} + +int in_addr_data_compare_func(const void *a, const void *b) { + const struct in_addr_data *x = a, *y = b; + int r; + + r = CMP(x->family, y->family); + if (r != 0) + return r; + + return memcmp(&x->address, &y->address, FAMILY_ADDRESS_SIZE(x->family)); +} + +const struct hash_ops in_addr_data_hash_ops = { + .hash = in_addr_data_hash_func, + .compare = in_addr_data_compare_func, +}; #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/in-addr-util.h b/src/systemd/src/basic/in-addr-util.h index 956c00a8..e4be30dc 100644 --- a/src/systemd/src/basic/in-addr-util.h +++ b/src/systemd/src/basic/in-addr-util.h @@ -5,6 +5,7 @@ #include <stddef.h> #include <sys/socket.h> +#include "hash-funcs.h" #include "macro.h" #include "util.h" @@ -53,3 +54,7 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) { } #define IN_ADDR_NULL ((union in_addr_union) {}) + +void in_addr_data_hash_func(const void *p, struct siphash *state); +int in_addr_data_compare_func(const void *a, const void *b); +extern const struct hash_ops in_addr_data_hash_ops; diff --git a/src/systemd/src/basic/macro.h b/src/systemd/src/basic/macro.h index cdb54f82..22193fe3 100644 --- a/src/systemd/src/basic/macro.h +++ b/src/systemd/src/basic/macro.h @@ -7,7 +7,7 @@ #include <sys/sysmacros.h> #include <sys/types.h> -#define _printf_(a,b) __attribute__ ((format (printf, a, b))) +#define _printf_(a, b) __attribute__ ((format (printf, a, b))) #ifdef __clang__ # define _alloc_(...) #else @@ -22,8 +22,8 @@ #define _packed_ __attribute__ ((packed)) #define _malloc_ __attribute__ ((malloc)) #define _weak_ __attribute__ ((weak)) -#define _likely_(x) (__builtin_expect(!!(x),1)) -#define _unlikely_(x) (__builtin_expect(!!(x),0)) +#define _likely_(x) (__builtin_expect(!!(x), 1)) +#define _unlikely_(x) (__builtin_expect(!!(x), 0)) #define _public_ __attribute__ ((visibility("default"))) #define _hidden_ __attribute__ ((visibility("hidden"))) #define _weakref_(x) __attribute__((weakref(#x))) @@ -155,10 +155,10 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { # define VOID_0 ((void*)0) #endif -#define ELEMENTSOF(x) \ - __extension__ (__builtin_choose_expr( \ +#define ELEMENTSOF(x) \ + (__builtin_choose_expr( \ !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \ - sizeof(x)/sizeof((x)[0]), \ + sizeof(x)/sizeof((x)[0]), \ VOID_0)) /* @@ -176,23 +176,23 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { */ #define container_of(ptr, type, member) __container_of(UNIQ, (ptr), type, member) #define __container_of(uniq, ptr, type, member) \ - __extension__ ({ \ + ({ \ const typeof( ((type*)0)->member ) *UNIQ_T(A, uniq) = (ptr); \ - (type*)( (char *)UNIQ_T(A, uniq) - offsetof(type,member) ); \ + (type*)( (char *)UNIQ_T(A, uniq) - offsetof(type, member) ); \ }) #undef MAX #define MAX(a, b) __MAX(UNIQ, (a), UNIQ, (b)) #define __MAX(aq, a, bq, b) \ - __extension__ ({ \ + ({ \ const typeof(a) UNIQ_T(A, aq) = (a); \ const typeof(b) UNIQ_T(B, bq) = (b); \ - UNIQ_T(A,aq) > UNIQ_T(B,bq) ? UNIQ_T(A,aq) : UNIQ_T(B,bq); \ + UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \ }) /* evaluates to (void) if _A or _B are not constant or of different types */ #define CONST_MAX(_A, _B) \ - __extension__ (__builtin_choose_expr( \ + (__builtin_choose_expr( \ __builtin_constant_p(_A) && \ __builtin_constant_p(_B) && \ __builtin_types_compatible_p(typeof(_A), typeof(_B)), \ @@ -202,47 +202,56 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { /* takes two types and returns the size of the larger one */ #define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; })) -#define MAX3(x,y,z) \ - __extension__ ({ \ - const typeof(x) _c = MAX(x,y); \ - MAX(_c, z); \ - }) +#define MAX3(x, y, z) \ + ({ \ + const typeof(x) _c = MAX(x, y); \ + MAX(_c, z); \ + }) #undef MIN #define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b)) #define __MIN(aq, a, bq, b) \ - __extension__ ({ \ + ({ \ const typeof(a) UNIQ_T(A, aq) = (a); \ const typeof(b) UNIQ_T(B, bq) = (b); \ - UNIQ_T(A,aq) < UNIQ_T(B,bq) ? UNIQ_T(A,aq) : UNIQ_T(B,bq); \ + UNIQ_T(A, aq) < UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \ }) -#define MIN3(x,y,z) \ - __extension__ ({ \ - const typeof(x) _c = MIN(x,y); \ - MIN(_c, z); \ - }) +#define MIN3(x, y, z) \ + ({ \ + const typeof(x) _c = MIN(x, y); \ + MIN(_c, z); \ + }) #define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b)) #define __LESS_BY(aq, a, bq, b) \ - __extension__ ({ \ + ({ \ + const typeof(a) UNIQ_T(A, aq) = (a); \ + const typeof(b) UNIQ_T(B, bq) = (b); \ + UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) - UNIQ_T(B, bq) : 0; \ + }) + +#define CMP(a, b) __CMP(UNIQ, (a), UNIQ, (b)) +#define __CMP(aq, a, bq, b) \ + ({ \ const typeof(a) UNIQ_T(A, aq) = (a); \ const typeof(b) UNIQ_T(B, bq) = (b); \ - UNIQ_T(A,aq) > UNIQ_T(B,bq) ? UNIQ_T(A,aq) - UNIQ_T(B,bq) : 0; \ + UNIQ_T(A, aq) < UNIQ_T(B, bq) ? -1 : \ + UNIQ_T(A, aq) > UNIQ_T(B, bq) ? 1 : 0; \ }) #undef CLAMP #define CLAMP(x, low, high) __CLAMP(UNIQ, (x), UNIQ, (low), UNIQ, (high)) #define __CLAMP(xq, x, lowq, low, highq, high) \ - __extension__ ({ \ - const typeof(x) UNIQ_T(X,xq) = (x); \ - const typeof(low) UNIQ_T(LOW,lowq) = (low); \ - const typeof(high) UNIQ_T(HIGH,highq) = (high); \ - UNIQ_T(X,xq) > UNIQ_T(HIGH,highq) ? \ - UNIQ_T(HIGH,highq) : \ - UNIQ_T(X,xq) < UNIQ_T(LOW,lowq) ? \ - UNIQ_T(LOW,lowq) : \ - UNIQ_T(X,xq); \ + ({ \ + const typeof(x) UNIQ_T(X, xq) = (x); \ + const typeof(low) UNIQ_T(LOW, lowq) = (low); \ + const typeof(high) UNIQ_T(HIGH, highq) = (high); \ + UNIQ_T(X, xq) > UNIQ_T(HIGH, highq) ? \ + UNIQ_T(HIGH, highq) : \ + UNIQ_T(X, xq) < UNIQ_T(LOW, lowq) ? \ + UNIQ_T(LOW, lowq) : \ + UNIQ_T(X, xq); \ }) /* [(x + y - 1) / y] suffers from an integer overflow, even though the @@ -250,18 +259,54 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { * [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the * quotient and the remainder, so both should be equally fast. */ #define DIV_ROUND_UP(_x, _y) \ - __extension__ ({ \ + ({ \ const typeof(_x) __x = (_x); \ const typeof(_y) __y = (_y); \ (__x / __y + !!(__x % __y)); \ }) +#ifdef __COVERITY__ + +/* Use special definitions of assertion macros in order to prevent + * false positives of ASSERT_SIDE_EFFECT on Coverity static analyzer + * for uses of assert_se() and assert_return(). + * + * These definitions make expression go through a (trivial) function + * call to ensure they are not discarded. Also use ! or !! to ensure + * the boolean expressions are seen as such. + * + * This technique has been described and recommended in: + * https://community.synopsys.com/s/question/0D534000046Yuzb/suppressing-assertsideeffect-for-functions-that-allow-for-sideeffects + */ + +extern void __coverity_panic__(void); + +static inline int __coverity_check__(int condition) { + return condition; +} + +#define assert_message_se(expr, message) \ + do { \ + if (__coverity_check__(!(expr))) \ + __coverity_panic__(); \ + } while (false) + +#define assert_log(expr, message) __coverity_check__(!!(expr)) + +#else /* ! __COVERITY__ */ + #define assert_message_se(expr, message) \ do { \ if (_unlikely_(!(expr))) \ log_assert_failed(message, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ } while (false) +#define assert_log(expr, message) ((_likely_(expr)) \ + ? (true) \ + : (log_assert_failed_return(message, __FILE__, __LINE__, __PRETTY_FUNCTION__), false)) + +#endif /* __COVERITY__ */ + #define assert_se(expr) assert_message_se(expr, #expr) /* We override the glibc assert() here. */ @@ -294,10 +339,6 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { REENABLE_WARNING #endif -#define assert_log(expr, message) ((_likely_(expr)) \ - ? (true) \ - : (log_assert_failed_return(message, __FILE__, __LINE__, __PRETTY_FUNCTION__), false)) - #define assert_return(expr, r) \ do { \ if (!assert_log(expr, #expr)) \ @@ -419,7 +460,7 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__ * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) +#if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) #define thread_local _Thread_local #else #define thread_local __thread diff --git a/src/systemd/src/basic/mempool.c b/src/systemd/src/basic/mempool.c index a0154263..dd1b1e5f 100644 --- a/src/systemd/src/basic/mempool.c +++ b/src/systemd/src/basic/mempool.c @@ -1,7 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2014 Michal Schmidt -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/basic/mempool.h b/src/systemd/src/basic/mempool.h index 291415de..4098535c 100644 --- a/src/systemd/src/basic/mempool.h +++ b/src/systemd/src/basic/mempool.h @@ -1,10 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - Copyright © 2014 Michal Schmidt -***/ - #include <stddef.h> struct pool; diff --git a/src/systemd/src/basic/parse-util.c b/src/systemd/src/basic/parse-util.c index 7d6bcb5a..b0ccce28 100644 --- a/src/systemd/src/basic/parse-util.c +++ b/src/systemd/src/basic/parse-util.c @@ -642,6 +642,8 @@ int parse_permille_unbounded(const char *p) { r = safe_atoi(n, &v); if (r < 0) return r; + if (v < 0) + return -ERANGE; } else { pc = endswith(p, "%"); if (!pc) @@ -662,15 +664,14 @@ int parse_permille_unbounded(const char *p) { r = safe_atoi(n, &v); if (r < 0) return r; + if (v < 0) + return -ERANGE; if (v > (INT_MAX - q) / 10) return -ERANGE; v = v * 10 + q; } - if (v < 0) - return -ERANGE; - return v; } diff --git a/src/systemd/src/basic/path-util.c b/src/systemd/src/basic/path-util.c index 69bdb894..5202eae3 100644 --- a/src/systemd/src/basic/path-util.c +++ b/src/systemd/src/basic/path-util.c @@ -113,10 +113,7 @@ int path_make_absolute_cwd(const char *p, char **ret) { if (r < 0) return r; - if (endswith(cwd, "/")) - c = strjoin(cwd, p); - else - c = strjoin(cwd, "/", p); + c = path_join(NULL, cwd, p); } if (!c) return -ENOMEM; @@ -426,6 +423,7 @@ char* path_startswith(const char *path, const char *prefix) { prefix += b; } } +#endif /* NM_IGNORED */ int path_compare(const char *a, const char *b) { int d; @@ -477,6 +475,7 @@ bool path_equal(const char *a, const char *b) { return path_compare(a, b) == 0; } +#if 0 /* NM_IGNORED */ bool path_equal_or_files_same(const char *a, const char *b, int flags) { return path_equal(a, b) || files_same(a, b, flags) > 0; } diff --git a/src/systemd/src/basic/path-util.h b/src/systemd/src/basic/path-util.h index 519060cf..72f3ce36 100644 --- a/src/systemd/src/basic/path-util.h +++ b/src/systemd/src/basic/path-util.h @@ -60,10 +60,10 @@ static inline bool path_equal_ptr(const char *a, const char *b) { /* Note: the search terminates on the first NULL item. */ #define PATH_IN_SET(p, ...) \ ({ \ - char **s; \ + char **_s; \ bool _found = false; \ - STRV_FOREACH(s, STRV_MAKE(__VA_ARGS__)) \ - if (path_equal(p, *s)) { \ + STRV_FOREACH(_s, STRV_MAKE(__VA_ARGS__)) \ + if (path_equal(p, *_s)) { \ _found = true; \ break; \ } \ diff --git a/src/systemd/src/basic/process-util.c b/src/systemd/src/basic/process-util.c index 10aa0e56..1412f036 100644 --- a/src/systemd/src/basic/process-util.c +++ b/src/systemd/src/basic/process-util.c @@ -1115,12 +1115,7 @@ int pid_compare_func(const void *a, const void *b) { const pid_t *p = a, *q = b; /* Suitable for usage in qsort() */ - - if (*p < *q) - return -1; - if (*p > *q) - return 1; - return 0; + return CMP(*p, *q); } int ioprio_parse_priority(const char *s, int *ret) { @@ -1161,7 +1156,7 @@ void reset_cached_pid(void) { /* We use glibc __register_atfork() + __dso_handle directly here, as they are not included in the glibc * headers. __register_atfork() is mostly equivalent to pthread_atfork(), but doesn't require us to link against * libpthread, as it is part of glibc anyway. */ -extern int __register_atfork(void (*prepare) (void), void (*parent) (void), void (*child) (void), void * __dso_handle); +extern int __register_atfork(void (*prepare) (void), void (*parent) (void), void (*child) (void), void *dso_handle); extern void* __dso_handle __attribute__ ((__weak__)); pid_t getpid_cached(void) { diff --git a/src/systemd/src/basic/random-util.c b/src/systemd/src/basic/random-util.c index 01a8488f..5c07e067 100644 --- a/src/systemd/src/basic/random-util.c +++ b/src/systemd/src/basic/random-util.c @@ -2,6 +2,10 @@ #include "nm-sd-adapt.h" +#ifdef __x86_64__ +#include <cpuid.h> +#endif + #include <elf.h> #include <errno.h> #include <fcntl.h> @@ -28,6 +32,41 @@ #include "random-util.h" #include "time-util.h" + +int rdrand64(uint64_t *ret) { + +#ifdef __x86_64__ + static int have_rdrand = -1; + unsigned char err; + + if (have_rdrand < 0) { + uint32_t eax, ebx, ecx, edx; + + /* Check if RDRAND is supported by the CPU */ + if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) == 0) { + have_rdrand = false; + return -EOPNOTSUPP; + } + + have_rdrand = !!(ecx & (1U << 30)); + } + + if (have_rdrand == 0) + return -EOPNOTSUPP; + + asm volatile("rdrand %0;" + "setc %1" + : "=r" (*ret), + "=qm" (err)); + if (!err) + return -EAGAIN; + + return 0; +#else + return -EOPNOTSUPP; +#endif +} + int acquire_random_bytes(void *p, size_t n, bool high_quality_required) { static int have_syscall = -1; @@ -77,8 +116,26 @@ int acquire_random_bytes(void *p, size_t n, bool high_quality_required) { * a best-effort basis. */ have_syscall = true; - if (!high_quality_required) - return -ENODATA; + if (!high_quality_required) { + uint64_t u; + size_t k; + + /* Try x86-64' RDRAND intrinsic if we have it. We only use it if high quality + * randomness is not required, as we don't trust it (who does?). Note that we only do a + * single iteration of RDRAND here, even though the Intel docs suggest calling this in + * a tight loop of 10 invocatins or so. That's because we don't really care about the + * quality here. */ + + if (rdrand64(&u) < 0) + return -ENODATA; + + k = MIN(n, sizeof(u)); + memcpy(p, &u, k); + + /* We only get 64bit out of RDRAND, the rest let's fill up with pseudo-random crap. */ + pseudorandom_bytes((uint8_t*) p + k, n - k); + return 0; + } } else return -errno; } diff --git a/src/systemd/src/basic/random-util.h b/src/systemd/src/basic/random-util.h index 9a103f0e..affcc9ac 100644 --- a/src/systemd/src/basic/random-util.h +++ b/src/systemd/src/basic/random-util.h @@ -21,3 +21,5 @@ static inline uint32_t random_u32(void) { random_bytes(&u, sizeof(u)); return u; } + +int rdrand64(uint64_t *ret); diff --git a/src/systemd/src/basic/socket-util.c b/src/systemd/src/basic/socket-util.c index a71db5a7..acc22901 100644 --- a/src/systemd/src/basic/socket-util.c +++ b/src/systemd/src/basic/socket-util.c @@ -53,7 +53,8 @@ static const char* const socket_address_type_table[] = { DEFINE_STRING_TABLE_LOOKUP(socket_address_type, int); int socket_address_parse(SocketAddress *a, const char *s) { - char *e, *n; + _cleanup_free_ char *n = NULL; + char *e; int r; assert(a); @@ -71,7 +72,9 @@ int socket_address_parse(SocketAddress *a, const char *s) { if (!e) return -EINVAL; - n = strndupa(s+1, e-s-1); + n = strndup(s+1, e-s-1); + if (!n) + return -ENOMEM; errno = 0; if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) @@ -128,7 +131,10 @@ int socket_address_parse(SocketAddress *a, const char *s) { if (r < 0) return r; - n = strndupa(cid_start, e - cid_start); + n = strndup(cid_start, e - cid_start); + if (!n) + return -ENOMEM; + if (!isempty(n)) { r = safe_atou(n, &a->sockaddr.vm.svm_cid); if (r < 0) @@ -149,7 +155,9 @@ int socket_address_parse(SocketAddress *a, const char *s) { if (r < 0) return r; - n = strndupa(s, e-s); + n = strndup(s, e-s); + if (!n) + return -ENOMEM; /* IPv4 in w.x.y.z:p notation? */ r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr); @@ -1006,9 +1014,10 @@ int getpeergroups(int fd, gid_t **ret) { return (int) n; } -int send_one_fd_sa( +ssize_t send_one_fd_iov_sa( int transport_fd, int fd, + struct iovec *iov, size_t iovlen, const struct sockaddr *sa, socklen_t len, int flags) { @@ -1019,28 +1028,58 @@ int send_one_fd_sa( struct msghdr mh = { .msg_name = (struct sockaddr*) sa, .msg_namelen = len, - .msg_control = &control, - .msg_controllen = sizeof(control), + .msg_iov = iov, + .msg_iovlen = iovlen, }; - struct cmsghdr *cmsg; + ssize_t k; assert(transport_fd >= 0); - assert(fd >= 0); - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); + /* + * We need either an FD or data to send. + * If there's nothing, return an error. + */ + if (fd < 0 && !iov) + return -EINVAL; - mh.msg_controllen = CMSG_SPACE(sizeof(int)); - if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0) - return -errno; + if (fd >= 0) { + struct cmsghdr *cmsg; - return 0; + mh.msg_control = &control; + mh.msg_controllen = sizeof(control); + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); + + mh.msg_controllen = CMSG_SPACE(sizeof(int)); + } + k = sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags); + if (k < 0) + return (ssize_t) -errno; + + return k; } -int receive_one_fd(int transport_fd, int flags) { +int send_one_fd_sa( + int transport_fd, + int fd, + const struct sockaddr *sa, socklen_t len, + int flags) { + + assert(fd >= 0); + + return (int) send_one_fd_iov_sa(transport_fd, fd, NULL, 0, sa, len, flags); +} + +ssize_t receive_one_fd_iov( + int transport_fd, + struct iovec *iov, size_t iovlen, + int flags, + int *ret_fd) { + union { struct cmsghdr cmsghdr; uint8_t buf[CMSG_SPACE(sizeof(int))]; @@ -1048,10 +1087,14 @@ int receive_one_fd(int transport_fd, int flags) { struct msghdr mh = { .msg_control = &control, .msg_controllen = sizeof(control), + .msg_iov = iov, + .msg_iovlen = iovlen, }; struct cmsghdr *cmsg, *found = NULL; + ssize_t k; assert(transport_fd >= 0); + assert(ret_fd); /* * Receive a single FD via @transport_fd. We don't care for @@ -1061,8 +1104,9 @@ int receive_one_fd(int transport_fd, int flags) { * combination with send_one_fd(). */ - if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0) - return -errno; + k = recvmsg(transport_fd, &mh, MSG_CMSG_CLOEXEC | flags); + if (k < 0) + return (ssize_t) -errno; CMSG_FOREACH(cmsg, &mh) { if (cmsg->cmsg_level == SOL_SOCKET && @@ -1074,12 +1118,33 @@ int receive_one_fd(int transport_fd, int flags) { } } - if (!found) { + if (!found) cmsg_close_all(&mh); + + /* If didn't receive an FD or any data, return an error. */ + if (k == 0 && !found) return -EIO; - } - return *(int*) CMSG_DATA(found); + if (found) + *ret_fd = *(int*) CMSG_DATA(found); + else + *ret_fd = -1; + + return k; +} + +int receive_one_fd(int transport_fd, int flags) { + int fd; + ssize_t k; + + k = receive_one_fd_iov(transport_fd, NULL, 0, flags, &fd); + if (k == 0) + return fd; + + /* k must be negative, since receive_one_fd_iov() only returns + * a positive value if data was received through the iov. */ + assert(k < 0); + return (int) k; } #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/socket-util.h b/src/systemd/src/basic/socket-util.h index e2db795a..d7b814ae 100644 --- a/src/systemd/src/basic/socket-util.h +++ b/src/systemd/src/basic/socket-util.h @@ -132,11 +132,19 @@ int getpeercred(int fd, struct ucred *ucred); int getpeersec(int fd, char **ret); int getpeergroups(int fd, gid_t **ret); +ssize_t send_one_fd_iov_sa( + int transport_fd, + int fd, + struct iovec *iov, size_t iovlen, + const struct sockaddr *sa, socklen_t len, + int flags); int send_one_fd_sa(int transport_fd, int fd, const struct sockaddr *sa, socklen_t len, int flags); -#define send_one_fd(transport_fd, fd, flags) send_one_fd_sa(transport_fd, fd, NULL, 0, flags) +#define send_one_fd_iov(transport_fd, fd, iov, iovlen, flags) send_one_fd_iov_sa(transport_fd, fd, iov, iovlen, NULL, 0, flags) +#define send_one_fd(transport_fd, fd, flags) send_one_fd_iov_sa(transport_fd, fd, NULL, 0, NULL, 0, flags) +ssize_t receive_one_fd_iov(int transport_fd, struct iovec *iov, size_t iovlen, int flags, int *ret_fd); int receive_one_fd(int transport_fd, int flags); ssize_t next_datagram_size_fd(int fd); diff --git a/src/systemd/src/basic/stat-util.c b/src/systemd/src/basic/stat-util.c index 9892d8bc..d645ce30 100644 --- a/src/systemd/src/basic/stat-util.c +++ b/src/systemd/src/basic/stat-util.c @@ -48,6 +48,17 @@ int is_dir(const char* path, bool follow) { return !!S_ISDIR(st.st_mode); } +int is_dir_fd(int fd) { + struct stat st; + int r; + + r = fstat(fd, &st); + if (r < 0) + return -errno; + + return !!S_ISDIR(st.st_mode); +} + int is_device_node(const char *path) { struct stat info; diff --git a/src/systemd/src/basic/stat-util.h b/src/systemd/src/basic/stat-util.h index f8014ed3..1a725f1d 100644 --- a/src/systemd/src/basic/stat-util.h +++ b/src/systemd/src/basic/stat-util.h @@ -12,6 +12,7 @@ int is_symlink(const char *path); int is_dir(const char *path, bool follow); +int is_dir_fd(int fd); int is_device_node(const char *path); int dir_is_empty(const char *path); diff --git a/src/systemd/src/basic/strv.c b/src/systemd/src/basic/strv.c index 9da8cece..6f80b317 100644 --- a/src/systemd/src/basic/strv.c +++ b/src/systemd/src/basic/strv.c @@ -255,6 +255,10 @@ char **strv_split(const char *s, const char *separator) { assert(s); + s += strspn(s, separator); + if (isempty(s)) + return new0(char*, 1); + n = 0; FOREACH_WORD_SEPARATOR(word, l, s, separator, state) n++; diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c index aafa0375..c0f53a47 100644 --- a/src/systemd/src/basic/time-util.c +++ b/src/systemd/src/basic/time-util.c @@ -2,6 +2,7 @@ #include "nm-sd-adapt.h" +#include <ctype.h> #include <errno.h> #include <limits.h> #include <stdlib.h> @@ -1001,10 +1002,10 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { } for (;;) { + usec_t multiplier = default_unit, k; long long l, z = 0; - char *e; unsigned n = 0; - usec_t multiplier = default_unit, k; + char *e; p += strspn(p, WHITESPACE); @@ -1015,6 +1016,9 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { break; } + if (*p == '-') /* Don't allow "-0" */ + return -ERANGE; + errno = 0; l = strtoll(p, &e, 10); if (errno > 0) @@ -1025,14 +1029,16 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { if (*e == '.') { char *b = e + 1; + /* Don't allow "0.-0", "3.+1" or "3. 1" */ + if (*b == '-' || *b == '+' || isspace(*b)) + return -EINVAL; + errno = 0; z = strtoll(b, &e, 10); if (errno > 0) return -errno; - if (z < 0) return -ERANGE; - if (e == b) return -EINVAL; @@ -1149,26 +1155,28 @@ int parse_nsec(const char *t, nsec_t *nsec) { break; } + if (*p == '-') + return -ERANGE; + errno = 0; l = strtoll(p, &e, 10); - if (errno > 0) return -errno; - if (l < 0) return -ERANGE; if (*e == '.') { char *b = e + 1; + if (*b == '-' || *b == '+' || isspace(*b)) + return -EINVAL; + errno = 0; z = strtoll(b, &e, 10); if (errno > 0) return -errno; - if (z < 0) return -ERANGE; - if (e == b) return -EINVAL; diff --git a/src/systemd/src/basic/utf8.c b/src/systemd/src/basic/utf8.c index 80de43c5..7238bca7 100644 --- a/src/systemd/src/basic/utf8.c +++ b/src/systemd/src/basic/utf8.c @@ -1,7 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2008-2011 Kay Sievers -***/ /* Parts of this file are based on the GLIB utf8 validation functions. The * original license text follows. */ diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c index ba7474f0..2c6101ea 100644 --- a/src/systemd/src/basic/util.c +++ b/src/systemd/src/basic/util.c @@ -82,31 +82,6 @@ bool display_is_local(const char *display) { display[1] <= '9'; } -int socket_from_display(const char *display, char **path) { - size_t k; - char *f, *c; - - assert(display); - assert(path); - - if (!display_is_local(display)) - return -EINVAL; - - k = strspn(display+1, "0123456789"); - - f = new(char, STRLEN("/tmp/.X11-unix/X") + k + 1); - if (!f) - return -ENOMEM; - - c = stpcpy(f, "/tmp/.X11-unix/X"); - memcpy(c, display+1, k); - c[k] = 0; - - *path = f; - - return 0; -} - bool kexec_loaded(void) { _cleanup_free_ char *s = NULL; @@ -260,6 +235,11 @@ int container_get_leader(const char *machine, pid_t *pid) { assert(machine); assert(pid); + if (streq(machine, ".host")) { + *pid = 1; + return 0; + } + if (!machine_name_is_valid(machine)) return -EINVAL; diff --git a/src/systemd/src/basic/util.h b/src/systemd/src/basic/util.h index 9699d228..308933ac 100644 --- a/src/systemd/src/basic/util.h +++ b/src/systemd/src/basic/util.h @@ -50,7 +50,6 @@ static inline const char* enable_disable(bool b) { bool plymouth_running(void); bool display_is_local(const char *display) _pure_; -int socket_from_display(const char *display, char **path); #define NULSTR_FOREACH(i, l) \ for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) @@ -113,9 +112,7 @@ static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, int (*com qsort_r(base, nmemb, size, compar, userdata); } -/** - * Normal memcpy requires src to be nonnull. We do nothing if n is 0. - */ +/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */ static inline void memcpy_safe(void *dst, const void *src, size_t n) { if (n == 0) return; @@ -123,6 +120,15 @@ static inline void memcpy_safe(void *dst, const void *src, size_t n) { memcpy(dst, src, n); } +/* Normal memcmp requires s1 and s2 to be nonnull. We do nothing if n is 0. */ +static inline int memcmp_safe(const void *s1, const void *s2, size_t n) { + if (n == 0) + return 0; + assert(s1); + assert(s2); + return memcmp(s1, s2, n); +} + int on_ac_power(void); #define memzero(x,l) (memset((x), 0, (l))) diff --git a/src/systemd/src/libsystemd-network/arp-util.c b/src/systemd/src/libsystemd-network/arp-util.c index 1b711c95..4fbecb54 100644 --- a/src/systemd/src/libsystemd-network/arp-util.c +++ b/src/systemd/src/libsystemd-network/arp-util.c @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** Copyright © 2014 Axis Communications AB. All rights reserved. - Copyright © 2015 Tom Gundersen ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c index 75357367..f18713e8 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.c +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c @@ -1,11 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2015 Tom Gundersen <teg@jklmen> -***/ #include "nm-sd-adapt.h" -#include "libudev.h" +#include <linux/if_infiniband.h> +#include <net/if_arp.h> + +#include "sd-device.h" #include "sd-id128.h" #include "dhcp-identifier.h" @@ -13,7 +13,6 @@ #include "network-internal.h" #include "siphash24.h" #include "sparse-endian.h" -#include "udev-util.h" #include "virt.h" #if 0 /* NM_IGNORED */ @@ -21,8 +20,10 @@ #include <net/if.h> #endif /* NM_IGNORED */ -#define SYSTEMD_PEN 43793 -#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) +#define SYSTEMD_PEN 43793 +#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) +#define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03) +#define USEC_2000 ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */ int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { struct duid d; @@ -55,6 +56,58 @@ int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { return 0; } +#if 0 /* NM_IGNORED */ +int dhcp_identifier_set_duid_llt(struct duid *duid, usec_t t, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len) { + uint16_t time_from_2000y; + + assert(duid); + assert(len); + assert(addr); + + if (arp_type == ARPHRD_ETHER) + assert_return(addr_len == ETH_ALEN, -EINVAL); + else if (arp_type == ARPHRD_INFINIBAND) + assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + else + return -EINVAL; + + if (t < USEC_2000) + time_from_2000y = 0; + else + time_from_2000y = (uint16_t) (((t - USEC_2000) / USEC_PER_SEC) & 0xffffffff); + + unaligned_write_be16(&duid->type, DUID_TYPE_LLT); + unaligned_write_be16(&duid->llt.htype, arp_type); + unaligned_write_be32(&duid->llt.time, time_from_2000y); + memcpy(duid->llt.haddr, addr, addr_len); + + *len = sizeof(duid->type) + sizeof(duid->llt.htype) + sizeof(duid->llt.time) + addr_len; + + return 0; +} + +int dhcp_identifier_set_duid_ll(struct duid *duid, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len) { + assert(duid); + assert(len); + assert(addr); + + if (arp_type == ARPHRD_ETHER) + assert_return(addr_len == ETH_ALEN, -EINVAL); + else if (arp_type == ARPHRD_INFINIBAND) + assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + else + return -EINVAL; + + unaligned_write_be16(&duid->type, DUID_TYPE_LL); + unaligned_write_be16(&duid->ll.htype, arp_type); + memcpy(duid->ll.haddr, addr, addr_len); + + *len = sizeof(duid->type) + sizeof(duid->ll.htype) + addr_len; + + return 0; +} +#endif /* NM_IGNORED */ + int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { sd_id128_t machine_id; uint64_t hash; @@ -73,18 +126,39 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { *len = sizeof(duid->type) + sizeof(duid->en); /* a bit of snake-oil perhaps, but no need to expose the machine-id - directly; duid->en.id might not be aligned, so we need to copy */ + * directly; duid->en.id might not be aligned, so we need to copy */ hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes)); memcpy(duid->en.id, &hash, sizeof(duid->en.id)); return 0; } +#if 0 /* NM_IGNORED */ +int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len) { + sd_id128_t machine_id; + int r; + + assert(duid); + assert(len); + + r = sd_id128_get_machine_app_specific(APPLICATION_ID, &machine_id); + if (r < 0) + return r; + + unaligned_write_be16(&duid->type, DUID_TYPE_UUID); + memcpy(&duid->raw.data, &machine_id, sizeof(machine_id)); + + *len = sizeof(duid->type) + sizeof(machine_id); + + return 0; +} +#endif + int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) { #if 0 /* NM_IGNORED */ - /* name is a pointer to memory in the udev_device struct, so must - have the same scope */ - _cleanup_(udev_device_unrefp) struct udev_device *device = NULL; + /* name is a pointer to memory in the sd_device struct, so must + * have the same scope */ + _cleanup_(sd_device_unrefp) sd_device *device = NULL; #else /* NM_IGNORED */ char name_buf[IF_NAMESIZE]; #endif /* NM_IGNORED */ @@ -94,17 +168,15 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_i #if 0 /* NM_IGNORED */ if (detect_container() <= 0) { /* not in a container, udev will be around */ - _cleanup_(udev_unrefp) struct udev *udev; char ifindex_str[2 + DECIMAL_STR_MAX(int)]; - - udev = udev_new(); - if (!udev) - return -ENOMEM; + int initialized, r; sprintf(ifindex_str, "n%d", ifindex); - device = udev_device_new_from_device_id(udev, ifindex_str); - if (device) { - if (udev_device_get_is_initialized(device) <= 0) + if (sd_device_new_from_device_id(&device, ifindex_str) >= 0) { + r = sd_device_get_is_initialized(device, &initialized); + if (r < 0) + return r; + if (!initialized) /* not yet ready */ return -EBUSY; diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.h b/src/systemd/src/libsystemd-network/dhcp-identifier.h index 42d4956d..64315d3a 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.h +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.h @@ -1,14 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - Copyright © 2015 Tom Gundersen <teg@jklmen> -***/ - #include "sd-id128.h" #include "macro.h" #include "sparse-endian.h" +#include "time-util.h" #include "unaligned.h" typedef enum DUIDType { @@ -31,18 +28,18 @@ struct duid { union { struct { /* DUID_TYPE_LLT */ - uint16_t htype; - uint32_t time; + be16_t htype; + be32_t time; uint8_t haddr[0]; } _packed_ llt; struct { /* DUID_TYPE_EN */ - uint32_t pen; + be32_t pen; uint8_t id[8]; } _packed_ en; struct { /* DUID_TYPE_LL */ - int16_t htype; + be16_t htype; uint8_t haddr[0]; } _packed_ ll; struct { @@ -56,5 +53,8 @@ struct duid { } _packed_; int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len); +int dhcp_identifier_set_duid_llt(struct duid *duid, usec_t t, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len); +int dhcp_identifier_set_duid_ll(struct duid *duid, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len); int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len); +int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len); int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id); diff --git a/src/systemd/src/libsystemd-network/dhcp-internal.h b/src/systemd/src/libsystemd-network/dhcp-internal.h index 257a3c2e..a0f9c229 100644 --- a/src/systemd/src/libsystemd-network/dhcp-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-internal.h @@ -3,7 +3,6 @@ /*** Copyright © 2013 Intel Corporation. All rights reserved. - Copyright © 2014 Tom Gundersen ***/ #include <linux/if_packet.h> diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h index fabac183..9d245a90 100644 --- a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h @@ -3,7 +3,6 @@ /*** Copyright © 2013 Intel Corporation. All rights reserved. - Copyright © 2014 Tom Gundersen ***/ #include <stdint.h> diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c index 90fe29d0..80e9577c 100644 --- a/src/systemd/src/libsystemd-network/dhcp-network.c +++ b/src/systemd/src/libsystemd-network/dhcp-network.c @@ -128,8 +128,6 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, const uint8_t *bcast_addr = NULL; uint8_t dhcp_hlen = 0; - assert_return(mac_addr_len > 0, -EINVAL); - if (arp_type == ARPHRD_ETHER) { assert_return(mac_addr_len == ETH_ALEN, -EINVAL); memcpy(ð_mac, mac_addr, ETH_ALEN); diff --git a/src/systemd/src/libsystemd-network/dhcp-packet.c b/src/systemd/src/libsystemd-network/dhcp-packet.c index 214aed8e..8f8acb0d 100644 --- a/src/systemd/src/libsystemd-network/dhcp-packet.c +++ b/src/systemd/src/libsystemd-network/dhcp-packet.c @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** Copyright © 2013 Intel Corporation. All rights reserved. - Copyright © 2014 Tom Gundersen ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/dhcp6-internal.h b/src/systemd/src/libsystemd-network/dhcp6-internal.h index f1cbd6a4..06e2e532 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp6-internal.h @@ -91,7 +91,7 @@ int dhcp6_option_append_pd(uint8_t *buf, size_t len, DHCP6IA *pd); int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn); int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen, uint8_t **optvalue); -int dhcp6_option_parse_status(DHCP6Option *option); +int dhcp6_option_parse_status(DHCP6Option *option, size_t len); int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia); int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen, struct in6_addr **addrs, size_t count, diff --git a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h index dc85c437..ff0b0f00 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h @@ -2,7 +2,6 @@ #pragma once /*** - Copyright © 2014 Tom Gundersen Copyright © 2014-2015 Intel Corporation. All rights reserved. ***/ diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c index a8a56463..ff1cbf13 100644 --- a/src/systemd/src/libsystemd-network/dhcp6-option.c +++ b/src/systemd/src/libsystemd-network/dhcp6-option.c @@ -249,10 +249,11 @@ int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, return 0; } -int dhcp6_option_parse_status(DHCP6Option *option) { +int dhcp6_option_parse_status(DHCP6Option *option, size_t len) { DHCP6StatusOption *statusopt = (DHCP6StatusOption *)option; - if (be16toh(option->len) + sizeof(DHCP6Option) < sizeof(*statusopt)) + if (len < sizeof(DHCP6StatusOption) || + be16toh(option->len) + sizeof(DHCP6Option) < sizeof(DHCP6StatusOption)) return -ENOBUFS; return be16toh(statusopt->status); @@ -279,7 +280,7 @@ static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia, } if (be16toh(option->len) + sizeof(DHCP6Option) > sizeof(*addr_option)) { - r = dhcp6_option_parse_status((DHCP6Option *)addr_option->options); + r = dhcp6_option_parse_status((DHCP6Option *)addr_option->options, be16toh(option->len) + sizeof(DHCP6Option) - sizeof(*addr_option)); if (r != 0) return r < 0 ? r: 0; } @@ -319,7 +320,7 @@ static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia, } if (be16toh(option->len) + sizeof(DHCP6Option) > sizeof(*pdprefix_option)) { - r = dhcp6_option_parse_status((DHCP6Option *)pdprefix_option->options); + r = dhcp6_option_parse_status((DHCP6Option *)pdprefix_option->options, be16toh(option->len) + sizeof(DHCP6Option) - sizeof(*pdprefix_option)); if (r != 0) return r < 0 ? r: 0; } @@ -464,7 +465,7 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) { case SD_DHCP6_OPTION_STATUS_CODE: - status = dhcp6_option_parse_status(option); + status = dhcp6_option_parse_status(option, optlen); if (status) { log_dhcp6_client(client, "IA status %d", status); @@ -565,7 +566,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char * /* Literal label */ label = (const char *)&optval[pos]; pos += c; - if (pos > optlen) + if (pos >= optlen) return -EMSGSIZE; if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) { diff --git a/src/systemd/src/libsystemd-network/lldp-internal.h b/src/systemd/src/libsystemd-network/lldp-internal.h index e5650988..328d51f8 100644 --- a/src/systemd/src/libsystemd-network/lldp-internal.h +++ b/src/systemd/src/libsystemd-network/lldp-internal.h @@ -1,11 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - Copyright © 2014 Tom Gundersen - Copyright © 2014 Susant Sahani -***/ - #include "sd-event.h" #include "sd-lldp.h" diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.c b/src/systemd/src/libsystemd-network/lldp-neighbor.c index c28c9956..cd9358a4 100644 --- a/src/systemd/src/libsystemd-network/lldp-neighbor.c +++ b/src/systemd/src/libsystemd-network/lldp-neighbor.c @@ -28,22 +28,15 @@ static int lldp_neighbor_id_compare_func(const void *a, const void *b) { if (r != 0) return r; - if (x->chassis_id_size < y->chassis_id_size) - return -1; - - if (x->chassis_id_size > y->chassis_id_size) - return 1; + r = CMP(x->chassis_id_size, y->chassis_id_size); + if (r != 0) + return r; r = memcmp(x->port_id, y->port_id, MIN(x->port_id_size, y->port_id_size)); if (r != 0) return r; - if (x->port_id_size < y->port_id_size) - return -1; - if (x->port_id_size > y->port_id_size) - return 1; - - return 0; + return CMP(x->port_id_size, y->port_id_size); } const struct hash_ops lldp_neighbor_id_hash_ops = { @@ -54,13 +47,7 @@ const struct hash_ops lldp_neighbor_id_hash_ops = { int lldp_neighbor_prioq_compare_func(const void *a, const void *b) { const sd_lldp_neighbor *x = a, *y = b; - if (x->until < y->until) - return -1; - - if (x->until > y->until) - return 1; - - return 0; + return CMP(x->until, y->until); } _public_ sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) { diff --git a/src/systemd/src/libsystemd-network/lldp-network.c b/src/systemd/src/libsystemd-network/lldp-network.c index bc6c20d1..db779aaa 100644 --- a/src/systemd/src/libsystemd-network/lldp-network.c +++ b/src/systemd/src/libsystemd-network/lldp-network.c @@ -1,8 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2014 Tom Gundersen - Copyright © 2014 Susant Sahani -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/lldp-network.h b/src/systemd/src/libsystemd-network/lldp-network.h index 1d773acc..e4ed2898 100644 --- a/src/systemd/src/libsystemd-network/lldp-network.h +++ b/src/systemd/src/libsystemd-network/lldp-network.h @@ -1,11 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - Copyright © 2014 Tom Gundersen - Copyright © 2014 Susant Sahani -***/ - #include "sd-event.h" int lldp_network_bind_raw_socket(int ifindex); diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index 308762ee..57a59030 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -1,7 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2013 Tom Gundersen <teg@jklm.no> -***/ #include "nm-sd-adapt.h" @@ -29,24 +26,22 @@ #include "util.h" #if 0 /* NM_IGNORED */ -const char *net_get_name(struct udev_device *device) { +const char *net_get_name(sd_device *device) { const char *name, *field; assert(device); /* fetch some persistent data unique (on this machine) to this device */ - FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") { - name = udev_device_get_property_value(device, field); - if (name) + FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") + if (sd_device_get_property_value(device, field, &name) >= 0) return name; - } return NULL; } #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a) -int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result) { +int net_get_unique_predictable_data(sd_device *device, uint64_t *result) { size_t l, sz = 0; const char *name = NULL; int r; @@ -130,7 +125,7 @@ bool net_match_config(Set *match_mac, if (match_arch && condition_test(match_arch) <= 0) return false; - if (match_mac && dev_mac && !set_contains(match_mac, dev_mac)) + if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac))) return false; if (!net_condition_test_strv(match_paths, dev_path)) diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h index ef69e701..06d61184 100644 --- a/src/systemd/src/libsystemd-network/network-internal.h +++ b/src/systemd/src/libsystemd-network/network-internal.h @@ -1,18 +1,14 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - Copyright © 2013 Tom Gundersen <teg@jklm.no> -***/ - #include <stdbool.h> +#include "sd-device.h" #include "sd-dhcp-lease.h" #include "condition.h" #include "conf-parser.h" #include "set.h" -#include "udev.h" #define LINK_BRIDGE_PORT_PRIORITY_INVALID 128 #define LINK_BRIDGE_PORT_PRIORITY_MAX 63 @@ -42,10 +38,10 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ifnames); CONFIG_PARSER_PROTOTYPE(config_parse_ifalias); CONFIG_PARSER_PROTOTYPE(config_parse_iaid); CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority); -#endif /* NM_IGNORED */ -int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result); -const char *net_get_name(struct udev_device *device); +int net_get_unique_predictable_data(sd_device *device, uint64_t *result); +const char *net_get_name(sd_device *device); +#endif /* NM_IGNORED */ void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size); int deserialize_in_addrs(struct in_addr **addresses, const char *string); diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index c2f81e1c..42707f10 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -345,13 +345,14 @@ int sd_dhcp_client_set_client_id( * without further modification. Otherwise, if duid_type is supported, DUID * is set based on that type. Otherwise, an error is returned. */ -static int dhcp_client_set_iaid_duid( +static int dhcp_client_set_iaid_duid_internal( sd_dhcp_client *client, uint32_t iaid, bool append_iaid, uint16_t duid_type, const void *duid, - size_t duid_len) { + size_t duid_len, + usec_t llt_time) { DHCP_CLIENT_DONT_DESTROY(client); int r; @@ -385,18 +386,43 @@ static int dhcp_client_set_iaid_duid( client->client_id.ns.duid.type = htobe16(duid_type); memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len); len = sizeof(client->client_id.ns.duid.type) + duid_len; - } else if (duid_type == DUID_TYPE_EN) { - r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len); - if (r < 0) - return r; } else - return -EOPNOTSUPP; + switch (duid_type) { + case DUID_TYPE_LLT: + if (!client->mac_addr || client->mac_addr_len == 0) + return -EOPNOTSUPP; + + r = dhcp_identifier_set_duid_llt(&client->client_id.ns.duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &len); + if (r < 0) + return r; + break; + case DUID_TYPE_EN: + r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len); + if (r < 0) + return r; + break; + case DUID_TYPE_LL: + if (!client->mac_addr || client->mac_addr_len == 0) + return -EOPNOTSUPP; + + r = dhcp_identifier_set_duid_ll(&client->client_id.ns.duid, client->mac_addr, client->mac_addr_len, client->arp_type, &len); + if (r < 0) + return r; + break; + case DUID_TYPE_UUID: + r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len); + if (r < 0) + return r; + break; + default: + return -EINVAL; + } client->client_id_len = sizeof(client->client_id.type) + len + (append_iaid ? sizeof(client->client_id.ns.iaid) : 0); if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { - log_dhcp_client(client, "Configured IAID+DUID, restarting."); + log_dhcp_client(client, "Configured %sDUID, restarting.", append_iaid ? "IAID+" : ""); client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); sd_dhcp_client_start(client); } @@ -410,7 +436,14 @@ int sd_dhcp_client_set_iaid_duid( uint16_t duid_type, const void *duid, size_t duid_len) { - return dhcp_client_set_iaid_duid(client, iaid, true, duid_type, duid, duid_len); + return dhcp_client_set_iaid_duid_internal(client, iaid, true, duid_type, duid, duid_len, 0); +} + +int sd_dhcp_client_set_iaid_duid_llt( + sd_dhcp_client *client, + uint32_t iaid, + usec_t llt_time) { + return dhcp_client_set_iaid_duid_internal(client, iaid, true, DUID_TYPE_LLT, NULL, 0, llt_time); } int sd_dhcp_client_set_duid( @@ -418,7 +451,13 @@ int sd_dhcp_client_set_duid( uint16_t duid_type, const void *duid, size_t duid_len) { - return dhcp_client_set_iaid_duid(client, 0, false, duid_type, duid, duid_len); + return dhcp_client_set_iaid_duid_internal(client, 0, false, duid_type, duid, duid_len, 0); +} + +int sd_dhcp_client_set_duid_llt( + sd_dhcp_client *client, + usec_t llt_time) { + return dhcp_client_set_iaid_duid_internal(client, 0, false, DUID_TYPE_LLT, NULL, 0, llt_time); } #endif /* NM_IGNORED */ diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c index 33a0796a..d2402595 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** Copyright © 2013 Intel Corporation. All rights reserved. - Copyright © 2014 Tom Gundersen ***/ #include "nm-sd-adapt.h" @@ -28,6 +27,7 @@ #include "parse-util.h" #include "stdio-util.h" #include "string-util.h" +#include "strv.h" #include "unaligned.h" int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c index ca03f580..8444a750 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -184,13 +184,14 @@ static int client_ensure_duid(sd_dhcp6_client *client) { * without further modification. Otherwise, if duid_type is supported, DUID * is set based on that type. Otherwise, an error is returned. */ -int sd_dhcp6_client_set_duid( +static int dhcp6_client_set_duid_internal( sd_dhcp6_client *client, uint16_t duid_type, const void *duid, - size_t duid_len) { - + size_t duid_len, + usec_t llt_time) { int r; + assert_return(client, -EINVAL); assert_return(duid_len == 0 || duid != NULL, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); @@ -199,23 +200,64 @@ int sd_dhcp6_client_set_duid( r = dhcp_validate_duid_len(duid_type, duid_len); if (r < 0) return r; - } - if (duid != NULL) { client->duid.type = htobe16(duid_type); memcpy(&client->duid.raw.data, duid, duid_len); client->duid_len = sizeof(client->duid.type) + duid_len; - } else if (duid_type == DUID_TYPE_EN) { - r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); - if (r < 0) - return r; } else - return -EOPNOTSUPP; +#if 0 /* NM_IGNORED */ + switch (duid_type) { + case DUID_TYPE_LLT: + if (!client->mac_addr || client->mac_addr_len == 0) + return -EOPNOTSUPP; + + r = dhcp_identifier_set_duid_llt(&client->duid, 0, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len); + if (r < 0) + return r; + break; + case DUID_TYPE_EN: + r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); + if (r < 0) + return r; + break; + case DUID_TYPE_LL: + if (!client->mac_addr || client->mac_addr_len == 0) + return -EOPNOTSUPP; + + r = dhcp_identifier_set_duid_ll(&client->duid, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len); + if (r < 0) + return r; + break; + case DUID_TYPE_UUID: + r = dhcp_identifier_set_duid_uuid(&client->duid, &client->duid_len); + if (r < 0) + return r; + break; + default: + return -EINVAL; + } +#else /* NM_IGNORED */ + g_return_val_if_reached (-EINVAL); +#endif /* NM_IGNORED */ return 0; } +int sd_dhcp6_client_set_duid( + sd_dhcp6_client *client, + uint16_t duid_type, + const void *duid, + size_t duid_len) { + return dhcp6_client_set_duid_internal(client, duid_type, duid, duid_len, 0); +} + #if 0 /* NM_IGNORED */ +int sd_dhcp6_client_set_duid_llt( + sd_dhcp6_client *client, + usec_t llt_time) { + return dhcp6_client_set_duid_internal(client, DUID_TYPE_LLT, NULL, 0, llt_time); +} + int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) { assert_return(client, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); @@ -828,7 +870,7 @@ static int client_parse_message( break; case SD_DHCP6_OPTION_STATUS_CODE: - status = dhcp6_option_parse_status(option); + status = dhcp6_option_parse_status(option, optlen); if (status) { log_dhcp6_client(client, "%s Status %s", dhcp6_message_type_to_string(message->type), @@ -1148,9 +1190,8 @@ static int client_receive_message( return 0; } - if (r >= 0) - log_dhcp6_client(client, "Recv %s", - dhcp6_message_type_to_string(message->type)); + log_dhcp6_client(client, "Recv %s", + dhcp6_message_type_to_string(message->type)); return 0; } diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c index 1c8346d4..cca0b500 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** - Copyright © 2014 Tom Gundersen Copyright © 2014-2015 Intel Corporation. All rights reserved. ***/ diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c index 3766c1f3..a39a865a 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** Copyright © 2014 Axis Communications AB. All rights reserved. - Copyright © 2015 Tom Gundersen ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c index ca1e0bdb..69fa60e2 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /*** Copyright © 2014 Axis Communications AB. All rights reserved. - Copyright © 2015 Tom Gundersen ***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c index ea1dda4d..74ba8236 100644 --- a/src/systemd/src/libsystemd-network/sd-lldp.c +++ b/src/systemd/src/libsystemd-network/sd-lldp.c @@ -1,8 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2014 Tom Gundersen - Copyright © 2014 Susant Sahani -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index f4d5dbe4..2af3572d 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -1,6 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** -***/ #include "nm-sd-adapt.h" @@ -94,7 +92,7 @@ struct sd_event_source { char *description; EventSourceType type:5; - int enabled:3; + signed int enabled:3; bool pending:1; bool dispatching:1; bool floating:1; diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c index 03a38699..d4d668e8 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.c +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c @@ -1,6 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.h b/src/systemd/src/libsystemd/sd-id128/id128-util.h index f0b4eca5..44f159c0 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.h +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.h @@ -1,9 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** -***/ - #include <stdbool.h> #include "sd-id128.h" diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c index 8fe8ff43..483b2fe0 100644 --- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c +++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c @@ -1,6 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** -***/ #include "nm-sd-adapt.h" diff --git a/src/systemd/src/shared/dns-domain.c b/src/systemd/src/shared/dns-domain.c index ab034043..048075f2 100644 --- a/src/systemd/src/shared/dns-domain.c +++ b/src/systemd/src/shared/dns-domain.c @@ -1,6 +1,4 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - ***/ #include "nm-sd-adapt.h" @@ -514,7 +512,7 @@ int dns_name_compare_func(const void *a, const void *b) { r = dns_label_unescape_suffix(a, &x, la, sizeof(la)); q = dns_label_unescape_suffix(b, &y, lb, sizeof(lb)); if (r < 0 || q < 0) - return r - q; + return CMP(r, q); r = ascii_strcasecmp_nn(la, r, lb, q); if (r != 0) diff --git a/src/systemd/src/shared/dns-domain.h b/src/systemd/src/shared/dns-domain.h index 8781eec6..95f4069c 100644 --- a/src/systemd/src/shared/dns-domain.h +++ b/src/systemd/src/shared/dns-domain.h @@ -1,9 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once -/*** - ***/ - #include <errno.h> #include <stdbool.h> #include <stddef.h> diff --git a/src/systemd/src/systemd/_sd-common.h b/src/systemd/src/systemd/_sd-common.h index 7b54d179..4742b2e7 100644 --- a/src/systemd/src/systemd/_sd-common.h +++ b/src/systemd/src/systemd/_sd-common.h @@ -3,7 +3,6 @@ #define foosdcommonhfoo /*** - systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h index 931b0e89..e3885520 100644 --- a/src/systemd/src/systemd/sd-dhcp-client.h +++ b/src/systemd/src/systemd/sd-dhcp-client.h @@ -131,11 +131,18 @@ int sd_dhcp_client_set_iaid_duid( uint16_t duid_type, const void *duid, size_t duid_len); +int sd_dhcp_client_set_iaid_duid_llt( + sd_dhcp_client *client, + uint32_t iaid, + uint64_t llt_time); int sd_dhcp_client_set_duid( sd_dhcp_client *client, uint16_t duid_type, const void *duid, size_t duid_len); +int sd_dhcp_client_set_duid_llt( + sd_dhcp_client *client, + uint64_t llt_time); int sd_dhcp_client_get_client_id( sd_dhcp_client *client, uint8_t *type, diff --git a/src/systemd/src/systemd/sd-dhcp-lease.h b/src/systemd/src/systemd/sd-dhcp-lease.h index 16c05661..2a60145f 100644 --- a/src/systemd/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/src/systemd/sd-dhcp-lease.h @@ -4,8 +4,6 @@ /*** Copyright © 2013 Intel Corporation. All rights reserved. - Copyright © 2014 Tom Gundersen - systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or diff --git a/src/systemd/src/systemd/sd-dhcp6-client.h b/src/systemd/src/systemd/sd-dhcp6-client.h index 4f3b2d9e..fa36dca9 100644 --- a/src/systemd/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/src/systemd/sd-dhcp6-client.h @@ -102,6 +102,9 @@ int sd_dhcp6_client_set_duid( uint16_t duid_type, const void *duid, size_t duid_len); +int sd_dhcp6_client_set_duid_llt( + sd_dhcp6_client *client, + uint64_t llt_time); int sd_dhcp6_client_set_iaid( sd_dhcp6_client *client, uint32_t iaid); diff --git a/src/systemd/src/systemd/sd-dhcp6-lease.h b/src/systemd/src/systemd/sd-dhcp6-lease.h index a673de5e..33a32a6d 100644 --- a/src/systemd/src/systemd/sd-dhcp6-lease.h +++ b/src/systemd/src/systemd/sd-dhcp6-lease.h @@ -3,7 +3,6 @@ #define foosddhcp6leasehfoo /*** - Copyright © 2014 Tom Gundersen Copyright © 2014-2015 Intel Corporation. All rights reserved. systemd is free software; you can redistribute it and/or modify it diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h index 7fcae4ac..eb35b834 100644 --- a/src/systemd/src/systemd/sd-event.h +++ b/src/systemd/src/systemd/sd-event.h @@ -3,7 +3,6 @@ #define foosdeventhfoo /*** - systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or diff --git a/src/systemd/src/systemd/sd-id128.h b/src/systemd/src/systemd/sd-id128.h index b24fd06f..143a0ffb 100644 --- a/src/systemd/src/systemd/sd-id128.h +++ b/src/systemd/src/systemd/sd-id128.h @@ -3,7 +3,6 @@ #define foosdid128hfoo /*** - systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or diff --git a/src/systemd/src/systemd/sd-ipv4acd.h b/src/systemd/src/systemd/sd-ipv4acd.h index 259db263..039ed3c7 100644 --- a/src/systemd/src/systemd/sd-ipv4acd.h +++ b/src/systemd/src/systemd/sd-ipv4acd.h @@ -4,8 +4,6 @@ /*** Copyright © 2014 Axis Communications AB. All rights reserved. - Copyright © 2015 Tom Gundersen - systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or diff --git a/src/systemd/src/systemd/sd-lldp.h b/src/systemd/src/systemd/sd-lldp.h index 11a2119a..d650794c 100644 --- a/src/systemd/src/systemd/sd-lldp.h +++ b/src/systemd/src/systemd/sd-lldp.h @@ -3,9 +3,6 @@ #define foosdlldphfoo /*** - Copyright © 2014 Tom Gundersen - Copyright © 2014 Susant Sahani - systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or diff --git a/src/tests/config/meson.build b/src/tests/config/meson.build index f542c453..fd6c89b7 100644 --- a/src/tests/config/meson.build +++ b/src/tests/config/meson.build @@ -11,7 +11,6 @@ exe = executable( test_unit, sources, dependencies: test_nm_dep, - c_args: nm_build_cflags, ) test( diff --git a/src/tests/test-general-with-expect.c b/src/tests/test-general-with-expect.c index a78b5311..ba8e3ce4 100644 --- a/src/tests/test-general-with-expect.c +++ b/src/tests/test-general-with-expect.c @@ -32,10 +32,6 @@ #include "nm-test-utils-core.h" -#ifndef CLOCK_BOOTTIME -#define CLOCK_BOOTTIME 7 -#endif - /*****************************************************************************/ static void diff --git a/src/tests/test-general.c b/src/tests/test-general.c index 4db05ac8..1e7329d1 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -907,6 +907,79 @@ test_connection_match_ip6_routes (void) g_assert (matched == copy); } +#define do_test_wildcard_match(str, result, ...) \ + g_assert (nm_wildcard_match_check (str, \ + (const char *const[]) { __VA_ARGS__ }, \ + NM_NARG (__VA_ARGS__)) \ + == result); + +static void +test_wildcard_match (void) +{ + do_test_wildcard_match ("foobar", TRUE); + + do_test_wildcard_match ("foo", TRUE, "foo", "bar", "baz"); + do_test_wildcard_match ("bar", TRUE, "foo", "bar", "baz"); + do_test_wildcard_match ("baz", TRUE, "foo", "bar", "baz"); + do_test_wildcard_match ("aaa", FALSE, "foo", "bar", "baz"); + do_test_wildcard_match ("", FALSE, "foo", "bar", "baz"); + + do_test_wildcard_match ("ens1", TRUE, "ens1*"); + do_test_wildcard_match ("ens10", TRUE, "ens1*"); + do_test_wildcard_match ("ens11", TRUE, "ens1*"); + do_test_wildcard_match ("ens12", TRUE, "ens1*"); + do_test_wildcard_match ("eth0", FALSE, "ens1*"); + do_test_wildcard_match ("ens", FALSE, "ens1*"); + + do_test_wildcard_match ("ens1*", TRUE, "ens1\\*"); + do_test_wildcard_match ("ens1" , FALSE, "ens1\\*"); + do_test_wildcard_match ("ens10", FALSE, "ens1\\*"); + + do_test_wildcard_match ("abcd", TRUE, "ab??"); + do_test_wildcard_match ("ab", FALSE, "ab??"); + + do_test_wildcard_match ("ab??", TRUE, "ab\\?\\?"); + do_test_wildcard_match ("abcd", FALSE, "ab\\?\\?"); + + do_test_wildcard_match ("ens10", TRUE, "ens1*", "!ens11"); + do_test_wildcard_match ("ens11", FALSE, "ens1*", "!ens11"); + do_test_wildcard_match ("ens12", TRUE, "ens1*", "!ens11"); + + do_test_wildcard_match ("a", FALSE, "!a", "!b"); + do_test_wildcard_match ("b", FALSE, "!a", "!b"); + do_test_wildcard_match ("c", TRUE, "!a", "!b"); + do_test_wildcard_match ("!a", TRUE, "!a", "!b"); + + do_test_wildcard_match ("!net", TRUE, "\\!net"); + do_test_wildcard_match ("net", FALSE, "\\!net"); + do_test_wildcard_match ("ens10", FALSE, "\\!net"); + do_test_wildcard_match ("\\!net", FALSE, "\\!net"); + + do_test_wildcard_match ("eth0", FALSE, "*eth?", "!veth*", "!*0"); + do_test_wildcard_match ("eth1", TRUE, "*eth?", "!veth*", "!*0"); + do_test_wildcard_match ("myeth0", FALSE, "*eth?", "!veth*", "!*0"); + do_test_wildcard_match ("myeth2", TRUE, "*eth?", "!veth*", "!*0"); + do_test_wildcard_match ("veth0", FALSE, "*eth?", "!veth*", "!*0"); + do_test_wildcard_match ("veth1", FALSE, "*eth?", "!veth*", "!*0"); + do_test_wildcard_match ("dummy1", FALSE, "*eth?", "!veth*", "!*0"); + + do_test_wildcard_match ("a", TRUE, "!!a"); + do_test_wildcard_match ("b", TRUE, "!!a"); + do_test_wildcard_match ("!a", FALSE, "!!a"); + + do_test_wildcard_match ("\\", TRUE, "\\\\"); + do_test_wildcard_match ("\\\\", FALSE, "\\\\"); + do_test_wildcard_match ("", FALSE, "\\\\"); + + do_test_wildcard_match ("name", FALSE, "name[123]"); + do_test_wildcard_match ("name1", TRUE, "name[123]"); + do_test_wildcard_match ("name2", TRUE, "name[123]"); + do_test_wildcard_match ("name3", TRUE, "name[123]"); + do_test_wildcard_match ("name4", FALSE, "name[123]"); + + do_test_wildcard_match ("[a]", TRUE, "\\[a\\]"); +} + static NMConnection * _create_connection_autoconnect (const char *id, gboolean autoconnect, int autoconnect_priority) { @@ -1205,7 +1278,7 @@ test_match_spec_device (void) /*****************************************************************************/ static void -_do_test_match_spec_config (const char *file, gint line, const char *spec_str, guint version, guint v_maj, guint v_min, guint v_mic, NMMatchSpecMatchType expected) +_do_test_match_spec_config (const char *file, int line, const char *spec_str, guint version, guint v_maj, guint v_min, guint v_mic, NMMatchSpecMatchType expected) { GSList *specs; NMMatchSpecMatchType match_result; @@ -1372,7 +1445,7 @@ test_nm_utils_strbuf_append (void) t_buf = buf; t_len = buf_len; - test_mode = nmtst_get_rand_int () % 4; + test_mode = nmtst_get_rand_int () % 5; switch (test_mode) { case 0: @@ -1393,6 +1466,45 @@ test_nm_utils_strbuf_append (void) case 3: nm_utils_strbuf_append (&t_buf, &t_len, "%s", str); break; + case 4: + g_snprintf (t_buf, t_len, "%s", str); + if ( t_len > 0 + && strlen (str) >= buf_len + && (nmtst_get_rand_int () % 2)) { + /* the string was truncated by g_snprintf(). That means, at the last position in the + * buffer is now NUL. + * Replace the NUL by the actual character, and check that nm_utils_strbuf_seek_end() + * does the right thing: NUL terminate the buffer and seek past the end of the buffer. */ + g_assert_cmpmem (t_buf, t_len - 1, str, t_len - 1); + g_assert (t_buf[t_len - 1] == '\0'); + g_assert (str[t_len - 1] != '\0'); + t_buf[t_len - 1] = str[t_len - 1]; + nm_utils_strbuf_seek_end (&t_buf, &t_len); + g_assert (t_len == 0); + g_assert (t_buf == &buf[buf_len]); + g_assert (t_buf[-1] == '\0'); + } else { + nm_utils_strbuf_seek_end (&t_buf, &t_len); + if ( buf_len > 0 + && strlen (str) + 1 > buf_len) { + /* the buffer was truncated by g_snprintf() above. + * + * But nm_utils_strbuf_seek_end() does not recognize that and returns + * a remaining length of 1. + * + * Note that other nm_utils_strbuf_append*() functions recognize + * truncation, and properly set the remaining length to zero. + * As the assertions below check for the behavior of nm_utils_strbuf_append*(), + * we assert here that nm_utils_strbuf_seek_end() behaved as expected, and then + * adjust t_buf/t_len according to the "is-truncated" case. */ + g_assert (t_len == 1); + g_assert (t_buf == &buf[buf_len - 1]); + g_assert (t_buf[0] == '\0'); + t_len = 0; + t_buf++; + } + } + break; } /* Assert that the source-buffer is unmodified. */ @@ -1765,6 +1877,8 @@ main (int argc, char **argv) g_test_add_func ("/general/connection-match/routes/ip4/2", test_connection_match_ip4_routes2); g_test_add_func ("/general/connection-match/routes/ip6", test_connection_match_ip6_routes); + g_test_add_func ("/general/wildcard-match", test_wildcard_match); + g_test_add_func ("/general/connection-sort/autoconnect-priority", test_connection_sort_autoconnect_priority); g_test_add_func ("/general/match-spec/device", test_match_spec_device); diff --git a/src/tests/test-wired-defname.c b/src/tests/test-wired-defname.c index a966ed21..97a6c319 100644 --- a/src/tests/test-wired-defname.c +++ b/src/tests/test-wired-defname.c @@ -44,15 +44,14 @@ _new_connection (const char *id) static char * _get_default_wired_name (GSList *list) { - gs_free NMConnection **v = NULL; - guint l, i; - - l = g_slist_length (list); - v = g_new0 (NMConnection *, l + 1); - for (i = 0; list; list = list->next, i++) - v[i] = NM_CONNECTION (list->data); - g_assert (i == l); - return nm_device_ethernet_utils_get_default_wired_name (v); + gs_unref_hashtable GHashTable *existing_ids = NULL; + + if (list) { + existing_ids = g_hash_table_new (nm_str_hash, g_str_equal); + for (; list; list = list->next) + g_hash_table_add (existing_ids, (char *) nm_connection_get_id (list->data)); + } + return nm_device_ethernet_utils_get_default_wired_name (existing_ids); } /*****************************************************************************/ diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 91acf07e..bd847d75 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -193,7 +193,7 @@ static void _set_vpn_state (NMVpnConnection *self, #define __NMLOG_prefix_buf_len 128 static const char * -__LOG_create_prefix (char *buf, NMVpnConnection *self, NMConnection *con) +__LOG_create_prefix (char *buf, NMVpnConnection *self, NMSettingsConnection *con) { NMVpnConnectionPrivate *priv; const char *id; @@ -202,7 +202,7 @@ __LOG_create_prefix (char *buf, NMVpnConnection *self, NMConnection *con) return _NMLOG_PREFIX_NAME; priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - id = con ? nm_connection_get_id (con) : NULL; + id = con ? nm_settings_connection_get_id (con) : NULL; g_snprintf (buf, __NMLOG_prefix_buf_len, "%s[" @@ -214,7 +214,7 @@ __LOG_create_prefix (char *buf, NMVpnConnection *self, NMConnection *con) "]", _NMLOG_PREFIX_NAME, self, - con ? "," : "--", con ? (nm_connection_get_uuid (con) ?: "??") : "", + con ? "," : "--", con ? (nm_settings_connection_get_uuid (con) ?: "??") : "", con ? "," : "", NM_PRINT_FMT_QUOTED (id, "\"", id, "\"", con ? "??" : ""), priv->ip_ifindex, NM_PRINT_FMT_QUOTED (priv->ip_iface, ":(", priv->ip_iface, ")", "") @@ -225,17 +225,17 @@ __LOG_create_prefix (char *buf, NMVpnConnection *self, NMConnection *con) #define _NMLOG(level, ...) \ G_STMT_START { \ - const NMLogLevel __level = (level); \ - NMConnection *__con = (self) ? (NMConnection *) _get_settings_connection (self, TRUE) : NULL; \ + const NMLogLevel _level = (level); \ + NMSettingsConnection *_con = (self) ? _get_settings_connection (self, TRUE) : NULL; \ \ - if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ + if (nm_logging_enabled (_level, _NMLOG_DOMAIN)) { \ char __prefix[__NMLOG_prefix_buf_len]; \ \ - _nm_log (__level, _NMLOG_DOMAIN, 0, \ + _nm_log (_level, _NMLOG_DOMAIN, 0, \ (self) ? NM_VPN_CONNECTION_GET_PRIVATE (self)->ip_iface : NULL, \ - (__con) ? nm_connection_get_uuid (__con) : NULL, \ + (_con) ? nm_settings_connection_get_uuid (_con) : NULL, \ "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ - __LOG_create_prefix (__prefix, (self), __con) \ + __LOG_create_prefix (__prefix, (self), _con) \ _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } \ } G_STMT_END @@ -1619,6 +1619,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) nm_ip4_config_merge_setting (config, s_ip, nm_setting_connection_get_mdns (s_con), + nm_setting_connection_get_llmnr (s_con), route_table, route_metric); @@ -1876,13 +1877,10 @@ connect_success (NMVpnConnection *self) * It is a configured value or 60 seconds */ timeout = nm_setting_vpn_get_timeout (s_vpn); if (timeout == 0) { - char *value; - - value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, - "vpn.timeout", NULL); - timeout = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, 60); - timeout = timeout == 0 ? 60 : timeout; - g_free (value); + timeout = nm_config_data_get_connection_default_int64 (NM_CONFIG_GET_DATA, + "vpn.timeout", + NULL, + 1, G_MAXUINT32, 60); } priv->connect_timeout = g_timeout_add_seconds (timeout, connect_timeout_cb, self); diff --git a/src/vpn/nm-vpn-connection.h b/src/vpn/nm-vpn-connection.h index 3046634d..e409cc31 100644 --- a/src/vpn/nm-vpn-connection.h +++ b/src/vpn/nm-vpn-connection.h @@ -59,7 +59,7 @@ void nm_vpn_connection_activate (NMVpnConnection *self, NMVpnPluginInfo *plugin_info); NMVpnConnectionState nm_vpn_connection_get_vpn_state (NMVpnConnection *self); const char * nm_vpn_connection_get_banner (NMVpnConnection *self); -const gchar * nm_vpn_connection_get_service (NMVpnConnection *self); +const char * nm_vpn_connection_get_service (NMVpnConnection *self); gboolean nm_vpn_connection_deactivate (NMVpnConnection *self, NMActiveConnectionStateReason reason, |