[NetworkManager] Preserve Wifi Enabled state across reboot and suspend/resume
Daniel Williams
dcbw at fedoraproject.org
Tue Nov 2 01:28:14 UTC 2010
commit 86ef1e5f8fdc3ce99889489f25faf86572e58d75
Author: Dan Williams <dcbw at redhat.com>
Date: Mon Nov 1 20:26:49 2010 -0500
Preserve Wifi Enabled state across reboot and suspend/resume
NetworkManager.spec | 14 ++-
nm-preserve-wifi-state.patch | 398 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 410 insertions(+), 2 deletions(-)
---
diff --git a/NetworkManager.spec b/NetworkManager.spec
index b34e57e..fa1d88f 100644
--- a/NetworkManager.spec
+++ b/NetworkManager.spec
@@ -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 at redhat.com> - 0.8.1-10
+- core: preserve WiFi Enabled state across reboot and suspend/resume
+
* Fri Oct 15 2010 Dan Williams <dcbw at redhat.com> - 0.8.1-9
- core: fix suspend/resume regression (rh #638640)
- core: fix issue causing some nmcli requests to be ignored
diff --git a/nm-preserve-wifi-state.patch b/nm-preserve-wifi-state.patch
new file mode 100644
index 0000000..3b2eaca
--- /dev/null
+++ b/nm-preserve-wifi-state.patch
@@ -0,0 +1,398 @@
+commit e86ef05d84749c5a15d7bcf30f78056ca205489c
+Author: Dan Williams <dcbw at 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;
More information about the scm-commits
mailing list