Preserve Wifi Enabled state across reboot and suspend/resume

This commit is contained in:
Dan Williams 2010-11-01 20:26:49 -05:00
parent 3e67131815
commit 86ef1e5f8f
2 changed files with 410 additions and 2 deletions

View File

@ -12,7 +12,7 @@
%define realversion 0.8.1
%define use_systemd 0
%if 0%{?fedora} >= 14
%if 0%{?fedora} >= 15
%define use_systemd 1
%endif
@ -20,7 +20,7 @@ Name: NetworkManager
Summary: Network connection manager and user applications
Epoch: 1
Version: 0.8.1
Release: 9%{snapshot}%{?dist}
Release: 10%{snapshot}%{?dist}
Group: System Environment/Base
License: GPLv2+
URL: http://www.gnome.org/projects/NetworkManager/
@ -36,6 +36,7 @@ Patch5: nm-preserve-custom-hostnames.patch
Patch6: nm-prevent-hostname-dup.patch
Patch7: nm-sleep-wake-no-auth.patch
Patch8: nm-libnm-glib-prop-set-delay.patch
Patch9: nm-preserve-wifi-state.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Requires(post): chkconfig
@ -171,6 +172,7 @@ tar -xjf %{SOURCE1}
%patch6 -p1 -b .prevent-hostname-dup
%patch7 -p1 -b .sleep-wake
%patch8 -p1 -b .prop-set-delay
%patch9 -p1 -b .wifi-state-preserve
%build
@ -251,6 +253,11 @@ echo 'NotShowIn=KDE;' >>$RPM_BUILD_ROOT%{_sysconfdir}/xdg/autostart/nm-applet.de
# validate the autostart .desktop file
desktop-file-validate $RPM_BUILD_ROOT%{_sysconfdir}/xdg/autostart/nm-applet.desktop
# remove systemd stuff if necessary
%if !%{use_systemd}
%{__rm} -f $RPM_BUILD_ROOT/lib/systemd/system/NetworkManager.service
%{__rm} -f $RPM_BUILD_ROOT%{_datadir}/dbus-1/system-services/org.freedesktop.NetworkManager.service
%endif
%clean
%{__rm} -rf $RPM_BUILD_ROOT
@ -424,6 +431,9 @@ fi
%{_datadir}/gtk-doc/html/libnm-util/*
%changelog
* Mon Nov 1 2010 Dan Williams <dcbw@redhat.com> - 0.8.1-10
- core: preserve WiFi Enabled state across reboot and suspend/resume
* Fri Oct 15 2010 Dan Williams <dcbw@redhat.com> - 0.8.1-9
- core: fix suspend/resume regression (rh #638640)
- core: fix issue causing some nmcli requests to be ignored

View File

@ -0,0 +1,398 @@
commit e86ef05d84749c5a15d7bcf30f78056ca205489c
Author: Dan Williams <dcbw@redhat.com>
Date: Wed Sep 1 17:08:10 2010 -0500
wifi: ensure Enabled state is preserved regardless of rfkill (bgo #624479)
Previously the "Enable Wireless" state was somewhat tied to rfkill state,
in that when NM started up, rfkill state would take precedence over what
was listed in the state file, and if you rmmodded your wifi driver and
then modprobed it again after disabling wifi from the menu, wifi would
magically become re-enabled becuase rfkill state changed.
Fix that by creating a third wifi/wwan enable state that tracks the
actual user preference instead of just the rfkill state so that when
the user disables wifi it stays disabled, regardless of what happens
with rfkill.
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 1e9c3c6..abe30bf 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -187,7 +187,8 @@ struct PendingActivation {
};
typedef struct {
- gboolean enabled;
+ gboolean user_enabled;
+ gboolean sw_enabled;
gboolean hw_enabled;
RfKillType rtype;
const char *desc;
@@ -1584,50 +1585,40 @@ write_value_to_state_file (const char *filename,
return ret;
}
+static gboolean
+radio_enabled_for_rstate (RadioState *rstate)
+{
+ return rstate->user_enabled && rstate->sw_enabled && rstate->hw_enabled;
+}
+
+static gboolean
+radio_enabled_for_type (NMManager *self, RfKillType rtype)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+
+ return radio_enabled_for_rstate (&priv->radio_states[rtype]);
+}
+
static void
-manager_set_radio_enabled (NMManager *manager,
- RadioState *rstate,
- gboolean enabled)
+manager_update_radio_enabled (NMManager *self, RadioState *rstate)
{
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GSList *iter;
- GError *error = NULL;
/* Do nothing for radio types not yet implemented */
if (!rstate->prop)
return;
- if (rstate->enabled == enabled)
- return;
-
- /* Can't set wireless enabled if it's disabled in hardware */
- if (!rstate->hw_enabled && enabled)
- return;
-
- rstate->enabled = enabled;
-
- g_object_notify (G_OBJECT (manager), rstate->prop);
-
- /* Update enabled key in state file */
- if (priv->state_file) {
- if (!write_value_to_state_file (priv->state_file,
- "main", rstate->key,
- G_TYPE_BOOLEAN, (gpointer) &enabled,
- &error)) {
- nm_log_warn (LOGD_CORE, "writing to state file %s failed: (%d) %s.",
- priv->state_file,
- error ? error->code : -1,
- (error && error->message) ? error->message : "unknown");
- }
- }
+ g_object_notify (G_OBJECT (self), rstate->prop);
/* Don't touch devices if asleep/networking disabled */
- if (manager_sleeping (manager))
+ if (manager_sleeping (self))
return;
/* enable/disable wireless devices as required */
for (iter = priv->devices; iter; iter = iter->next) {
RfKillType devtype = RFKILL_TYPE_UNKNOWN;
+ gboolean enabled = radio_enabled_for_rstate (rstate);
g_object_get (G_OBJECT (iter->data), NM_DEVICE_INTERFACE_RFKILL_TYPE, &devtype, NULL);
if (devtype == rstate->rtype) {
@@ -1750,6 +1741,21 @@ nm_manager_get_modem_enabled_state (NMManager *self)
}
static void
+update_rstate_from_rfkill (RadioState *rstate, RfKillState rfkill)
+{
+ if (rfkill == RFKILL_UNBLOCKED) {
+ rstate->sw_enabled = TRUE;
+ rstate->hw_enabled = TRUE;
+ } else if (rfkill == RFKILL_SOFT_BLOCKED) {
+ rstate->sw_enabled = FALSE;
+ rstate->hw_enabled = TRUE;
+ } else if (rfkill == RFKILL_HARD_BLOCKED) {
+ rstate->sw_enabled = FALSE;
+ rstate->hw_enabled = FALSE;
+ }
+}
+
+static void
manager_rfkill_update_one_type (NMManager *self,
RadioState *rstate,
RfKillType rtype)
@@ -1758,7 +1764,12 @@ manager_rfkill_update_one_type (NMManager *self,
RfKillState udev_state = RFKILL_UNBLOCKED;
RfKillState other_state = RFKILL_UNBLOCKED;
RfKillState composite;
- gboolean new_e = TRUE, new_he = TRUE;
+ gboolean old_enabled, new_enabled, old_rfkilled, new_rfkilled;
+ gboolean old_hwe;
+
+ old_enabled = radio_enabled_for_rstate (rstate);
+ old_rfkilled = rstate->hw_enabled && rstate->sw_enabled;
+ old_hwe = rstate->hw_enabled;
udev_state = nm_udev_manager_get_rfkill_state (priv->udev_mgr, rtype);
@@ -1773,38 +1784,31 @@ manager_rfkill_update_one_type (NMManager *self,
else
composite = RFKILL_UNBLOCKED;
- switch (composite) {
- case RFKILL_UNBLOCKED:
- new_e = TRUE;
- new_he = TRUE;
- break;
- case RFKILL_SOFT_BLOCKED:
- new_e = FALSE;
- new_he = TRUE;
- break;
- case RFKILL_HARD_BLOCKED:
- new_e = FALSE;
- new_he = FALSE;
- break;
- default:
- break;
- }
+ update_rstate_from_rfkill (rstate, composite);
if (rstate->desc) {
- nm_log_dbg (LOGD_RFKILL, "%s hw-enabled %d enabled %d",
- rstate->desc, new_he, new_e);
+ nm_log_dbg (LOGD_RFKILL, "%s hw-enabled %d sw-enabled %d",
+ rstate->desc, rstate->hw_enabled, rstate->sw_enabled);
}
- if (new_he != rstate->hw_enabled) {
+ /* Log new killswitch state */
+ new_rfkilled = rstate->hw_enabled && rstate->sw_enabled;
+ if (old_rfkilled != new_rfkilled) {
nm_log_info (LOGD_RFKILL, "%s now %s by radio killswitch",
rstate->desc,
- (new_e && new_he) ? "enabled" : "disabled");
+ new_rfkilled ? "enabled" : "disabled");
+ }
- rstate->hw_enabled = new_he;
+ /* Send out property changed signal for HW enabled */
+ if (rstate->hw_enabled != old_hwe) {
if (rstate->hw_prop)
g_object_notify (G_OBJECT (self), rstate->hw_prop);
}
- manager_set_radio_enabled (self, rstate, new_e);
+
+ /* And finally update the actual device radio state itself */
+ new_enabled = radio_enabled_for_rstate (rstate);
+ if (new_enabled != old_enabled)
+ manager_update_radio_enabled (self, rstate);
}
static void
@@ -2014,7 +2018,7 @@ add_device (NMManager *self, NMDevice *device)
NMConnection *existing = NULL;
GHashTableIter iter;
gpointer value;
- gboolean managed = FALSE;
+ gboolean managed = FALSE, enabled = FALSE;
iface = nm_device_get_ip_iface (device);
g_assert (iface);
@@ -2053,14 +2057,15 @@ add_device (NMManager *self, NMDevice *device)
* then set this device's rfkill state based on the global state.
*/
nm_manager_rfkill_update (self, RFKILL_TYPE_WLAN);
- nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device),
- priv->radio_states[RFKILL_TYPE_WLAN].enabled);
+ enabled = radio_enabled_for_type (self, RFKILL_TYPE_WLAN);
+ nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device), enabled);
} else if (NM_IS_DEVICE_MODEM (device)) {
g_signal_connect (device, NM_DEVICE_MODEM_ENABLE_CHANGED,
G_CALLBACK (manager_modem_enabled_changed),
self);
nm_manager_rfkill_update (self, RFKILL_TYPE_WWAN);
+ enabled = radio_enabled_for_type (self, RFKILL_TYPE_WWAN);
/* Until we start respecting WWAN rfkill switches the modem itself
* is the source of the enabled/disabled state, so the manager shouldn't
* touch it here.
@@ -3305,13 +3310,13 @@ do_sleep_wake (NMManager *self)
*/
for (i = 0; i < RFKILL_TYPE_MAX; i++) {
RadioState *rstate = &priv->radio_states[i];
- gboolean enabled = (rstate->hw_enabled && rstate->enabled);
+ gboolean enabled = radio_enabled_for_rstate (rstate);
RfKillType devtype = RFKILL_TYPE_UNKNOWN;
if (rstate->desc) {
- nm_log_dbg (LOGD_RFKILL, "%s %s devices (hw_enabled %d, enabled %d)",
+ nm_log_dbg (LOGD_RFKILL, "%s %s devices (hw_enabled %d, sw_enabled %d, user_enabled %d)",
enabled ? "enabling" : "disabling",
- rstate->desc, rstate->hw_enabled, rstate->enabled);
+ rstate->desc, rstate->hw_enabled, rstate->sw_enabled, rstate->user_enabled);
}
g_object_get (G_OBJECT (device), NM_DEVICE_INTERFACE_RFKILL_TYPE, &devtype, NULL);
@@ -3879,34 +3884,21 @@ nm_manager_start (NMManager *self)
/* Set initial radio enabled/disabled state */
for (i = 0; i < RFKILL_TYPE_MAX; i++) {
RadioState *rstate = &priv->radio_states[i];
- gboolean enabled = TRUE, hw_enabled = TRUE;
+ RfKillState udev_state;
if (!rstate->desc)
continue;
- switch (nm_udev_manager_get_rfkill_state (priv->udev_mgr, i)) {
- case RFKILL_UNBLOCKED:
- enabled = TRUE;
- hw_enabled = TRUE;
- break;
- case RFKILL_SOFT_BLOCKED:
- enabled = FALSE;
- hw_enabled = TRUE;
- break;
- case RFKILL_HARD_BLOCKED:
- enabled = FALSE;
- hw_enabled = FALSE;
- break;
- default:
- break;
- }
+ udev_state = nm_udev_manager_get_rfkill_state (priv->udev_mgr, i);
+ update_rstate_from_rfkill (rstate, udev_state);
- rstate->hw_enabled = hw_enabled;
- nm_log_info (LOGD_RFKILL, "%s %s by radio killswitch; %s by state file",
- rstate->desc,
- (rstate->hw_enabled && enabled) ? "enabled" : "disabled",
- (rstate->enabled) ? "enabled" : "disabled");
- manager_set_radio_enabled (self, rstate, rstate->enabled && enabled);
+ if (rstate->desc) {
+ nm_log_info (LOGD_RFKILL, "%s %s by radio killswitch; %s by state file",
+ rstate->desc,
+ (rstate->hw_enabled && rstate->sw_enabled) ? "enabled" : "disabled",
+ rstate->user_enabled ? "enabled" : "disabled");
+ }
+ manager_update_radio_enabled (self, rstate);
}
/* Log overall networking status - enabled/disabled */
@@ -4188,8 +4180,8 @@ nm_manager_get (const char *config_file,
priv->net_enabled = initial_net_enabled;
- priv->radio_states[RFKILL_TYPE_WLAN].enabled = initial_wifi_enabled;
- priv->radio_states[RFKILL_TYPE_WWAN].enabled = initial_wwan_enabled;
+ priv->radio_states[RFKILL_TYPE_WLAN].user_enabled = initial_wifi_enabled;
+ priv->radio_states[RFKILL_TYPE_WWAN].user_enabled = initial_wwan_enabled;
g_signal_connect (priv->sys_settings, "notify::" NM_SYSCONFIG_SETTINGS_UNMANAGED_SPECS,
G_CALLBACK (system_unmanaged_devices_changed_cb), singleton);
@@ -4335,6 +4327,42 @@ dispose (GObject *object)
}
static void
+manager_radio_user_toggled (NMManager *self,
+ RadioState *rstate,
+ gboolean enabled)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ GError *error = NULL;
+ gboolean old_enabled, new_enabled;
+
+ if (rstate->desc) {
+ nm_log_dbg (LOGD_RFKILL, "(%s): setting radio %s by user",
+ rstate->desc,
+ enabled ? "enabled" : "disabled");
+ }
+
+ /* Update enabled key in state file */
+ if (priv->state_file) {
+ if (!write_value_to_state_file (priv->state_file,
+ "main", rstate->key,
+ G_TYPE_BOOLEAN, (gpointer) &enabled,
+ &error)) {
+ nm_log_warn (LOGD_CORE, "writing to state file %s failed: (%d) %s.",
+ priv->state_file,
+ error ? error->code : -1,
+ (error && error->message) ? error->message : "unknown");
+ g_clear_error (&error);
+ }
+ }
+
+ old_enabled = radio_enabled_for_rstate (rstate);
+ rstate->user_enabled = enabled;
+ new_enabled = radio_enabled_for_rstate (rstate);
+ if (new_enabled != old_enabled)
+ manager_update_radio_enabled (self, rstate);
+}
+
+static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
@@ -4347,14 +4375,14 @@ set_property (GObject *object, guint prop_id,
priv->net_enabled = g_value_get_boolean (value);
break;
case PROP_WIRELESS_ENABLED:
- manager_set_radio_enabled (NM_MANAGER (object),
- &priv->radio_states[RFKILL_TYPE_WLAN],
- g_value_get_boolean (value));
+ manager_radio_user_toggled (NM_MANAGER (object),
+ &priv->radio_states[RFKILL_TYPE_WLAN],
+ g_value_get_boolean (value));
break;
case PROP_WWAN_ENABLED:
- manager_set_radio_enabled (NM_MANAGER (object),
- &priv->radio_states[RFKILL_TYPE_WWAN],
- g_value_get_boolean (value));
+ manager_radio_user_toggled (NM_MANAGER (object),
+ &priv->radio_states[RFKILL_TYPE_WWAN],
+ g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -4378,13 +4406,13 @@ get_property (GObject *object, guint prop_id,
g_value_set_boolean (value, priv->net_enabled);
break;
case PROP_WIRELESS_ENABLED:
- g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WLAN].enabled);
+ g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WLAN));
break;
case PROP_WIRELESS_HARDWARE_ENABLED:
g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WLAN].hw_enabled);
break;
case PROP_WWAN_ENABLED:
- g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WWAN].enabled);
+ g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WWAN));
break;
case PROP_WWAN_HARDWARE_ENABLED:
g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WWAN].hw_enabled);
@@ -4416,7 +4444,7 @@ nm_manager_init (NMManager *manager)
/* Initialize rfkill structures and states */
memset (priv->radio_states, 0, sizeof (priv->radio_states));
- priv->radio_states[RFKILL_TYPE_WLAN].enabled = TRUE;
+ priv->radio_states[RFKILL_TYPE_WLAN].user_enabled = TRUE;
priv->radio_states[RFKILL_TYPE_WLAN].key = "WirelessEnabled";
priv->radio_states[RFKILL_TYPE_WLAN].prop = NM_MANAGER_WIRELESS_ENABLED;
priv->radio_states[RFKILL_TYPE_WLAN].hw_prop = NM_MANAGER_WIRELESS_HARDWARE_ENABLED;
@@ -4424,7 +4452,7 @@ nm_manager_init (NMManager *manager)
priv->radio_states[RFKILL_TYPE_WLAN].other_enabled_func = nm_manager_get_ipw_rfkill_state;
priv->radio_states[RFKILL_TYPE_WLAN].rtype = RFKILL_TYPE_WLAN;
- priv->radio_states[RFKILL_TYPE_WWAN].enabled = TRUE;
+ priv->radio_states[RFKILL_TYPE_WWAN].user_enabled = TRUE;
priv->radio_states[RFKILL_TYPE_WWAN].key = "WWANEnabled";
priv->radio_states[RFKILL_TYPE_WWAN].prop = NM_MANAGER_WWAN_ENABLED;
priv->radio_states[RFKILL_TYPE_WWAN].hw_prop = NM_MANAGER_WWAN_HARDWARE_ENABLED;
@@ -4432,7 +4460,7 @@ nm_manager_init (NMManager *manager)
priv->radio_states[RFKILL_TYPE_WWAN].other_enabled_func = nm_manager_get_modem_enabled_state;
priv->radio_states[RFKILL_TYPE_WWAN].rtype = RFKILL_TYPE_WWAN;
- priv->radio_states[RFKILL_TYPE_WIMAX].enabled = TRUE;
+ priv->radio_states[RFKILL_TYPE_WIMAX].user_enabled = TRUE;
priv->radio_states[RFKILL_TYPE_WIMAX].key = "WiMAXEnabled";
priv->radio_states[RFKILL_TYPE_WIMAX].prop = NULL;
priv->radio_states[RFKILL_TYPE_WIMAX].hw_prop = NULL;