From fc91d538f533870a30714fd443bdcc8452dda191 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Tue, 12 May 2015 11:55:52 +0200 Subject: [PATCH] ifcfg-rh: add support for Wake-on-LAN ethtool options Based on branch danw/wip/ethtool by Dan Winship (cherry picked from commit 2e0d0bc050b44afaeb017cc30ac409c743b9b171) --- src/settings/plugins/ifcfg-rh/reader.c | 78 +++++++++++ .../tests/network-scripts/Makefile.am | 3 +- .../ifcfg-test-wired-wake-on-lan | 22 ++++ .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 123 ++++++++++++++++++ src/settings/plugins/ifcfg-rh/writer.c | 31 +++++ 5 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-wake-on-lan 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 @@ -5103,6 +5103,43 @@ test_read_wifi_wep_eap_ttls_chap (void) g_object_unref (connection); } +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) { @@ -5217,6 +5254,90 @@ test_write_wifi_hidden (void) g_object_unref (reread); } +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) { @@ -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..2184c8ff58 100644 --- a/src/settings/plugins/ifcfg-rh/writer.c +++ b/src/settings/plugins/ifcfg-rh/writer.c @@ -42,6 +42,8 @@ #include #include "nm-core-internal.h" #include +#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,33 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) g_string_free (str, TRUE); } + svSetValue (ifcfg, "ETHTOOL_OPTS", NULL, FALSE); + wol = nm_setting_wired_get_wake_on_lan (s_wired); + wol_password = nm_setting_wired_get_wake_on_lan_password (s_wired); + if (wol) { + 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 (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;