399 lines
15 KiB
Diff
399 lines
15 KiB
Diff
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;
|