diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2015-08-21 18:15:47 +0200 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2015-08-21 18:15:47 +0200 |
commit | f75abea53010a1863ed149e4d0450fb2b56d5f06 (patch) | |
tree | 631f2b0c1c97f984489332768876b2d0b93d1dc0 | |
parent | 3b3f5fa7552785ad67ca56b4904da92a468857e8 (diff) | |
parent | ac9d08727839a69fa0049a5b5254b006f2d03e42 (diff) | |
download | NetworkManager-bg/wol-rh1141417-on-nm-1-0.tar.gz |
merge: ethernet: add Wake-on-LAN supportbg/wol-rh1141417-on-nm-1-0
Add support for configuring Wake-on-LAN options for Ethernet
connections.
https://bugzilla.redhat.com/show_bug.cgi?id=1141417
-rw-r--r-- | clients/cli/settings.c | 63 | ||||
-rw-r--r-- | docs/libnm/Makefile.am | 3 | ||||
-rw-r--r-- | libnm-core/nm-setting-wired.c | 120 | ||||
-rw-r--r-- | libnm-core/nm-setting-wired.h | 37 | ||||
-rw-r--r-- | libnm-core/nm-utils.c | 121 | ||||
-rw-r--r-- | libnm-core/nm-utils.h | 6 | ||||
-rw-r--r-- | libnm-core/tests/Makefile.am | 15 | ||||
-rw-r--r-- | libnm-core/tests/test-general-enums.h | 46 | ||||
-rw-r--r-- | libnm-core/tests/test-general.c | 79 | ||||
-rw-r--r-- | libnm/libnm.ver | 6 | ||||
-rw-r--r-- | man/NetworkManager.conf.xml.in | 3 | ||||
-rw-r--r-- | src/devices/nm-device-ethernet.c | 37 | ||||
-rw-r--r-- | src/platform/nm-platform-utils.c | 38 | ||||
-rw-r--r-- | src/platform/nm-platform-utils.h | 4 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/reader.c | 78 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am | 3 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-wake-on-lan | 22 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 123 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/writer.c | 35 |
19 files changed, 835 insertions, 4 deletions
diff --git a/clients/cli/settings.c b/clients/cli/settings.c index 7d27f2481e..8c4af22d42 100644 --- a/clients/cli/settings.c +++ b/clients/cli/settings.c @@ -30,6 +30,7 @@ #include "settings.h" #include "nm-glib-compat.h" #include "nm-macros-internal.h" +#include "gsystem-local-alloc.h" /* Forward declarations */ static char *wep_key_type_to_string (NMWepKeyType type); @@ -96,6 +97,8 @@ NmcOutputField nmc_fields_setting_wired[] = { SETTING_FIELD (NM_SETTING_WIRED_S390_SUBCHANNELS, 20), /* 9 */ SETTING_FIELD (NM_SETTING_WIRED_S390_NETTYPE, 15), /* 10 */ SETTING_FIELD (NM_SETTING_WIRED_S390_OPTIONS, 20), /* 11 */ + SETTING_FIELD (NM_SETTING_WIRED_WAKE_ON_LAN, 10), /* 12 */ + SETTING_FIELD (NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, 20), /* 13 */ {NULL, NULL, 0, NULL, FALSE, FALSE, 0} }; #define NMC_FIELDS_SETTING_WIRED_ALL "name"","\ @@ -109,7 +112,9 @@ NmcOutputField nmc_fields_setting_wired[] = { NM_SETTING_WIRED_MTU","\ NM_SETTING_WIRED_S390_SUBCHANNELS","\ NM_SETTING_WIRED_S390_NETTYPE","\ - NM_SETTING_WIRED_S390_OPTIONS + NM_SETTING_WIRED_S390_OPTIONS","\ + NM_SETTING_WIRED_WAKE_ON_LAN","\ + NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD #define NMC_FIELDS_SETTING_WIRED_COMMON NMC_FIELDS_SETTING_WIRED_ALL /* Available fields for NM_SETTING_802_1X_SETTING_NAME */ @@ -1499,6 +1504,7 @@ DEFINE_GETTER (nmc_property_wired_get_mac_address_blacklist, NM_SETTING_WIRED_MA DEFINE_GETTER (nmc_property_wired_get_s390_subchannels, NM_SETTING_WIRED_S390_SUBCHANNELS) DEFINE_GETTER (nmc_property_wired_get_s390_nettype, NM_SETTING_WIRED_S390_NETTYPE) DEFINE_GETTER (nmc_property_wired_get_s390_options, NM_SETTING_WIRED_S390_OPTIONS) +DEFINE_GETTER (nmc_property_wired_get_wake_on_lan_password, NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD) static char * nmc_property_wired_get_mtu (NMSetting *setting, NmcPropertyGetType get_type) @@ -1513,6 +1519,45 @@ nmc_property_wired_get_mtu (NMSetting *setting, NmcPropertyGetType get_type) return g_strdup_printf ("%d", mtu); } +static char * +nmc_property_wired_get_wake_on_lan (NMSetting *setting, NmcPropertyGetType get_type) +{ + NMSettingWired *s_wired = NM_SETTING_WIRED (setting); + NMSettingWiredWakeOnLan wol; + + wol = nm_setting_wired_get_wake_on_lan (s_wired); + return nm_utils_enum_to_str (nm_setting_wired_wake_on_lan_get_type (), wol); +} + +static gboolean +nmc_property_wired_set_wake_on_lan (NMSetting *setting, const char *prop, + const char *val, GError **error) +{ + NMSettingWiredWakeOnLan wol; + gs_free char *err_token = NULL; + gboolean ret; + + ret = nm_utils_enum_from_str (nm_setting_wired_wake_on_lan_get_type (), val, + (int *) &wol, &err_token); + + if (!ret) { + g_set_error (error, 1, 0, _("invalid option '%s', use a combination of %s or 'default'"), + err_token, + nm_utils_enum_to_str (nm_setting_wired_wake_on_lan_get_type (), + NM_SETTING_WIRED_WAKE_ON_LAN_ALL)); + return FALSE; + } + + if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) && + NM_FLAGS_ANY (wol, NM_SETTING_WIRED_WAKE_ON_LAN_ALL)) { + g_set_error_literal (error, 1, 0, _("'default' is incompatible with other flags")); + return FALSE; + } + + g_object_set (setting, prop, (guint) wol, NULL); + return TRUE; +} + /* --- NM_SETTING_WIRELESS_SETTING_NAME property get functions --- */ DEFINE_GETTER (nmc_property_wireless_get_mode, NM_SETTING_WIRELESS_MODE) DEFINE_GETTER (nmc_property_wireless_get_band, NM_SETTING_WIRELESS_BAND) @@ -6203,6 +6248,20 @@ nmc_properties_init (void) nmc_property_wired_describe_s390_options, nmc_property_wired_allowed_s390_options, NULL); + nmc_add_prop_funcs (GLUE (WIRED, WAKE_ON_LAN), + nmc_property_wired_get_wake_on_lan, + nmc_property_wired_set_wake_on_lan, + NULL, + NULL, + NULL, + NULL); + nmc_add_prop_funcs (GLUE (WIRED, WAKE_ON_LAN_PASSWORD), + nmc_property_wired_get_wake_on_lan_password, + nmc_property_set_mac, + NULL, + NULL, + NULL, + NULL); /* Add editable properties for NM_SETTING_WIRELESS_SETTING_NAME */ nmc_add_prop_funcs (GLUE (WIRELESS, SSID), @@ -6786,6 +6845,8 @@ setting_wired_details (NMSetting *setting, NmCli *nmc, const char *one_prop, gb set_val_str (arr, 9, nmc_property_wired_get_s390_subchannels (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 10, nmc_property_wired_get_s390_nettype (setting, NMC_PROPERTY_GET_PRETTY)); set_val_str (arr, 11, nmc_property_wired_get_s390_options (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 12, nmc_property_wired_get_wake_on_lan (setting, NMC_PROPERTY_GET_PRETTY)); + set_val_str (arr, 13, nmc_property_wired_get_wake_on_lan_password (setting, NMC_PROPERTY_GET_PRETTY)); g_ptr_array_add (nmc->output_data, arr); print_data (nmc); /* Print all data */ diff --git a/docs/libnm/Makefile.am b/docs/libnm/Makefile.am index 28938f89ff..2525856d5f 100644 --- a/docs/libnm/Makefile.am +++ b/docs/libnm/Makefile.am @@ -53,7 +53,8 @@ IGNORE_HFILES= \ nm-setting-private.h \ nm-types.h \ nm-utils-private.h \ - nm-vpn-plugin-old.h + nm-vpn-plugin-old.h \ + nm-core-tests-enum-types.h # Images to copy into HTML directory. HTML_IMAGES = libnm.png diff --git a/libnm-core/nm-setting-wired.c b/libnm-core/nm-setting-wired.c index 2a7479405d..3d0c5b6464 100644 --- a/libnm-core/nm-setting-wired.c +++ b/libnm-core/nm-setting-wired.c @@ -30,6 +30,7 @@ #include "nm-utils.h" #include "nm-utils-private.h" #include "nm-setting-private.h" +#include "nm-macros-internal.h" /** * SECTION:nm-setting-wired @@ -57,6 +58,8 @@ typedef struct { char **s390_subchannels; char *s390_nettype; GHashTable *s390_options; + NMSettingWiredWakeOnLan wol; + char *wol_password; } NMSettingWiredPrivate; enum { @@ -72,6 +75,8 @@ enum { PROP_S390_SUBCHANNELS, PROP_S390_NETTYPE, PROP_S390_OPTIONS, + PROP_WAKE_ON_LAN, + PROP_WAKE_ON_LAN_PASSWORD, LAST_PROP }; @@ -554,6 +559,43 @@ nm_setting_wired_get_valid_s390_options (NMSettingWired *setting) return valid_s390_opts; } +/** + * nm_setting_wired_get_wake_on_lan: + * @setting: the #NMSettingWired + * + * Returns the Wake-on-LAN options enabled for the connection + * + * Returns: the Wake-on-LAN options + * + * Since: 1.0.6 + */ +NMSettingWiredWakeOnLan +nm_setting_wired_get_wake_on_lan (NMSettingWired *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), NM_SETTING_WIRED_WAKE_ON_LAN_NONE); + + return NM_SETTING_WIRED_GET_PRIVATE (setting)->wol; +} + +/** + * nm_setting_wired_get_wake_on_lan_password: + * @setting: the #NMSettingWired + * + * Returns the Wake-on-LAN password. This only applies to + * %NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC. + * + * Returns: the Wake-on-LAN setting password, or %NULL if there is no password. + * + * Since: 1.0.6 + */ +const char * +nm_setting_wired_get_wake_on_lan_password (NMSettingWired *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), NULL); + + return NM_SETTING_WIRED_GET_PRIVATE (setting)->wol_password; +} + static gboolean verify (NMSetting *setting, NMConnection *connection, GError **error) { @@ -654,6 +696,34 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + if ( NM_FLAGS_HAS (priv->wol, NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) + && NM_FLAGS_ANY (priv->wol, NM_SETTING_WIRED_WAKE_ON_LAN_ALL)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("Wake-on-LAN mode 'default' is incompatible with other flags")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_WAKE_ON_LAN); + return FALSE; + } + + if (priv->wol_password && !NM_FLAGS_HAS (priv->wol, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("Wake-on-LAN password can only be used with magic packet mode")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD); + return FALSE; + } + + if (priv->wol_password && !nm_utils_hwaddr_valid (priv->wol_password, ETH_ALEN)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("is not a valid MAC address")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD); + return FALSE; + } + return TRUE; } @@ -693,6 +763,8 @@ finalize (GObject *object) if (priv->s390_subchannels) g_strfreev (priv->s390_subchannels); + g_free (priv->wol_password); + G_OBJECT_CLASS (nm_setting_wired_parent_class)->finalize (object); } @@ -756,6 +828,13 @@ set_property (GObject *object, guint prop_id, g_hash_table_unref (priv->s390_options); priv->s390_options = _nm_utils_copy_strdict (g_value_get_boxed (value)); break; + case PROP_WAKE_ON_LAN: + priv->wol = g_value_get_uint (value); + break; + case PROP_WAKE_ON_LAN_PASSWORD: + g_free (priv->wol_password); + priv->wol_password = g_value_dup_string (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -803,6 +882,12 @@ get_property (GObject *object, guint prop_id, case PROP_S390_OPTIONS: g_value_take_boxed (value, _nm_utils_copy_strdict (priv->s390_options)); break; + case PROP_WAKE_ON_LAN: + g_value_set_uint (value, priv->wol); + break; + case PROP_WAKE_ON_LAN_PASSWORD: + g_value_set_string (value, priv->wol_password); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1097,4 +1182,39 @@ nm_setting_wired_class_init (NMSettingWiredClass *setting_class) G_VARIANT_TYPE ("a{ss}"), _nm_utils_strdict_to_dbus, _nm_utils_strdict_from_dbus); + + /** + * NMSettingWired:wake-on-lan: + * + * The #NMSettingWiredWakeOnLan options to enable. Not all devices support all options. + * May be any combination of %NM_SETTING_WIRED_WAKE_ON_LAN_PHY, + * %NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST, %NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST, + * %NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST, %NM_SETTING_WIRED_WAKE_ON_LAN_ARP, + * %NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC. + * + * Since: 1.0.6 + **/ + g_object_class_install_property + (object_class, PROP_WAKE_ON_LAN, + g_param_spec_uint (NM_SETTING_WIRED_WAKE_ON_LAN, "", "", + 0, G_MAXUINT32, NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT, + G_PARAM_CONSTRUCT | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingWired:wake-on-lan-password: + * + * If specified, the password used with magic-packet-based + * Wake-on-LAN, represented as an Ethernet MAC address. If %NULL, + * no password will be required. + * + * Since: 1.0.6 + **/ + g_object_class_install_property + (object_class, PROP_WAKE_ON_LAN_PASSWORD, + g_param_spec_string (NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); } diff --git a/libnm-core/nm-setting-wired.h b/libnm-core/nm-setting-wired.h index 4189b68967..44b7c4d023 100644 --- a/libnm-core/nm-setting-wired.h +++ b/libnm-core/nm-setting-wired.h @@ -40,6 +40,36 @@ G_BEGIN_DECLS #define NM_SETTING_WIRED_SETTING_NAME "802-3-ethernet" +/** + * NMSettingWiredWakeOnLan: + * @NM_SETTING_WIRED_WAKE_ON_LAN_NONE: Wake-on-LAN disabled + * @NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT: Use the default value + * @NM_SETTING_WIRED_WAKE_ON_LAN_PHY: Wake on PHY activity + * @NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST: Wake on unicast messages + * @NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST: Wake on multicast messages + * @NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST: Wake on broadcast messages + * @NM_SETTING_WIRED_WAKE_ON_LAN_ARP: Wake on ARP + * @NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC: Wake on magic packet + * @NM_SETTING_WIRED_WAKE_ON_LAN_ALL: Wake on all events + * + * Options for #NMSettingWired:wake-on-lan. Note that not all options + * are supported by all devices. + * + * Since: 1.0.6 + */ +typedef enum { /*< flags >*/ + NM_SETTING_WIRED_WAKE_ON_LAN_NONE = 0, /*< skip >*/ + NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT = (1 << 0), + NM_SETTING_WIRED_WAKE_ON_LAN_PHY = (1 << 1), + NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST = (1 << 2), + NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST = (1 << 3), + NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST = (1 << 4), + NM_SETTING_WIRED_WAKE_ON_LAN_ARP = (1 << 5), + NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC = (1 << 6), + _NM_SETTING_WIRED_WAKE_ON_LAN_LAST, /*< skip >*/ + NM_SETTING_WIRED_WAKE_ON_LAN_ALL = (((_NM_SETTING_WIRED_WAKE_ON_LAN_LAST - 1) << 1) - 1 - NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) /*< skip >*/ +} NMSettingWiredWakeOnLan; + #define NM_SETTING_WIRED_PORT "port" #define NM_SETTING_WIRED_SPEED "speed" #define NM_SETTING_WIRED_DUPLEX "duplex" @@ -51,6 +81,8 @@ G_BEGIN_DECLS #define NM_SETTING_WIRED_S390_SUBCHANNELS "s390-subchannels" #define NM_SETTING_WIRED_S390_NETTYPE "s390-nettype" #define NM_SETTING_WIRED_S390_OPTIONS "s390-options" +#define NM_SETTING_WIRED_WAKE_ON_LAN "wake-on-lan" +#define NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD "wake-on-lan-password" struct _NMSettingWired { NMSetting parent; @@ -104,6 +136,11 @@ gboolean nm_setting_wired_remove_s390_option (NMSettingWired *setting const char *key); const char ** nm_setting_wired_get_valid_s390_options (NMSettingWired *setting); +NM_AVAILABLE_IN_1_0_6 +NMSettingWiredWakeOnLan nm_setting_wired_get_wake_on_lan (NMSettingWired *setting); +NM_AVAILABLE_IN_1_0_6 +const char * nm_setting_wired_get_wake_on_lan_password (NMSettingWired *setting); + G_END_DECLS #endif /* __NM_SETTING_WIRED_H__ */ diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 70450af11f..34e9e94c84 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -3639,3 +3639,124 @@ _nm_dbus_error_has_name (GError *error, return has_name; } +/** + * nm_utils_enum_to_str: + * @type: the %GType of the enum + * @value: the value to be translated + * + * Converts an enum value to its string representation. If the enum is a + * %G_TYPE_FLAGS the function returns a comma-separated list of matching values. + * If the enum is a %G_TYPE_ENUM and the given value is not valid the + * function returns %NULL. + * + * Returns: a newly allocated string or %NULL + * + * Since: 1.0.6 + */ +char *nm_utils_enum_to_str (GType type, int value) +{ + GTypeClass *class; + char *ret; + + class = g_type_class_ref (type); + + if (G_IS_ENUM_CLASS (class)) { + GEnumValue *enum_value; + + enum_value = g_enum_get_value (G_ENUM_CLASS (class), value); + ret = enum_value ? strdup (enum_value->value_nick) : NULL; + } else if (G_IS_FLAGS_CLASS (class)) { + GFlagsValue *flags_value; + GString *str = g_string_new (""); + gboolean first = TRUE; + + while (value) { + flags_value = g_flags_get_first_value (G_FLAGS_CLASS (class), value); + if (!flags_value) + break; + + if (!first) + g_string_append_c (str, ','); + g_string_append (str, flags_value->value_nick); + + value &= ~flags_value->value; + first = FALSE; + } + ret = g_string_free (str, FALSE); + } else + g_return_if_reached (); + + g_type_class_unref (class); + return ret; +} + +/** + * nm_utils_enum_from_str: + * @type: the %GType of the enum + * @str: the input string + * @out_value: (out) (allow-none) the output value + * @err_token: (out) (allow-none) location to store the first unrecognized token + * + * Converts a string to the matching enum value. + * + * If the enum is a %G_TYPE_FLAGS the function returns the logical OR of values + * matching the comma-separated tokens in the string; if an unknown token is found + * the function returns %FALSE and stores a pointer to a newly allocated string + * containing the unrecognized token in @err_token. + * + * Returns: %TRUE if the conversion was successful, %FALSE otherwise + * + * Since: 1.0.6 + */ +gboolean nm_utils_enum_from_str (GType type, const char *str, + int *out_value, char **err_token) +{ + GTypeClass *class; + gboolean ret = FALSE; + int value = 0; + gs_free char *stripped = NULL; + + g_return_val_if_fail (str, FALSE); + stripped = g_strstrip (strdup (str)); + class = g_type_class_ref (type); + + if (G_IS_ENUM_CLASS (class)) { + GEnumValue *enum_value; + + enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (class), stripped); + if (enum_value) { + value = enum_value->value; + ret = TRUE; + } + } else if (G_IS_FLAGS_CLASS (class)) { + GFlagsValue *flags_value; + gs_strfreev char **strv = NULL; + int i; + + strv = g_strsplit (stripped, ",", 0); + for (i = 0; strv[i]; i++) { + if (!strv[i][0]) + continue; + + flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (class), strv[i]); + if (!flags_value) + break; + + value |= flags_value->value; + } + + if (strv[i]) { + if (err_token) + *err_token = strdup (strv[i]); + value = 0; + } else + ret = TRUE; + } else + g_assert_not_reached (); + + if (out_value) + *out_value = value; + + g_type_class_unref (class); + return ret; +} diff --git a/libnm-core/nm-utils.h b/libnm-core/nm-utils.h index 45bdf757ea..d1f4bcf4d6 100644 --- a/libnm-core/nm-utils.h +++ b/libnm-core/nm-utils.h @@ -189,6 +189,12 @@ gboolean nm_utils_ipaddr_valid (int family, const char *ip); gboolean nm_utils_check_virtual_device_compatibility (GType virtual_type, GType other_type); +NM_AVAILABLE_IN_1_0_6 +char *nm_utils_enum_to_str (GType type, int value); + +NM_AVAILABLE_IN_1_0_6 +gboolean nm_utils_enum_from_str (GType type, const char *str, int *out_value, char **err_token); + G_END_DECLS #endif /* __NM_UTILS_H__ */ diff --git a/libnm-core/tests/Makefile.am b/libnm-core/tests/Makefile.am index daa5825b50..dd38b3d685 100644 --- a/libnm-core/tests/Makefile.am +++ b/libnm-core/tests/Makefile.am @@ -1,5 +1,14 @@ if ENABLE_TESTS +include $(GLIB_MAKEFILE) + +GLIB_GENERATED = nm-core-tests-enum-types.h nm-core-tests-enum-types.c +nm_core_tests_enum_types_sources = test-general-enums.h +GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM +GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM + +BUILT_SOURCES = $(GLIB_GENERATED) + certsdir = $(srcdir)/certs AM_CPPFLAGS = \ @@ -28,6 +37,12 @@ LDADD = \ @VALGRIND_RULES@ TESTS = $(noinst_PROGRAMS) +test_general_SOURCES = \ + test-general.c \ + test-general-enums.h \ + nm-core-tests-enum-types.c \ + nm-core-tests-enum-types.h + endif # test-cert.p12 created with: diff --git a/libnm-core/tests/test-general-enums.h b/libnm-core/tests/test-general-enums.h new file mode 100644 index 0000000000..d06d6e39ff --- /dev/null +++ b/libnm-core/tests/test-general-enums.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Copyright 2015 Red Hat, Inc. + */ + +#ifndef _NM_TEST_GENERAL_ENUMS_H_ +#define _NM_TEST_GENERAL_ENUMS_H_ + +typedef enum { + NM_TEST_GENERAL_BOOL_ENUM_NO = 0, + NM_TEST_GENERAL_BOOL_ENUM_YES = 1, + NM_TEST_GENERAL_BOOL_ENUM_MAYBE = 2, + NM_TEST_GENERAL_BOOL_ENUM_UNKNOWN = 3, + NM_TEST_GENERAL_BOOL_ENUM_INVALID = 4, /*< skip >*/ +} NMTestGeneralBoolEnum; + +typedef enum { + NM_TEST_GENERAL_META_FLAGS_NONE = 0, + NM_TEST_GENERAL_META_FLAGS_FOO = (1 << 0), + NM_TEST_GENERAL_META_FLAGS_BAR = (1 << 1), + NM_TEST_GENERAL_META_FLAGS_BAZ = (1 << 2), +} NMTestGeneralMetaFlags; + +typedef enum { /*< flags >*/ + NM_TEST_GENERAL_COLOR_FLAGS_WHITE = 1, /*< skip >*/ + NM_TEST_GENERAL_COLOR_FLAGS_BLUE = 2, + NM_TEST_GENERAL_COLOR_FLAGS_RED = 4, + NM_TEST_GENERAL_COLOR_FLAGS_GREEN = 8, +} NMTestGeneralColorFlags; + +#endif /* _NM_TEST_GENERAL_ENUMS_H_ */ diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index b300acadc4..e94836527d 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -32,6 +32,7 @@ #include "nm-setting-private.h" #include "nm-utils.h" #include "nm-core-internal.h" +#include "nm-core-tests-enum-types.h" #include "nm-setting-8021x.h" #include "nm-setting-adsl.h" @@ -62,6 +63,7 @@ #include "nm-glib-compat.h" #include "nm-test-utils.h" +#include "test-general-enums.h" static void vpn_check_func (const char *key, const char *value, gpointer user_data) @@ -1984,6 +1986,8 @@ test_connection_diff_a_only (void) { NM_SETTING_WIRED_S390_SUBCHANNELS, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_WIRED_S390_NETTYPE, NM_SETTING_DIFF_RESULT_IN_A }, { NM_SETTING_WIRED_S390_OPTIONS, NM_SETTING_DIFF_RESULT_IN_A }, + { NM_SETTING_WIRED_WAKE_ON_LAN, NM_SETTING_DIFF_RESULT_IN_A }, + { NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, NM_SETTING_DIFF_RESULT_IN_A }, { NULL, NM_SETTING_DIFF_RESULT_UNKNOWN }, } }, { NM_SETTING_IP4_CONFIG_SETTING_NAME, { @@ -4536,6 +4540,79 @@ test_nm_in_set (void) /******************************************************************************/ +static void +test_nm_utils_enum_from_str_do (GType type, const char *str, + gboolean exp_result, int exp_flags, + const char *exp_err_token) +{ + int flags = 1; + char *err_token = NULL; + gboolean result; + + result = nm_utils_enum_from_str (type, str, &flags, &err_token); + + g_assert (result == exp_result); + g_assert_cmpint (flags, ==, exp_flags); + g_assert_cmpstr (err_token, ==, exp_err_token); + + g_free (err_token); +} + +static void +test_nm_utils_enum_to_str_do (GType type, int flags, const char *exp_str) +{ + char *str; + + str = nm_utils_enum_to_str (type, flags); + g_assert_cmpstr (str, ==, exp_str); + g_free (str); +} + +static void test_nm_utils_enum (void) +{ + GType bool_enum = nm_test_general_bool_enum_get_type(); + GType meta_flags = nm_test_general_meta_flags_get_type(); + GType color_flags = nm_test_general_color_flags_get_type(); + + test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_YES, "yes"); + test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_UNKNOWN, "unknown"); + test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_INVALID, NULL); + + test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_NONE, ""); + test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_BAZ, "baz"); + test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_FOO | + NM_TEST_GENERAL_META_FLAGS_BAR | + NM_TEST_GENERAL_META_FLAGS_BAZ, "foo,bar,baz"); + + test_nm_utils_enum_to_str_do (color_flags, NM_TEST_GENERAL_COLOR_FLAGS_RED, "red"); + test_nm_utils_enum_to_str_do (color_flags, NM_TEST_GENERAL_COLOR_FLAGS_WHITE, ""); + test_nm_utils_enum_to_str_do (color_flags, NM_TEST_GENERAL_COLOR_FLAGS_RED | + NM_TEST_GENERAL_COLOR_FLAGS_GREEN, "red,green"); + + test_nm_utils_enum_from_str_do (bool_enum, "", FALSE, 0, NULL); + test_nm_utils_enum_from_str_do (bool_enum, " ", FALSE, 0, NULL); + test_nm_utils_enum_from_str_do (bool_enum, "invalid", FALSE, 0, NULL); + test_nm_utils_enum_from_str_do (bool_enum, "yes", TRUE, NM_TEST_GENERAL_BOOL_ENUM_YES, NULL); + test_nm_utils_enum_from_str_do (bool_enum, "no", TRUE, NM_TEST_GENERAL_BOOL_ENUM_NO, NULL); + test_nm_utils_enum_from_str_do (bool_enum, "yes,no", FALSE, 0, NULL); + + test_nm_utils_enum_from_str_do (meta_flags, "", TRUE, 0, NULL); + test_nm_utils_enum_from_str_do (meta_flags, " ", TRUE, 0, NULL); + test_nm_utils_enum_from_str_do (meta_flags, "foo", TRUE, NM_TEST_GENERAL_META_FLAGS_FOO, NULL); + test_nm_utils_enum_from_str_do (meta_flags, "foo,baz", TRUE, NM_TEST_GENERAL_META_FLAGS_FOO | + NM_TEST_GENERAL_META_FLAGS_BAZ, NULL); + test_nm_utils_enum_from_str_do (meta_flags, "foo,,bar", TRUE, NM_TEST_GENERAL_META_FLAGS_FOO | + NM_TEST_GENERAL_META_FLAGS_BAR, NULL); + test_nm_utils_enum_from_str_do (meta_flags, "foo,baz,quux,bar", FALSE, 0, "quux"); + + test_nm_utils_enum_from_str_do (color_flags, "green", TRUE, NM_TEST_GENERAL_COLOR_FLAGS_GREEN, NULL); + test_nm_utils_enum_from_str_do (color_flags, "blue,red", TRUE, NM_TEST_GENERAL_COLOR_FLAGS_BLUE | + NM_TEST_GENERAL_COLOR_FLAGS_RED, NULL); + test_nm_utils_enum_from_str_do (color_flags, "blue,white", FALSE, 0, "white"); +} + +/******************************************************************************/ + NMTST_DEFINE (); int main (int argc, char **argv) @@ -4641,6 +4718,8 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/_glib_compat_g_ptr_array_insert", test_g_ptr_array_insert); g_test_add_func ("/core/general/_nm_utils_ptrarray_find_binary_search", test_nm_utils_ptrarray_find_binary_search); + g_test_add_func ("/core/general/test_nm_utils_enum", test_nm_utils_enum); + return g_test_run (); } diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 4bf77938ec..90c5de04e5 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -859,7 +859,11 @@ global: nm_device_wifi_request_scan_options_async; nm_metered_get_type; nm_setting_connection_get_metered; + nm_setting_wired_get_wake_on_lan; + nm_setting_wired_get_wake_on_lan_password; + nm_setting_wired_wake_on_lan_get_type; + nm_utils_enum_from_str; + nm_utils_enum_to_str; nm_utils_wifi_2ghz_freqs; nm_utils_wifi_5ghz_freqs; } libnm_1_0_4; - diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in index 40fa49dd7a..029db24e5c 100644 --- a/man/NetworkManager.conf.xml.in +++ b/man/NetworkManager.conf.xml.in @@ -528,6 +528,9 @@ ipv6.ip6-privacy=1 <varlistentry> <term><varname>connection.autoconnect-slaves</varname></term> </varlistentry> + <varlistentry> + <term><varname>ethernet.wake-on-lan</varname></term> + </varlistentry> </variablelist> </para> </refsect1> diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 7bdb4cd28c..beb86e11e9 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -53,6 +53,7 @@ #include "nm-device-factory.h" #include "nm-core-internal.h" #include "NetworkManagerUtils.h" +#include "gsystem-local-alloc.h" #include "nm-device-ethernet-glue.h" @@ -1175,6 +1176,40 @@ dcb_carrier_changed (NMDevice *device, GParamSpec *pspec, gpointer unused) /****************************************************************/ +static gboolean +wake_on_lan_enable (NMDevice *device) +{ + NMSettingWiredWakeOnLan wol; + NMSettingWired *s_wired; + const char *password = NULL; + gs_free char *value = NULL; + + s_wired = (NMSettingWired *) device_get_setting (device, NM_TYPE_SETTING_WIRED); + if (s_wired) { + wol = nm_setting_wired_get_wake_on_lan (s_wired); + password = nm_setting_wired_get_wake_on_lan_password (s_wired); + if (wol != NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) + goto found; + } + + value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "ethernet.wake-on-lan", + device); + if (value) { + wol = _nm_utils_ascii_str_to_int64 (value, 10, + NM_SETTING_WIRED_WAKE_ON_LAN_NONE, + NM_SETTING_WIRED_WAKE_ON_LAN_ALL, + NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT); + if (wol != NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) + goto found; + } + wol = NM_SETTING_WIRED_WAKE_ON_LAN_NONE; +found: + return nmp_utils_ethtool_set_wake_on_lan (nm_device_get_iface (device), wol, password); +} + +/****************************************************************/ + static NMActStageReturn act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) { @@ -1207,6 +1242,8 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) } } + wake_on_lan_enable (device); + /* DCB and FCoE setup */ s_dcb = (NMSettingDcb *) device_get_setting (device, NM_TYPE_SETTING_DCB); if (s_dcb) { diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index c6ea6c99b9..b7f0947efb 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -33,6 +33,7 @@ #include "nm-utils.h" #include "NetworkManagerUtils.h" #include "nm-logging.h" +#include "nm-setting-wired.h" /****************************************************************** @@ -261,6 +262,43 @@ nmp_utils_ethtool_get_link_speed (const char *ifname, guint32 *out_speed) return TRUE; } +gboolean +nmp_utils_ethtool_set_wake_on_lan (const char *ifname, + NMSettingWiredWakeOnLan wol, + const char *wol_password) +{ + struct ethtool_wolinfo wol_info = { }; + + nm_log_dbg (LOGD_PLATFORM, "setting Wake-on-LAN options 0x%x, password '%s'", + (unsigned int) wol, wol_password); + + wol_info.cmd = ETHTOOL_SWOL; + wol_info.wolopts = 0; + + if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_PHY)) + wol_info.wolopts |= WAKE_PHY; + if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST)) + wol_info.wolopts |= WAKE_UCAST; + if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST)) + wol_info.wolopts |= WAKE_MCAST; + if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST)) + wol_info.wolopts |= WAKE_BCAST; + if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_ARP)) + wol_info.wolopts |= WAKE_ARP; + if (NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) + wol_info.wolopts |= WAKE_MAGIC; + + if (wol_password) { + if (!nm_utils_hwaddr_aton (wol_password, wol_info.sopass, ETH_ALEN)) { + nm_log_dbg (LOGD_PLATFORM, "couldn't parse Wake-on-LAN password '%s'", wol_password); + return FALSE; + } + wol_info.wolopts |= WAKE_MAGICSECURE; + } + + return ethtool_get (ifname, &wol_info); +} + /****************************************************************** * mii ******************************************************************/ diff --git a/src/platform/nm-platform-utils.h b/src/platform/nm-platform-utils.h index ebebb905b8..3769a8e193 100644 --- a/src/platform/nm-platform-utils.h +++ b/src/platform/nm-platform-utils.h @@ -26,6 +26,7 @@ #include <gudev/gudev.h> #include "nm-platform.h" +#include "nm-setting-wired.h" const char *nmp_utils_ethtool_get_driver (const char *ifname); @@ -33,6 +34,9 @@ gboolean nmp_utils_ethtool_supports_carrier_detect (const char *ifname); gboolean nmp_utils_ethtool_supports_vlans (const char *ifname); int nmp_utils_ethtool_get_peer_ifindex (const char *ifname); gboolean nmp_utils_ethtool_get_wake_on_lan (const char *ifname); +gboolean nmp_utils_ethtool_set_wake_on_lan (const char *ifname, NMSettingWiredWakeOnLan wol, + const char *wol_password); + gboolean nmp_utils_ethtool_get_link_speed (const char *ifname, guint32 *out_speed); gboolean nmp_utils_ethtool_get_driver_info (const char *ifname, diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c index 170b4b2905..72123e669e 100644 --- a/src/settings/plugins/ifcfg-rh/reader.c +++ b/src/settings/plugins/ifcfg-rh/reader.c @@ -3501,6 +3501,80 @@ wireless_connection_from_ifcfg (const char *file, return connection; } +static void +parse_ethtool_options (shvarFile *ifcfg, NMSettingWired *s_wired, char *value) +{ + NMSettingWiredWakeOnLan wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_NONE; + gboolean use_password = FALSE; + char **words, **iter, *flag; + + if (!value || !value[0]) + return; + + words = g_strsplit_set (value, " ", 0); + iter = words; + + while (iter[0]) { + if (g_str_equal (iter[0], "wol") && iter[1] && *iter[1]) { + for (flag = iter[1]; *flag; flag++) { + switch (*flag) { + 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': + use_password = TRUE; + break; + case 'd': + wol_flags = NM_SETTING_WIRED_WAKE_ON_LAN_NONE; + use_password = FALSE; + break; + default: + PARSE_WARNING ("unrecognized Wake-on-LAN option '%c'", *flag); + } + } + + if (!NM_FLAGS_HAS (wol_flags, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) + use_password = FALSE; + + g_object_set (s_wired, NM_SETTING_WIRED_WAKE_ON_LAN, wol_flags, NULL); + iter += 2; + continue; + } + + if (g_str_equal (iter[0], "sopass") && iter[1] && *iter[1]) { + if (use_password) { + if (nm_utils_hwaddr_valid (iter[1], ETH_ALEN)) + g_object_set (s_wired, NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, iter[1], NULL); + else + PARSE_WARNING ("Wake-on-LAN password '%s' is invalid", iter[1]); + } else + PARSE_WARNING ("Wake-on-LAN password not expected"); + iter += 2; + continue; + } + + /* Silently skip unknown options */ + iter++; + } + + g_strfreev (words); +} + static NMSetting * make_wired_setting (shvarFile *ifcfg, const char *file, @@ -3636,6 +3710,10 @@ make_wired_setting (shvarFile *ifcfg, g_free (value); } + value = svGetValue (ifcfg, "ETHTOOL_OPTS", FALSE); + parse_ethtool_options (ifcfg, s_wired, value); + g_free (value); + return (NMSetting *) s_wired; error: diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am index a20a78d9a5..7b5aaf1716 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am @@ -123,7 +123,8 @@ EXTRA_DIST = \ ifcfg-test-team-master \ ifcfg-test-team-port \ ifcfg-test-team-port-empty-config \ - ifcfg-test-vlan-trailing-spaces + ifcfg-test-vlan-trailing-spaces \ + ifcfg-test-wired-wake-on-lan # make target dependencies can't have colons in their names, which ends up # meaning that we can't add the alias files to EXTRA_DIST diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-wake-on-lan b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-wake-on-lan new file mode 100644 index 0000000000..1dfc9a4331 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-wake-on-lan @@ -0,0 +1,22 @@ +# Intel Corporation 82540EP Gigabit Ethernet Controller (Mobile) +TYPE=Ethernet +DEVICE=eth0 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=none +ONBOOT=yes +USERCTL=yes +MTU=1492 +NM_CONTROLLED=yes +DNS1=4.2.2.1 +DNS2=4.2.2.2 +IPADDR=192.168.1.5 +NETMASK=255.255.255.0 +GATEWAY=192.168.1.1 +IPV6INIT=yes +IPV6_AUTOCONF=no +IPV6ADDR=dead:beaf::1 +IPV6ADDR_SECONDARIES="dead:beaf::2/56" +DNS3=1:2:3:4::a +DNS4=1:2:3:4::b +RES_OPTIONS= +ETHTOOL_OPTS="speed 100 duplex full wol apgs sopass 00:11:22:33:44:55 autoneg off" 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 0edbe9b209..f2f85d3c1f 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -5104,6 +5104,43 @@ test_read_wifi_wep_eap_ttls_chap (void) } static void +test_read_wired_wake_on_lan (void) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + gboolean success; + GError *error = NULL; + + connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wired-wake-on-lan", + NULL, TYPE_WIRELESS, NULL, &error); + g_assert_no_error (error); + g_assert (connection); + + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); + + s_wired = nm_connection_get_setting_wired (connection); + g_assert (s_wired); + g_assert_cmpint (nm_setting_wired_get_wake_on_lan (s_wired), + ==, + NM_SETTING_WIRED_WAKE_ON_LAN_ARP | + NM_SETTING_WIRED_WAKE_ON_LAN_PHY | + NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC); + + g_assert_cmpstr (nm_setting_wired_get_wake_on_lan_password (s_wired), + ==, + "00:11:22:33:44:55"); + + g_object_unref (connection); +} + +static void test_read_wifi_hidden (void) { NMConnection *connection; @@ -5218,6 +5255,90 @@ test_write_wifi_hidden (void) } static void +test_write_wired_wake_on_lan (void) +{ + NMConnection *connection, *reread; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingWiredWakeOnLan wol; + char *uuid, *testfile = NULL, *val; + gboolean success; + GError *error = NULL; + shvarFile *f; + + connection = nm_simple_connection_new (); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + uuid = nm_utils_uuid_generate (); + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, "Test Write Wired Wake-on-LAN", + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, + NULL); + g_free (uuid); + + /* Wired setting */ + s_wired = (NMSettingWired *) nm_setting_wired_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + + wol = NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST | + NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST | + NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC; + + g_object_set (s_wired, + NM_SETTING_WIRED_WAKE_ON_LAN, wol, + NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD, "00:00:00:11:22:33", + NULL); + + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + /* Save the ifcfg */ + success = writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile, + &error); + g_assert_no_error (error); + g_assert (success); + + f = svOpenFile (testfile, &error); + g_assert_no_error (error); + g_assert (f); + + /* re-read the file to check that the key was written. */ + val = svGetValue (f, "ETHTOOL_OPTS", FALSE); + g_assert (val); + g_assert (strstr (val, "wol")); + g_assert (strstr (val, "sopass 00:00:00:11:22:33")); + g_free (val); + svCloseFile (f); + + /* reread will be normalized, so we must normalize connection too. */ + nm_connection_normalize (connection, NULL, NULL, NULL); + + /* re-read the connection for comparison */ + reread = connection_from_file_test (testfile, NULL, TYPE_ETHERNET, + NULL, &error); + unlink (testfile); + g_assert_no_error (error); + g_assert (reread); + + success = nm_connection_verify (reread, &error); + g_assert_no_error (error); + g_assert (success); + + g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT)); + + g_free (testfile); + g_object_unref (connection); + g_object_unref (reread); +} + +static void test_read_wifi_band_a (void) { NMConnection *connection; @@ -12551,6 +12672,7 @@ int main (int argc, char **argv) test_read_vlan_only_vlan_id (); test_read_vlan_only_device (); g_test_add_func (TPATH "vlan/physdev", test_read_vlan_physdev); + g_test_add_func (TPATH "wired/read-wake-on-lan", test_read_wired_wake_on_lan); test_write_wired_static (); test_write_wired_static_ip6_only (); @@ -12565,6 +12687,7 @@ int main (int argc, char **argv) test_write_wired_8021x_tls (NM_SETTING_802_1X_CK_SCHEME_BLOB, NM_SETTING_SECRET_FLAG_NONE); test_write_wired_aliases (); g_test_add_func (TPATH "ipv4/write-static-addresses-GATEWAY", test_write_gateway); + g_test_add_func (TPATH "wired/write-wake-on-lan", test_write_wired_wake_on_lan); test_write_wifi_open (); test_write_wifi_open_hex_ssid (); test_write_wifi_wep (); diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c index 146cd34096..8bdc1028ab 100644 --- a/src/settings/plugins/ifcfg-rh/writer.c +++ b/src/settings/plugins/ifcfg-rh/writer.c @@ -42,6 +42,8 @@ #include <nm-setting-team-port.h> #include "nm-core-internal.h" #include <nm-utils.h> +#include "nm-core-internal.h" +#include "nm-macros-internal.h" #include "nm-logging.h" #include "gsystem-local-alloc.h" @@ -1048,6 +1050,8 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) const char *const *s390_subchannels; GString *str; const char * const *macaddr_blacklist; + NMSettingWiredWakeOnLan wol; + const char *wol_password; s_wired = nm_connection_get_setting_wired (connection); if (!s_wired) { @@ -1131,6 +1135,37 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) g_string_free (str, TRUE); } + wol = nm_setting_wired_get_wake_on_lan (s_wired); + wol_password = nm_setting_wired_get_wake_on_lan_password (s_wired); + if (wol == NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) + svSetValue (ifcfg, "ETHTOOL_OPTS", NULL, FALSE); + else { + str = g_string_sized_new (30); + 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); + + svSetValue (ifcfg, "ETHTOOL_OPTS", str->str, FALSE); + g_string_free (str, TRUE); + } + svSetValue (ifcfg, "TYPE", TYPE_ETHERNET, FALSE); return TRUE; |