diff options
Diffstat (limited to 'src/settings/plugins/ifcfg-rh')
18 files changed, 1520 insertions, 760 deletions
diff --git a/src/settings/plugins/ifcfg-rh/meson.build b/src/settings/plugins/ifcfg-rh/meson.build index 964ce22d..5d9689a5 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,7 +16,6 @@ libnmdbus_ifcfg_rh = static_library( name, sources: dbus_sources, dependencies: glib_dep, - c_args: cflags ) sources = files( @@ -33,7 +27,6 @@ sources = files( ) deps = [ - crypto_dep, nm_dep ] @@ -41,7 +34,6 @@ libnms_ifcfg_rh_core = static_library( 'nms-ifcfg-rh-core', sources: sources, dependencies: deps, - c_args: cflags ) sources = [dbus_sources] + files('nms-ifcfg-rh-connection.c') @@ -50,7 +42,6 @@ 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, 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..e1a2289e 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_connection_get_setting_sriov (connection); + 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..70693861 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; @@ -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_connection_get_setting_sriov (connection); + 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); |