wifi: don't touch by default current powersave setting
authorBeniamino Galvani <bgalvani@redhat.com>
Wed, 10 Feb 2016 15:46:34 +0000 (16:46 +0100)
committerBeniamino Galvani <bgalvani@redhat.com>
Mon, 15 Feb 2016 23:18:06 +0000 (00:18 +0100)
Some drivers (or things outside NM like 'powertop') may turn powersave
on, so don't touch it unless explicitly configured by user.

To achieve this, add new 'default' and 'ignore' options; the former
can be used to fall back to a globally configured setting, while the
latter tells NM not to touch the current setting.

When 'default' is specified, a missing global default configuration is
equivalent to 'ignore'.

It is possible to enable Wi-Fi power saving for all connections by
dropping a file in /etc/NetworkManager/conf.d with the following
content:

 [connection]
 wifi.powersave=3

https://bugzilla.gnome.org/show_bug.cgi?id=760125

clients/cli/settings.c
libnm-core/nm-setting-wireless.c
libnm-core/nm-setting-wireless.h
libnm/libnm.ver
man/NetworkManager.conf.xml.in
src/devices/wifi/nm-device-wifi.c
src/settings/plugins/ifcfg-rh/reader.c
src/settings/plugins/ifcfg-rh/writer.c

index b524e1f..71d3713 100644 (file)
@@ -1854,14 +1854,19 @@ static char *
 nmc_property_wireless_get_powersave (NMSetting *setting, NmcPropertyGetType get_type)
 {
        NMSettingWireless *s_wireless = NM_SETTING_WIRELESS (setting);
-       guint powersave = nm_setting_wireless_get_powersave (s_wireless);
+       NMSettingWirelessPowersave powersave;
+       gs_free char *str = NULL;
+       char *ret;
 
-       if (powersave == 0)
-               return g_strdup (_("no"));
-       else if (powersave == 1)
-               return g_strdup (_("yes"));
-       else
-               return g_strdup_printf (_("yes (%u)"), powersave);
+       powersave = nm_setting_wireless_get_powersave (s_wireless);
+       str = nm_utils_enum_to_str (nm_setting_wireless_powersave_get_type (), powersave);
+
+       if (get_type == NMC_PROPERTY_GET_PARSABLE) {
+               ret = str;
+               str = NULL;
+               return ret;
+       } else
+               return g_strdup_printf ("%s (%u)", str, powersave);
 }
 
 static char *
@@ -4918,20 +4923,33 @@ DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_wireless_remove_mac_address_blacklis
 static gboolean
 nmc_property_wireless_set_powersave (NMSetting *setting, const char *prop, const char *val, GError **error)
 {
-       unsigned long powersave_int;
-       gboolean val_bool = FALSE;
-
-       g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+       NMSettingWirelessPowersave powersave;
+       gs_free const char **options = NULL;
+       gs_free char *options_str = NULL;
+       long int t;
+       gboolean ret;
 
-       if (!nmc_string_to_uint (val, TRUE, 0, G_MAXUINT32, &powersave_int)) {
-               if (!nmc_string_to_bool (val, &val_bool, NULL)) {
-                       g_set_error (error, 1, 0, _("'%s' is not a valid powersave value"), val);
+       if (nmc_string_to_int_base (val, 0, TRUE,
+                                   NM_SETTING_WIRELESS_POWERSAVE_DEFAULT,
+                                   NM_SETTING_WIRELESS_POWERSAVE_LAST,
+                                   &t))
+               powersave = (NMSettingWirelessPowersave) t;
+       else {
+               ret = nm_utils_enum_from_str (nm_setting_wireless_powersave_get_type (),
+                                             val,
+                                             (int *) &powersave,
+                                             NULL);
+               if (!ret) {
+                       options = nm_utils_enum_get_values (nm_setting_wireless_powersave_get_type (),
+                                                           NM_SETTING_WIRELESS_POWERSAVE_DEFAULT,
+                                                           NM_SETTING_WIRELESS_POWERSAVE_LAST);
+                       options_str = g_strjoinv (",", (char **) options);
+                       g_set_error (error, 1, 0, _("invalid option '%s', use one of [%s]"), val, options_str);
                        return FALSE;
                }
-               powersave_int = val_bool ? 1 : 0;
        }
 
-       g_object_set (setting, prop, (guint32) powersave_int, NULL);
+       g_object_set (setting, prop, (guint) powersave, NULL);
        return TRUE;
 }
 
index 3b27893..6b9ad0b 100644 (file)
@@ -1365,25 +1365,26 @@ nm_setting_wireless_class_init (NMSettingWirelessClass *setting_class)
        /**
         * NMSettingWireless:powersave:
         *
-        * If set to %FALSE, Wi-Fi power saving behavior is disabled.  If set to
-        * %TRUE, Wi-Fi power saving behavior is enabled.  All other values are
-        * reserved.  Note that even though only boolean values are allowed, the
-        * property type is an unsigned integer to allow for future expansion.
+        * One of %NM_SETTING_WIRELESS_POWERSAVE_DISABLE (disable Wi-Fi power
+        * saving), %NM_SETTING_WIRELESS_POWERSAVE_ENABLE (enable Wi-Fi power
+        * saving), %NM_SETTING_WIRELESS_POWERSAVE_IGNORE (don't touch currently
+        * configure setting) or %NM_SETTING_WIRELESS_POWERSAVE_DEFAULT (use the
+        * globally configured value). All other values are reserved.
         *
         * Since: 1.2
         **/
        /* ---ifcfg-rh---
         * property: powersave
         * variable: POWERSAVE(+)
-        * default: no
+        * values: default, ignore, enable, disable
         * description: Enables or disables Wi-Fi power saving.
-        * example: POWERSAVE=yes
+        * example: POWERSAVE=enable
         * ---end---
         */
        g_object_class_install_property
                (object_class, PROP_POWERSAVE,
                 g_param_spec_uint (NM_SETTING_WIRELESS_POWERSAVE, "", "",
-                                   0, G_MAXUINT32, 0,
+                                   0, G_MAXUINT32, NM_SETTING_WIRELESS_POWERSAVE_DEFAULT,
                                    G_PARAM_READWRITE |
                                    G_PARAM_STATIC_STRINGS));
 
index a4c0147..606733f 100644 (file)
@@ -80,6 +80,25 @@ G_BEGIN_DECLS
  */
 #define NM_SETTING_WIRELESS_MODE_INFRA  "infrastructure"
 
+/**
+ * NMSettingWirelessPowersave:
+ * @NM_SETTING_WIRELESS_POWERSAVE_DEFAULT: use the default value
+ * @NM_SETTING_WIRELESS_POWERSAVE_IGNORE: don't touch existing setting
+ * @NM_SETTING_WIRELESS_POWERSAVE_DISABLE: disable powersave
+ * @NM_SETTING_WIRELESS_POWERSAVE_ENABLE: enable powersave
+ *
+ * These flags indicate whether wireless powersave must be enabled.
+ **/
+typedef enum {
+       NM_SETTING_WIRELESS_POWERSAVE_DEFAULT       = 0,
+       NM_SETTING_WIRELESS_POWERSAVE_IGNORE        = 1,
+       NM_SETTING_WIRELESS_POWERSAVE_DISABLE       = 2,
+       NM_SETTING_WIRELESS_POWERSAVE_ENABLE        = 3,
+       _NM_SETTING_WIRELESS_POWERSAVE_NUM, /*< skip >*/
+       NM_SETTING_WIRELESS_POWERSAVE_LAST          =  _NM_SETTING_WIRELESS_POWERSAVE_NUM - 1, /*< skip >*/
+} NMSettingWirelessPowersave;
+
+
 struct _NMSettingWireless {
        NMSetting parent;
 };
index 8e01a31..3867c3d 100644 (file)
@@ -1014,6 +1014,7 @@ global:
        nm_setting_wired_wake_on_lan_get_type;
        nm_setting_wireless_get_powersave;
        nm_setting_wireless_get_mac_address_randomization;
+       nm_setting_wireless_powersave_get_type;
        nm_utils_bond_mode_int_to_string;
        nm_utils_bond_mode_string_to_int;
        nm_utils_enum_from_str;
index a2bd36e..75e1d93 100644 (file)
@@ -563,6 +563,11 @@ ipv6.ip6-privacy=0
           <term><varname>wifi.mac-address-randomization</varname></term>
           <listitem><para>If left unspecified, MAC address randomization is disabled.</para></listitem>
         </varlistentry>
+        <varlistentry>
+          <term><varname>wifi.powersave</varname></term>
+          <listitem><para>If left unspecified, the default value
+          "<literal>ignore</literal>" will be used.</para></listitem>
+        </varlistentry>
       </variablelist>
     </para>
     </refsect2>
index 63aa6d2..e464078 100644 (file)
@@ -489,8 +489,6 @@ deactivate (NMDevice *device)
        if (nm_device_get_initial_hw_address (device))
                nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_WIFI);
 
-       nm_platform_wifi_set_powersave (NM_PLATFORM_GET, ifindex, 0);
-
        /* Ensure we're in infrastructure mode after deactivation; some devices
         * (usually older ones) don't scan well in adhoc mode.
         */
@@ -2388,6 +2386,38 @@ ensure_hotspot_frequency (NMDeviceWifi *self,
        nm_ap_set_freq (ap, freq);
 }
 
+static void
+set_powersave (NMDevice *device)
+{
+       NMDeviceWifi *self = NM_DEVICE_WIFI (device);
+       NMSettingWireless *s_wireless;
+       NMSettingWirelessPowersave powersave;
+       gs_free char *value = NULL;
+
+       s_wireless = (NMSettingWireless *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRELESS);
+       g_return_if_fail (s_wireless);
+
+       powersave = nm_setting_wireless_get_powersave (s_wireless);
+       if (powersave == NM_SETTING_WIRELESS_POWERSAVE_DEFAULT) {
+               value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA,
+                                                              "wifi.powersave",
+                                                              device);
+               powersave = _nm_utils_ascii_str_to_int64 (value, 10,
+                                                         NM_SETTING_WIRELESS_POWERSAVE_IGNORE,
+                                                         NM_SETTING_WIRELESS_POWERSAVE_ENABLE,
+                                                         NM_SETTING_WIRELESS_POWERSAVE_IGNORE);
+       }
+
+       _LOGT (LOGD_WIFI, "powersave is set to %u", (unsigned int) powersave);
+
+       if (powersave == NM_SETTING_WIRELESS_POWERSAVE_IGNORE)
+               return;
+
+       nm_platform_wifi_set_powersave (NM_PLATFORM_GET,
+                                       nm_device_get_ifindex (device),
+                                       powersave == NM_SETTING_WIRELESS_POWERSAVE_ENABLE);
+}
+
 static NMActStageReturn
 act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
 {
@@ -2454,11 +2484,8 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
        if ((nm_ap_get_mode (ap) == NM_802_11_MODE_ADHOC) || nm_ap_is_hotspot (ap))
                ensure_hotspot_frequency (self, s_wireless, ap);
 
-       if (nm_ap_get_mode (ap) == NM_802_11_MODE_INFRA) {
-               nm_platform_wifi_set_powersave (NM_PLATFORM_GET,
-                                               nm_device_get_ifindex (device),
-                                               nm_setting_wireless_get_powersave (s_wireless));
-       }
+       if (nm_ap_get_mode (ap) == NM_802_11_MODE_INFRA)
+               set_powersave (device);
 
        /* Build up the supplicant configuration */
        config = build_supplicant_config (self, connection, nm_ap_get_freq (ap), &error);
index 7596ba2..042ad9a 100644 (file)
@@ -3332,6 +3332,7 @@ make_wireless_setting (shvarFile *ifcfg,
        char *value = NULL;
        gint64 chan = 0;
        NMSettingMacRandomization mac_randomization = NM_SETTING_MAC_RANDOMIZATION_NEVER;
+       NMSettingWirelessPowersave powersave = NM_SETTING_WIRELESS_POWERSAVE_DEFAULT;
 
        s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
 
@@ -3509,9 +3510,28 @@ make_wireless_setting (shvarFile *ifcfg,
                      svGetValueBoolean (ifcfg, "SSID_HIDDEN", FALSE),
                      NULL);
 
+       value = svGetValueFull (ifcfg, "POWERSAVE", FALSE);
+       if (value) {
+               if (!strcmp (value, "default"))
+                       powersave = NM_SETTING_WIRELESS_POWERSAVE_DEFAULT;
+               else if (!strcmp (value, "ignore"))
+                       powersave = NM_SETTING_WIRELESS_POWERSAVE_IGNORE;
+               else if (!strcmp (value, "disable") || !strcmp (value, "no"))
+                       powersave = NM_SETTING_WIRELESS_POWERSAVE_DISABLE;
+               else if (!strcmp (value, "enable") || !strcmp (value, "yes"))
+                       powersave = NM_SETTING_WIRELESS_POWERSAVE_ENABLE;
+               else {
+                       g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
+                                    "Invalid POWERSAVE value '%s'", value);
+                       g_free (value);
+                       goto error;
+               }
+               g_free (value);
+       }
+
        g_object_set (s_wireless,
                      NM_SETTING_WIRELESS_POWERSAVE,
-                     svGetValueBoolean (ifcfg, "POWERSAVE", FALSE) ? 1 : 0,
+                     powersave,
                      NULL);
 
        value = svGetValueFull (ifcfg, "MAC_ADDRESS_RANDOMIZATION", FALSE);
@@ -3525,6 +3545,7 @@ make_wireless_setting (shvarFile *ifcfg,
                else {
                        g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION,
                                     "Invalid MAC_ADDRESS_RANDOMIZATION value '%s'", value);
+                       g_free (value);
                        goto error;
                }
                g_free (value);
index 242af0c..a524b7b 100644 (file)
@@ -981,7 +981,22 @@ write_wireless_setting (NMConnection *connection,
        }
 
        svSetValue (ifcfg, "SSID_HIDDEN", nm_setting_wireless_get_hidden (s_wireless) ? "yes" : NULL, TRUE);
-       svSetValue (ifcfg, "POWERSAVE", nm_setting_wireless_get_powersave (s_wireless) ? "yes" : NULL, TRUE);
+
+       switch (nm_setting_wireless_get_powersave (s_wireless)) {
+       case NM_SETTING_WIRELESS_POWERSAVE_IGNORE:
+               svSetValue (ifcfg, "POWERSAVE", "ignore", TRUE);
+               break;
+       case NM_SETTING_WIRELESS_POWERSAVE_DISABLE:
+               svSetValue (ifcfg, "POWERSAVE", "disable", TRUE);
+               break;
+       case NM_SETTING_WIRELESS_POWERSAVE_ENABLE:
+               svSetValue (ifcfg, "POWERSAVE", "enable", TRUE);
+               break;
+       default:
+       case NM_SETTING_WIRELESS_POWERSAVE_DEFAULT:
+               svSetValue (ifcfg, "POWERSAVE", NULL, TRUE);
+               break;
+       }
 
        svSetValue (ifcfg, "MAC_ADDRESS_RANDOMIZATION", NULL, TRUE);
        switch (nm_setting_wireless_get_mac_address_randomization (s_wireless)) {