1
From d0a1b23ea1803fc46567af4bb38d0078c873c357 Mon Sep 17 00:00:00 2001
2
From: Dan Williams <dcbw@redhat.com>
3
Date: Thu, 14 Apr 2011 02:58:25 +0000
4
Subject: wwan: fix enabled state detection (bgo #647216)
6
Since the user state stuff got committed in 0.8.2, WWAN enable
7
state has been somewhat broken. The problem is that we want two
8
things: (1) that the current modem enabled state is reflected
9
in the WwanEnabled property, and (2) that enabled state should not
10
affect the user's ability to enable the modem via the UI.
12
The code did not properly separate these two. For all automatic
13
decisions and properties (ie the WwanEnabled property, setting the
14
initial enabled state on startup or hotplug, etc) the ModemManager
15
enabled state should be respected. But the user should be able
16
to override that state by turn WWAN on.
18
This calls for a fourth enabled check that modems have, the 'daemon'
19
state, distinct from the hardware and software kernel rfkill states
20
and from the user's chosen enabled/disabled state. Add that new
23
The actual problem was in manager_radio_user_toggled() where after
24
updating the user enabled state, new_enabled still equaled
25
old_enabled, because the kernel rfkill state was a combination of
26
both the kernel rfkill state *and* the ModemManager enabled state,
27
so the manager_update_radio_enabled() call would never happen and
28
the modem would never become enabled as a result of a user request.
30
diff --git a/src/nm-manager.c b/src/nm-manager.c
31
index 093585e..b0b12f8 100644
32
--- a/src/nm-manager.c
33
+++ b/src/nm-manager.c
34
@@ -188,6 +188,7 @@ struct PendingActivation {
37
gboolean user_enabled;
38
+ gboolean daemon_enabled;
42
@@ -196,6 +197,7 @@ typedef struct {
45
RfKillState (*other_enabled_func) (NMManager *);
46
+ RfKillState (*daemon_enabled_func) (NMManager *);
50
@@ -1648,21 +1650,28 @@ write_value_to_state_file (const char *filename,
54
-radio_enabled_for_rstate (RadioState *rstate)
55
+radio_enabled_for_rstate (RadioState *rstate, gboolean check_daemon_enabled)
57
- return rstate->user_enabled && rstate->sw_enabled && rstate->hw_enabled;
60
+ enabled = rstate->user_enabled && rstate->sw_enabled && rstate->hw_enabled;
61
+ if (rstate->daemon_enabled_func && check_daemon_enabled)
62
+ enabled &= rstate->daemon_enabled;
67
-radio_enabled_for_type (NMManager *self, RfKillType rtype)
68
+radio_enabled_for_type (NMManager *self, RfKillType rtype, gboolean check_daemon_enabled)
70
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
72
- return radio_enabled_for_rstate (&priv->radio_states[rtype]);
73
+ return radio_enabled_for_rstate (&priv->radio_states[rtype], check_daemon_enabled);
77
-manager_update_radio_enabled (NMManager *self, RadioState *rstate)
78
+manager_update_radio_enabled (NMManager *self,
82
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
84
@@ -1680,7 +1689,6 @@ manager_update_radio_enabled (NMManager *self, RadioState *rstate)
85
/* enable/disable wireless devices as required */
86
for (iter = priv->devices; iter; iter = iter->next) {
87
RfKillType devtype = RFKILL_TYPE_UNKNOWN;
88
- gboolean enabled = radio_enabled_for_rstate (rstate);
90
g_object_get (G_OBJECT (iter->data), NM_DEVICE_INTERFACE_RFKILL_TYPE, &devtype, NULL);
91
if (devtype == rstate->rtype) {
92
@@ -1827,9 +1835,9 @@ manager_rfkill_update_one_type (NMManager *self,
93
RfKillState other_state = RFKILL_UNBLOCKED;
94
RfKillState composite;
95
gboolean old_enabled, new_enabled, old_rfkilled, new_rfkilled;
97
+ gboolean old_hwe, old_daemon_enabled = FALSE;
99
- old_enabled = radio_enabled_for_rstate (rstate);
100
+ old_enabled = radio_enabled_for_rstate (rstate, TRUE);
101
old_rfkilled = rstate->hw_enabled && rstate->sw_enabled;
102
old_hwe = rstate->hw_enabled;
104
@@ -1848,9 +1856,26 @@ manager_rfkill_update_one_type (NMManager *self,
106
update_rstate_from_rfkill (rstate, composite);
108
+ /* If the device has a management daemon that can affect enabled state, check that now */
109
+ if (rstate->daemon_enabled_func) {
110
+ old_daemon_enabled = rstate->daemon_enabled;
111
+ rstate->daemon_enabled = (rstate->daemon_enabled_func (self) == RFKILL_UNBLOCKED);
112
+ if (old_daemon_enabled != rstate->daemon_enabled) {
113
+ nm_log_info (LOGD_RFKILL, "%s now %s by management service",
115
+ rstate->daemon_enabled ? "enabled" : "disabled");
119
+ /* Print out all states affecting device enablement */
121
- nm_log_dbg (LOGD_RFKILL, "%s hw-enabled %d sw-enabled %d",
122
- rstate->desc, rstate->hw_enabled, rstate->sw_enabled);
123
+ if (rstate->daemon_enabled_func) {
124
+ nm_log_dbg (LOGD_RFKILL, "%s hw-enabled %d sw-enabled %d daemon-enabled %d",
125
+ rstate->desc, rstate->hw_enabled, rstate->sw_enabled, rstate->daemon_enabled);
127
+ nm_log_dbg (LOGD_RFKILL, "%s hw-enabled %d sw-enabled %d",
128
+ rstate->desc, rstate->hw_enabled, rstate->sw_enabled);
132
/* Log new killswitch state */
133
@@ -1867,10 +1892,14 @@ manager_rfkill_update_one_type (NMManager *self,
134
g_object_notify (G_OBJECT (self), rstate->hw_prop);
137
- /* And finally update the actual device radio state itself */
138
- new_enabled = radio_enabled_for_rstate (rstate);
139
+ /* And finally update the actual device radio state itself; respect the
140
+ * daemon state here because this is never called from user-triggered
141
+ * radio changes and we only want to ignore the daemon enabled state when
142
+ * handling user radio change requests.
144
+ new_enabled = radio_enabled_for_rstate (rstate, TRUE);
145
if (new_enabled != old_enabled)
146
- manager_update_radio_enabled (self, rstate);
147
+ manager_update_radio_enabled (self, rstate, new_enabled);
151
@@ -1879,14 +1908,13 @@ nm_manager_rfkill_update (NMManager *self, RfKillType rtype)
152
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
155
- if (rtype != RFKILL_TYPE_UNKNOWN) {
156
+ if (rtype != RFKILL_TYPE_UNKNOWN)
157
manager_rfkill_update_one_type (self, &priv->radio_states[rtype], rtype);
160
+ /* Otherwise sync all radio types */
161
+ for (i = 0; i < RFKILL_TYPE_MAX; i++)
162
+ manager_rfkill_update_one_type (self, &priv->radio_states[i], i);
165
- /* Otherwise sync all radio types */
166
- for (i = 0; i < RFKILL_TYPE_MAX; i++)
167
- manager_rfkill_update_one_type (self, &priv->radio_states[i], i);
171
@@ -2081,6 +2109,7 @@ add_device (NMManager *self, NMDevice *device)
174
gboolean managed = FALSE, enabled = FALSE;
175
+ RfKillType rtype = RFKILL_TYPE_UNKNOWN;
177
iface = nm_device_get_ip_iface (device);
179
@@ -2114,26 +2143,21 @@ add_device (NMManager *self, NMDevice *device)
180
g_signal_connect (device, "notify::" NM_DEVICE_WIFI_IPW_RFKILL_STATE,
181
G_CALLBACK (manager_ipw_rfkill_state_changed),
184
- /* Update global rfkill state with this device's rfkill state, and
185
- * then set this device's rfkill state based on the global state.
187
- nm_manager_rfkill_update (self, RFKILL_TYPE_WLAN);
188
- enabled = radio_enabled_for_type (self, RFKILL_TYPE_WLAN);
189
- nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device), enabled);
190
+ rtype = RFKILL_TYPE_WLAN;
191
} else if (NM_IS_DEVICE_MODEM (device)) {
192
g_signal_connect (device, NM_DEVICE_MODEM_ENABLE_CHANGED,
193
G_CALLBACK (manager_modem_enabled_changed),
195
+ rtype = RFKILL_TYPE_WWAN;
198
- nm_manager_rfkill_update (self, RFKILL_TYPE_WWAN);
199
- enabled = radio_enabled_for_type (self, RFKILL_TYPE_WWAN);
200
- /* Until we start respecting WWAN rfkill switches the modem itself
201
- * is the source of the enabled/disabled state, so the manager shouldn't
203
- nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device),
204
- priv->radio_states[RFKILL_TYPE_WWAN].enabled);
206
+ if (rtype != RFKILL_TYPE_UNKNOWN) {
207
+ /* Update global rfkill state with this device's rfkill state, and
208
+ * then set this device's rfkill state based on the global state.
210
+ nm_manager_rfkill_update (self, rtype);
211
+ enabled = radio_enabled_for_type (self, rtype, TRUE);
212
+ nm_device_interface_set_enabled (NM_DEVICE_INTERFACE (device), enabled);
215
type_desc = nm_device_get_type_desc (device);
216
@@ -3372,7 +3396,7 @@ do_sleep_wake (NMManager *self)
218
for (i = 0; i < RFKILL_TYPE_MAX; i++) {
219
RadioState *rstate = &priv->radio_states[i];
220
- gboolean enabled = radio_enabled_for_rstate (rstate);
221
+ gboolean enabled = radio_enabled_for_rstate (rstate, TRUE);
222
RfKillType devtype = RFKILL_TYPE_UNKNOWN;
225
@@ -3986,6 +4010,7 @@ nm_manager_start (NMManager *self)
226
for (i = 0; i < RFKILL_TYPE_MAX; i++) {
227
RadioState *rstate = &priv->radio_states[i];
228
RfKillState udev_state;
233
@@ -3999,7 +4024,8 @@ nm_manager_start (NMManager *self)
234
(rstate->hw_enabled && rstate->sw_enabled) ? "enabled" : "disabled",
235
rstate->user_enabled ? "enabled" : "disabled");
237
- manager_update_radio_enabled (self, rstate);
238
+ enabled = radio_enabled_for_rstate (rstate, TRUE);
239
+ manager_update_radio_enabled (self, rstate, enabled);
242
/* Log overall networking status - enabled/disabled */
243
@@ -4475,11 +4501,20 @@ manager_radio_user_toggled (NMManager *self,
247
- old_enabled = radio_enabled_for_rstate (rstate);
248
+ /* When the user toggles the radio, their request should override any
249
+ * daemon (like ModemManager) enabled state that can be changed. For WWAN
250
+ * for example, we want the WwanEnabled property to reflect the daemon state
251
+ * too so that users can toggle the modem powered, but we don't want that
252
+ * daemon state to affect whether or not the user *can* turn it on, which is
253
+ * what the kernel rfkill state does. So we ignore daemon enabled state
254
+ * when determining what the new state should be since it shouldn't block
255
+ * the user's request.
257
+ old_enabled = radio_enabled_for_rstate (rstate, TRUE);
258
rstate->user_enabled = enabled;
259
- new_enabled = radio_enabled_for_rstate (rstate);
260
+ new_enabled = radio_enabled_for_rstate (rstate, FALSE);
261
if (new_enabled != old_enabled)
262
- manager_update_radio_enabled (self, rstate);
263
+ manager_update_radio_enabled (self, rstate, new_enabled);
267
@@ -4529,13 +4564,13 @@ get_property (GObject *object, guint prop_id,
268
g_value_set_boolean (value, priv->net_enabled);
270
case PROP_WIRELESS_ENABLED:
271
- g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WLAN));
272
+ g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WLAN, TRUE));
274
case PROP_WIRELESS_HARDWARE_ENABLED:
275
g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WLAN].hw_enabled);
277
case PROP_WWAN_ENABLED:
278
- g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WWAN));
279
+ g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WWAN, TRUE));
281
case PROP_WWAN_HARDWARE_ENABLED:
282
g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WWAN].hw_enabled);
283
@@ -4602,7 +4637,7 @@ nm_manager_init (NMManager *manager)
284
priv->radio_states[RFKILL_TYPE_WWAN].prop = NM_MANAGER_WWAN_ENABLED;
285
priv->radio_states[RFKILL_TYPE_WWAN].hw_prop = NM_MANAGER_WWAN_HARDWARE_ENABLED;
286
priv->radio_states[RFKILL_TYPE_WWAN].desc = "WWAN";
287
- priv->radio_states[RFKILL_TYPE_WWAN].other_enabled_func = nm_manager_get_modem_enabled_state;
288
+ priv->radio_states[RFKILL_TYPE_WWAN].daemon_enabled_func = nm_manager_get_modem_enabled_state;
289
priv->radio_states[RFKILL_TYPE_WWAN].rtype = RFKILL_TYPE_WWAN;
291
priv->radio_states[RFKILL_TYPE_WIMAX].user_enabled = TRUE;