diff --git a/NEWS b/NEWS index 62f6be58e4..2a0c19f4ec 100644 --- a/NEWS +++ b/NEWS @@ -31,6 +31,8 @@ Notable changes included in this snapshot so far include: type. The internal client is not affected by the change. * DNS setting rc-manager=file now always follows dangling symlinks instead of replacing /etc/resolv.conf with a plain file. +* Added wake_on_wlan connection setting to configure + wake-on-wireless-lan (WoWLAN). The following features were backported to 1.10.x releases from 1.10.0 to 1.10.8 are also present in NetworkManager-1.12: diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 6f0183492e..3e4bd1bb0b 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -7258,6 +7258,20 @@ static const NMMetaPropertyInfo *const property_infos_WIRELESS[] = { .typ_flags = NM_META_PROPERTY_TYP_FLAG_ENUM_GET_PARSABLE_TEXT, ), ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_WAKE_ON_WLAN, + .property_type = &_pt_gobject_enum, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (gobject_enum, + .get_gtype = nm_setting_wireless_wake_on_wlan_get_type, + .value_infos = ENUM_VALUE_INFOS ( + { + .value = NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE, + .nick = "disabled", + } + ), + ), + ), + ), NULL }; diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index 7beed42964..86447af267 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -21,6 +21,7 @@ #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SEEN_BSSIDS N_("A list of BSSIDs (each BSSID formatted as a MAC address like \"00:11:22:33:44:55\") that have been detected as part of the Wi-Fi network. NetworkManager internally tracks previously seen BSSIDs. The property is only meant for reading and reflects the BSSID list of NetworkManager. The changes you make to this property will not be preserved.") #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SSID N_("SSID of the Wi-Fi network. Must be specified.") #define DESCRIBE_DOC_NM_SETTING_WIRELESS_TX_POWER N_("If non-zero, directs the device to use the specified transmit power. Units are dBm. This property is highly driver dependent and not all devices support setting a static transmit power.") +#define DESCRIBE_DOC_NM_SETTING_WIRELESS_WAKE_ON_WLAN N_("The NMSettingWirelessWakeOnWLan options to enable. Not all devices support all options. May be any combination of NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY (0x2), NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT (0x4), NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC (0x8), NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE (0x10), NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST (0x20), NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE (0x40), NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE (0x80), NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP (0x100) or the special values NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT (0x1) (to use global settings) and NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE (0x8000) (to disable management of Wake-on-LAN in NetworkManager).") #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_AUTH_ALG N_("When WEP is used (ie, key-mgmt = \"none\" or \"ieee8021x\") indicate the 802.11 authentication algorithm required by the AP here. One of \"open\" for Open System, \"shared\" for Shared Key, or \"leap\" for Cisco LEAP. When using Cisco LEAP (ie, key-mgmt = \"ieee8021x\" and auth-alg = \"leap\") the \"leap-username\" and \"leap-password\" properties must be specified.") #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_FILS N_("Indicates whether Fast Initial Link Setup (802.11ai) must be enabled for the connection. One of NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) (use global default value), NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE (1) (disable FILS), NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL (2) (enable FILS if the supplicant and the access point support it) or NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED (3) (enable FILS and fail if not supported). When set to NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT (0) and no global default is set, FILS will be optionally enabled.") #define DESCRIBE_DOC_NM_SETTING_WIRELESS_SECURITY_GROUP N_("A list of group/broadcast encryption algorithms which prevents connections to Wi-Fi networks that do not utilize one of the algorithms in the list. For maximum compatibility leave this property empty. Each list element may be one of \"wep40\", \"wep104\", \"tkip\", or \"ccmp\".") diff --git a/clients/tests/test-client.check-on-disk/test_004-008.expected b/clients/tests/test-client.check-on-disk/test_004-008.expected index e9b5147b72..ad9b5a40ed 100644 --- a/clients/tests/test-client.check-on-disk/test_004-008.expected +++ b/clients/tests/test-client.check-on-disk/test_004-008.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:923:test_004()/8 cmd: $NMCLI con s con-xx1 lang: C returncode: 0 -stdout: 3756 bytes +stdout: 3810 bytes >>> connection.id: con-xx1 connection.uuid: UUID-con-xx1-REPLACED-REPLACED-REPLA @@ -41,6 +41,7 @@ connection.mdns: -1 (default) 802-11-wireless.seen-bssids: -- 802-11-wireless.hidden: no 802-11-wireless.powersave: 0 (default) +802-11-wireless.wake-on-wlan: 0x1 (default) ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- diff --git a/clients/tests/test-client.check-on-disk/test_004-009.expected b/clients/tests/test-client.check-on-disk/test_004-009.expected index 5e196fd1a2..86270c26f8 100644 --- a/clients/tests/test-client.check-on-disk/test_004-009.expected +++ b/clients/tests/test-client.check-on-disk/test_004-009.expected @@ -2,7 +2,7 @@ location: clients/tests/test-client.py:923:test_004()/9 cmd: $NMCLI con s con-xx1 lang: pl_PL.UTF-8 returncode: 0 -stdout: 3774 bytes +stdout: 3828 bytes >>> connection.id: con-xx1 connection.uuid: UUID-con-xx1-REPLACED-REPLACED-REPLA @@ -41,6 +41,7 @@ connection.mdns: -1 (default) 802-11-wireless.seen-bssids: -- 802-11-wireless.hidden: nie 802-11-wireless.powersave: 0 (default) +802-11-wireless.wake-on-wlan: 0x1 (default) ipv4.method: auto ipv4.dns: -- ipv4.dns-search: -- diff --git a/libnm-core/nm-setting-wireless.c b/libnm-core/nm-setting-wireless.c index 38948dee3e..89a2df8ebe 100644 --- a/libnm-core/nm-setting-wireless.c +++ b/libnm-core/nm-setting-wireless.c @@ -63,6 +63,7 @@ typedef struct { gboolean hidden; guint32 powersave; NMSettingMacRandomization mac_address_randomization; + guint32 wowl; } NMSettingWirelessPrivate; enum { @@ -83,6 +84,7 @@ enum { PROP_HIDDEN, PROP_POWERSAVE, PROP_MAC_ADDRESS_RANDOMIZATION, + PROP_WAKE_ON_WLAN, LAST_PROP }; @@ -885,6 +887,26 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + if (NM_FLAGS_ANY (priv->wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_EXCLUSIVE_FLAGS)) { + if (!nm_utils_is_power_of_two (priv->wowl)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("Wake-on-WLAN mode 'default' and 'ignore' are exclusive flags")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, + NM_SETTING_WIRELESS_WAKE_ON_WLAN); + return FALSE; + } + } else if (NM_FLAGS_ANY (priv->wowl, ~NM_SETTING_WIRELESS_WAKE_ON_WLAN_ALL)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("Wake-on-WLAN trying to set unknown flag")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, + NM_SETTING_WIRELESS_WAKE_ON_WLAN); + return FALSE; + } + /* from here on, check for NM_SETTING_VERIFY_NORMALIZABLE conditions. */ if (priv->cloned_mac_address) { @@ -939,6 +961,24 @@ nm_setting_wireless_get_security (NMSetting *setting, return NULL; } +/** + * nm_setting_wireless_get_wake_on_wlan: + * @setting: the #NMSettingWireless + * + * Returns the Wake-on-WLAN options enabled for the connection + * + * Returns: the Wake-on-WLAN options + * + * Since: 1.12 + */ +NMSettingWirelessWakeOnWLan +nm_setting_wireless_get_wake_on_wlan (NMSettingWireless *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_WIRELESS (setting), NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE); + + return NM_SETTING_WIRELESS_GET_PRIVATE (setting)->wowl; +} + static void clear_blacklist_item (char **item_p) { @@ -1061,6 +1101,9 @@ set_property (GObject *object, guint prop_id, case PROP_MAC_ADDRESS_RANDOMIZATION: priv->mac_address_randomization = g_value_get_uint (value); break; + case PROP_WAKE_ON_WLAN: + priv->wowl = g_value_get_uint (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1123,6 +1166,9 @@ get_property (GObject *object, guint prop_id, case PROP_MAC_ADDRESS_RANDOMIZATION: g_value_set_uint (value, nm_setting_wireless_get_mac_address_randomization (setting)); break; + case PROP_WAKE_ON_WLAN: + g_value_set_uint (value, nm_setting_wireless_get_wake_on_wlan (setting)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1636,4 +1682,30 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_wireless_class) _nm_setting_class_add_dbus_only_property (setting_class, "security", G_VARIANT_TYPE_STRING, nm_setting_wireless_get_security, NULL); + + /** + * NMSettingWireless:wake-on-wlan: + * + * The #NMSettingWirelessWakeOnWLan options to enable. Not all devices support all options. + * May be any combination of %NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY, + * %NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT, + * %NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC, + * %NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE, + * %NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST, + * %NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE, + * %NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE, + * %NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP or the special values + * %NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT (to use global settings) and + * %NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE (to disable management of Wake-on-LAN in + * NetworkManager). + * + * Since: 1.12 + **/ + g_object_class_install_property + (object_class, PROP_WAKE_ON_WLAN, + g_param_spec_uint (NM_SETTING_WIRELESS_WAKE_ON_WLAN, "", "", + 0, G_MAXUINT32, NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT, + G_PARAM_CONSTRUCT | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); } diff --git a/libnm-core/nm-setting-wireless.h b/libnm-core/nm-setting-wireless.h index b0ef475682..e9afe2c67f 100644 --- a/libnm-core/nm-setting-wireless.h +++ b/libnm-core/nm-setting-wireless.h @@ -41,6 +41,48 @@ G_BEGIN_DECLS #define NM_SETTING_WIRELESS_SETTING_NAME "802-11-wireless" +/** + * NMSettingWirelessWakeOnWLan: + * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE: Wake-on-WLAN disabled + * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY: Wake on any activity + * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT: Wake on disconnect + * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC: Wake on magic packet + * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE: Wake on GTK rekey failure + * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST: Wake on EAP identity request + * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE: Wake on 4way hanshake + * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE: Wake on rfkill release + * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_ALL: Wake on all events. This does not + * include the exclusive flags @NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT or + * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE. + * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT: Use the default value + * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE: Don't change configured settings + * @NM_SETTING_WIRELESS_WAKE_ON_WLAN_EXCLUSIVE_FLAGS: Mask of flags that are + * incompatible with other flags + * + * Options for #NMSettingWireless:wake-on-wlan. Note that not all options + * are supported by all devices. + * + * Since: 1.12 + */ +typedef enum { /*< flags >*/ + NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE = 0, /*< skip >*/ + NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY = (1 << 1), + NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT = (1 << 2), + NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC = (1 << 3), + NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE = (1 << 4), + NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST = (1 << 5), + NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE = (1 << 6), + NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE = (1 << 7), + NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP = (1 << 8), + _NM_SETTING_WIRELESS_WAKE_ON_WLAN_NUM, /*< skip >*/ + NM_SETTING_WIRELESS_WAKE_ON_WLAN_LAST = _NM_SETTING_WIRELESS_WAKE_ON_WLAN_NUM - 1, /*< skip >*/ + NM_SETTING_WIRELESS_WAKE_ON_WLAN_ALL = ((NM_SETTING_WIRELESS_WAKE_ON_WLAN_LAST << 1) - 1) - (1 << 0 /*DEFAULT*/), /*< skip >*/ + + NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT = (1 << 0), + NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE = (1 << 15), + NM_SETTING_WIRELESS_WAKE_ON_WLAN_EXCLUSIVE_FLAGS = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT | NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE, /*< skip >*/ +} NMSettingWirelessWakeOnWLan; + #define NM_SETTING_WIRELESS_SSID "ssid" #define NM_SETTING_WIRELESS_MODE "mode" #define NM_SETTING_WIRELESS_BAND "band" @@ -57,6 +99,7 @@ G_BEGIN_DECLS #define NM_SETTING_WIRELESS_HIDDEN "hidden" #define NM_SETTING_WIRELESS_POWERSAVE "powersave" #define NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION "mac-address-randomization" +#define NM_SETTING_WIRELESS_WAKE_ON_WLAN "wake-on-wlan" /** * NM_SETTING_WIRELESS_MODE_ADHOC: @@ -166,6 +209,9 @@ gboolean nm_setting_wireless_ap_security_compatible (NMSettingWireless NM80211ApSecurityFlags ap_rsn, NM80211Mode ap_mode); +NM_AVAILABLE_IN_1_12 +NMSettingWirelessWakeOnWLan nm_setting_wireless_get_wake_on_wlan (NMSettingWireless *setting); + G_END_DECLS #endif /* __NM_SETTING_WIRELESS_H__ */ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 08b7c531e7..f17cc46e88 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1363,6 +1363,8 @@ global: nm_setting_vpn_get_secret_keys; nm_setting_wireless_security_get_fils; nm_setting_wireless_security_fils_get_type; + nm_setting_wireless_get_wake_on_wlan; + nm_setting_wireless_wake_on_wlan_get_type; nm_settings_connection_flags_get_type; nm_vpn_service_plugin_shutdown; } libnm_1_10_0; diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index f3c23e60f3..bcb0e5471f 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -2423,6 +2423,48 @@ error: /*****************************************************************************/ +static gboolean +wake_on_wlan_enable (NMDeviceWifi *self) +{ + NMSettingWirelessWakeOnWLan wowl; + NMSettingWireless *s_wireless; + gs_free char *value = NULL; + + s_wireless = (NMSettingWireless *) nm_device_get_applied_setting (NM_DEVICE (self), NM_TYPE_SETTING_WIRELESS); + if (s_wireless) { + wowl = nm_setting_wireless_get_wake_on_wlan (s_wireless); + if (wowl != NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT) + goto found; + } + + value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "wifi.wake-on-wlan", + NM_DEVICE (self)); + + if (value) { + wowl = _nm_utils_ascii_str_to_int64 (value, 10, + NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE, + G_MAXINT32, + NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT); + + if (NM_FLAGS_ANY (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_EXCLUSIVE_FLAGS)) { + if (!nm_utils_is_power_of_two (wowl)) { + _LOGD (LOGD_WIFI, "invalid default value %u for wake-on-wlan: " + "'default' and 'ignore' are exclusive flags", (guint) wowl); + wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT; + } + } else if (NM_FLAGS_ANY (wowl, ~NM_SETTING_WIRELESS_WAKE_ON_WLAN_ALL)) { + _LOGD (LOGD_WIFI, "invalid default value %u for wake-on-wlan", (guint) wowl); + wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT; + } + if (wowl != NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT) + goto found; + } + wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; +found: + return nm_platform_wifi_set_wake_on_wlan (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), wowl); +} + static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) { @@ -2616,6 +2658,8 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) s_wireless = nm_connection_get_setting_wireless (connection); g_assert (s_wireless); + wake_on_wlan_enable (self); + /* If we need secrets, get them */ setting_name = nm_connection_need_secrets (connection, NULL); if (setting_name) { @@ -3083,7 +3127,8 @@ can_reapply_change (NMDevice *device, return nm_device_hash_check_invalid_keys (diffs, NM_SETTING_WIRELESS_SETTING_NAME, error, - NM_SETTING_WIRELESS_MTU); /* reapplied with IP config */ + NM_SETTING_WIRELESS_MTU, /* reapplied with IP config */ + NM_SETTING_WIRELESS_WAKE_ON_WLAN); } device_class = NM_DEVICE_CLASS (nm_device_wifi_parent_class); @@ -3095,6 +3140,20 @@ can_reapply_change (NMDevice *device, error); } +static void +reapply_connection (NMDevice *device, NMConnection *con_old, NMConnection *con_new) +{ + NMDeviceWifi *self = NM_DEVICE_WIFI (device); + + NM_DEVICE_CLASS (nm_device_wifi_parent_class)->reapply_connection (device, + con_old, + con_new); + + _LOGD (LOGD_DEVICE, "reapplying wireless settings"); + + wake_on_wlan_enable (self); +} + /*****************************************************************************/ static void @@ -3264,6 +3323,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) parent_class->deactivate_reset_hw_addr = deactivate_reset_hw_addr; parent_class->unmanaged_on_quit = unmanaged_on_quit; parent_class->can_reapply_change = can_reapply_change; + parent_class->reapply_connection = reapply_connection; parent_class->state_changed = device_state_changed; diff --git a/src/nm-manager.c b/src/nm-manager.c index c594f9b745..c6d82c9d40 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1558,6 +1558,12 @@ again: } } +static gboolean +device_is_wake_on_lan (NMPlatform *platform, NMDevice *device) +{ + return nm_platform_link_get_wake_on_lan (platform, nm_device_get_ip_ifindex (device)); +} + static void remove_device (NMManager *self, NMDevice *device, @@ -1567,14 +1573,19 @@ remove_device (NMManager *self, NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); gboolean unmanage = FALSE; - _LOG2D (LOGD_DEVICE, device, "removing device (allow_unmanage %d, managed %d)", - allow_unmanage, nm_device_get_managed (device, FALSE)); + _LOG2D (LOGD_DEVICE, device, "removing device (allow_unmanage %d, managed %d, wol %d)", + allow_unmanage, nm_device_get_managed (device, FALSE), + device_is_wake_on_lan (priv->platform, device)); if (allow_unmanage && nm_device_get_managed (device, FALSE)) { - if (quitting) - unmanage = nm_device_unmanage_on_quit (device); - else { + if (quitting) { + /* Leave configured if wo(w)lan and quitting */ + if (device_is_wake_on_lan (priv->platform, device)) + unmanage = FALSE; + else + unmanage = nm_device_unmanage_on_quit (device); + } else { /* the device is already gone. Unmanage it. */ unmanage = TRUE; } @@ -5138,12 +5149,6 @@ done: g_clear_object (&subject); } -static gboolean -device_is_wake_on_lan (NMPlatform *platform, NMDevice *device) -{ - return nm_platform_link_get_wake_on_lan (platform, nm_device_get_ip_ifindex (device)); -} - static gboolean sleep_devices_add (NMManager *self, NMDevice *device, gboolean suspending) { diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 3a671acf74..9bd662a18c 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -6092,6 +6092,14 @@ wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean ru wifi_utils_indicate_addressing_running (wifi_data, running); } +static gboolean +wifi_set_wake_on_wlan (NMPlatform *platform, int ifindex, + NMSettingWirelessWakeOnWLan wowl) +{ + WIFI_GET_WIFI_DATA_NETNS (wifi_data, platform, ifindex, FALSE); + return wifi_utils_set_wake_on_wlan (wifi_data, wowl); +} + /*****************************************************************************/ static gboolean @@ -7230,6 +7238,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->wifi_set_powersave = wifi_set_powersave; platform_class->wifi_find_frequency = wifi_find_frequency; platform_class->wifi_indicate_addressing_running = wifi_indicate_addressing_running; + platform_class->wifi_set_wake_on_wlan = wifi_set_wake_on_wlan; platform_class->mesh_get_channel = mesh_get_channel; platform_class->mesh_set_channel = mesh_set_channel; diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h index c0dc09c4b8..b938fa4a4d 100644 --- a/src/platform/nm-netlink.h +++ b/src/platform/nm-netlink.h @@ -244,6 +244,9 @@ nla_put_string (struct nl_msg *msg, int attrtype, const char *str) #define NLA_PUT_STRING(msg, attrtype, value) \ NLA_PUT(msg, attrtype, (int) strlen(value) + 1, value) +#define NLA_PUT_FLAG(msg, attrtype) \ + NLA_PUT(msg, attrtype, 0, NULL) + struct nlattr *nla_find (const struct nlattr *head, int len, int attrtype); static inline int diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 1a94ce282a..b9dcaf27f6 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -2888,6 +2888,16 @@ nm_platform_wifi_indicate_addressing_running (NMPlatform *self, int ifindex, gbo klass->wifi_indicate_addressing_running (self, ifindex, running); } +gboolean +nm_platform_wifi_set_wake_on_wlan (NMPlatform *self, int ifindex, NMSettingWirelessWakeOnWLan wowl) +{ + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (ifindex > 0, FALSE); + + return klass->wifi_set_wake_on_wlan (self, ifindex, wowl); +} + guint32 nm_platform_mesh_get_channel (NMPlatform *self, int ifindex) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 2d2bfaab7c..5d5ce4c869 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -33,6 +33,7 @@ #include "nm-core-utils.h" #include "nm-setting-vlan.h" #include "nm-setting-wired.h" +#include "nm-setting-wireless.h" #include "nm-setting-ip-tunnel.h" #define NM_TYPE_PLATFORM (nm_platform_get_type ()) @@ -867,6 +868,7 @@ typedef struct { void (*wifi_set_powersave) (NMPlatform *, int ifindex, guint32 powersave); guint32 (*wifi_find_frequency) (NMPlatform *, int ifindex, const guint32 *freqs); void (*wifi_indicate_addressing_running) (NMPlatform *, int ifindex, gboolean running); + gboolean (*wifi_set_wake_on_wlan) (NMPlatform *, int ifindex, NMSettingWirelessWakeOnWLan wowl); guint32 (*mesh_get_channel) (NMPlatform *, int ifindex); gboolean (*mesh_set_channel) (NMPlatform *, int ifindex, guint32 channel); @@ -1245,6 +1247,7 @@ void nm_platform_wifi_set_mode (NMPlatform *self, int ifindex, NM void nm_platform_wifi_set_powersave (NMPlatform *self, int ifindex, guint32 powersave); guint32 nm_platform_wifi_find_frequency (NMPlatform *self, int ifindex, const guint32 *freqs); void nm_platform_wifi_indicate_addressing_running (NMPlatform *self, int ifindex, gboolean running); +gboolean nm_platform_wifi_set_wake_on_wlan (NMPlatform *self, int ifindex, NMSettingWirelessWakeOnWLan wowl); guint32 nm_platform_mesh_get_channel (NMPlatform *self, int ifindex); gboolean nm_platform_mesh_set_channel (NMPlatform *self, int ifindex, guint32 channel); diff --git a/src/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c index 767e23a91d..6c2ff3f579 100644 --- a/src/platform/wifi/wifi-utils-nl80211.c +++ b/src/platform/wifi/wifi-utils-nl80211.c @@ -271,6 +271,47 @@ nla_put_failure: return FALSE; } +static gboolean +wifi_nl80211_set_wake_on_wlan (WifiData *data, NMSettingWirelessWakeOnWLan wowl) +{ + WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + nm_auto_nlmsg struct nl_msg *msg = NULL; + struct nlattr *triggers; + int err; + + if (wowl == NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) + return TRUE; + + msg = nl80211_alloc_msg(nl80211, NL80211_CMD_SET_WOWLAN, 0); + if (!msg) + return FALSE; + + triggers = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); + + if (NM_FLAGS_HAS (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY)) + NLA_PUT_FLAG (msg, NL80211_WOWLAN_TRIG_ANY); + if (NM_FLAGS_HAS (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT)) + NLA_PUT_FLAG (msg, NL80211_WOWLAN_TRIG_DISCONNECT); + if (NM_FLAGS_HAS (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC)) + NLA_PUT_FLAG (msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); + if (NM_FLAGS_HAS (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE)) + NLA_PUT_FLAG (msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE); + if (NM_FLAGS_HAS (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST)) + NLA_PUT_FLAG (msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST); + if (NM_FLAGS_HAS (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE)) + NLA_PUT_FLAG (msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE); + if (NM_FLAGS_HAS (wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE)) + NLA_PUT_FLAG (msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE); + + nla_nest_end(msg, triggers); + + err = nl80211_send_and_recv (nl80211, msg, NULL, NULL); + return err ? FALSE : TRUE; + +nla_put_failure: + return FALSE; +} + /* @divisor: pass what value @xbm should be divided by to get dBm */ static guint32 nl80211_xbm_to_percent (gint32 xbm, guint32 divisor) @@ -846,6 +887,7 @@ wifi_nl80211_init (int ifindex) .get_mode = wifi_nl80211_get_mode, .set_mode = wifi_nl80211_set_mode, .set_powersave = wifi_nl80211_set_powersave, + .set_wake_on_wlan = wifi_nl80211_set_wake_on_wlan, .get_freq = wifi_nl80211_get_freq, .find_freq = wifi_nl80211_find_freq, .get_bssid = wifi_nl80211_get_bssid, diff --git a/src/platform/wifi/wifi-utils-private.h b/src/platform/wifi/wifi-utils-private.h index 59386514d7..627108cbca 100644 --- a/src/platform/wifi/wifi-utils-private.h +++ b/src/platform/wifi/wifi-utils-private.h @@ -34,6 +34,9 @@ typedef struct { /* Set power saving mode on an interface */ gboolean (*set_powersave) (WifiData *data, guint32 powersave); + /* Set WakeOnWLAN mode on an interface */ + gboolean (*set_wake_on_wlan) (WifiData *data, NMSettingWirelessWakeOnWLan wowl); + /* Return current frequency in MHz (really associated BSS frequency) */ guint32 (*get_freq) (WifiData *data); diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c index 8818dc9d94..b3dd92bab0 100644 --- a/src/platform/wifi/wifi-utils.c +++ b/src/platform/wifi/wifi-utils.c @@ -112,6 +112,15 @@ wifi_utils_set_powersave (WifiData *data, guint32 powersave) return data->klass->set_powersave ? data->klass->set_powersave (data, powersave) : TRUE; } +gboolean +wifi_utils_set_wake_on_wlan (WifiData *data, NMSettingWirelessWakeOnWLan wowl) +{ + g_return_val_if_fail (data != NULL, FALSE); + + return data->klass->set_wake_on_wlan ? + data->klass->set_wake_on_wlan (data, wowl) : FALSE; +} + guint32 wifi_utils_get_freq (WifiData *data) { diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h index 8acc35fca1..c69561def4 100644 --- a/src/platform/wifi/wifi-utils.h +++ b/src/platform/wifi/wifi-utils.h @@ -25,6 +25,7 @@ #include #include "nm-dbus-interface.h" +#include "nm-setting-wireless.h" typedef struct WifiData WifiData; @@ -66,6 +67,8 @@ gboolean wifi_utils_get_wowlan (WifiData *data); gboolean wifi_utils_set_powersave (WifiData *data, guint32 powersave); +gboolean wifi_utils_set_wake_on_wlan (WifiData *data, NMSettingWirelessWakeOnWLan wowl); + /* OLPC Mesh-only functions */ guint32 wifi_utils_get_mesh_channel (WifiData *data);