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 - 0.8.1-10 +- core: preserve WiFi Enabled state across reboot and suspend/resume + * Fri Oct 15 2010 Dan Williams - 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 +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;