[PATCH] core: improving handling of rfkill



This commit improves the handling of rfkill.

- The original two passes check gathers the states of platform
  and non-platform switches in two separate loops. Now we gather
  the both states in one loop and determine the final states later.

- A new rule is used to determine the states of switches.

  if (platform_state == UNBLOCKED)
          choose non_platform_state;
  else
          choose platform_state;

  The state is UNBLOCKED if and only if both the platform and
  non-platform switches are unblocked, so the ambiguous state in
  bgo#655773 will not happen.
  See: https://bugzilla.gnome.org/show_bug.cgi?id=655773
---
 src/nm-udev-manager.c |   73 ++++++++++++++++---------------------------------
 1 files changed, 24 insertions(+), 49 deletions(-)

diff --git a/src/nm-udev-manager.c b/src/nm-udev-manager.c
index 72501c2..73c1f44 100644
--- a/src/nm-udev-manager.c
+++ b/src/nm-udev-manager.c
@@ -189,84 +189,59 @@ sysfs_state_to_nm_state (gint sysfs_state)
 	return RFKILL_UNBLOCKED;
 }
 
+static RfKillState
+aggregate_states (RfKillState platform, RfKillState non_platform)
+{
+	if (platform == RFKILL_UNBLOCKED)
+		return non_platform;
+	else
+		return platform;
+}
+
 static void
 recheck_killswitches (NMUdevManager *self)
 {
 	NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
 	GSList *iter;
 	RfKillState poll_states[RFKILL_TYPE_MAX];
+	RfKillState platform_states[RFKILL_TYPE_MAX];
 	gboolean platform_checked[RFKILL_TYPE_MAX];
 	int i;
 
 	/* Default state is unblocked */
 	for (i = 0; i < RFKILL_TYPE_MAX; i++) {
 		poll_states[i] = RFKILL_UNBLOCKED;
+		platform_states[i] = RFKILL_UNBLOCKED;
 		platform_checked[i] = FALSE;
 	}
 
-	/* Perform two passes here; the first pass is for non-platform switches,
-	 * which typically if hardkilled cannot be changed except by a physical
-	 * hardware switch.  The second pass checks platform killswitches, which
-	 * take precedence over device killswitches, because typically platform
-	 * killswitches control device killswitches.  That is, a hardblocked device
-	 * switch can often be unblocked by a platform switch.  Thus if we have
-	 * a hardblocked device switch and a softblocked platform switch, the
-	 * combined state should be softblocked since the platform switch can be
-	 * unblocked to change the device switch.
-	 */
-
-	/* Device switches first */
+	/* Gather the states of platform and non-platform switches */
 	for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
 		Killswitch *ks = iter->data;
 		GUdevDevice *device;
 		RfKillState dev_state;
 		int sysfs_state;
 
-		if (ks->platform == FALSE) {
-			device = g_udev_client_query_by_subsystem_and_name (priv->client, "rfkill", ks->name);
-			if (device) {
-				sysfs_state = g_udev_device_get_property_as_int (device, "RFKILL_STATE");
-				dev_state = sysfs_state_to_nm_state (sysfs_state);
+		device = g_udev_client_query_by_subsystem_and_name (priv->client, "rfkill", ks->name);
+		if (device) {
+			sysfs_state = g_udev_device_get_property_as_int (device, "RFKILL_STATE");
+			dev_state = sysfs_state_to_nm_state (sysfs_state);
+			if (ks->platform == FALSE) {
 				if (dev_state > poll_states[ks->rtype])
 					poll_states[ks->rtype] = dev_state;
-				g_object_unref (device);
-			}
-		}
-	}
-
-	/* Platform switches next; their state overwrites device state */
-	for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
-		Killswitch *ks = iter->data;
-		GUdevDevice *device;
-		RfKillState dev_state;
-		int sysfs_state;
-
-		if (ks->platform == TRUE) {
-			device = g_udev_client_query_by_subsystem_and_name (priv->client, "rfkill", ks->name);
-			if (device) {
-				sysfs_state = g_udev_device_get_property_as_int (device, "RFKILL_STATE");
-				dev_state = sysfs_state_to_nm_state (sysfs_state);
-
-				if (platform_checked[ks->rtype] == FALSE) {
-					/* Overwrite device state with platform state for first
-					 * platform switch found.
-					 */
-					poll_states[ks->rtype] = dev_state;
-					platform_checked[ks->rtype] = TRUE;
-				} else {
-					/* If there are multiple platform switches of the same type,
-					 * take the "worst" state for all of that type.
-					 */
-					if (dev_state > poll_states[ks->rtype])
-						poll_states[ks->rtype] = dev_state;
-				}
-				g_object_unref (device);
+			} else {
+				platform_checked[ks->rtype] = TRUE;
+				if (dev_state > platform_states[ks->rtype])
+					platform_states[ks->rtype] = dev_state;
 			}
+			g_object_unref (device);
 		}
 	}
 
 	/* Log and emit change signal for final rfkill states */
 	for (i = 0; i < RFKILL_TYPE_MAX; i++) {
+		if (platform_checked[i] == TRUE)
+			poll_states[i] = aggregate_states (platform_states[i], poll_states[i]);
 		if (poll_states[i] != priv->rfkill_states[i]) {
 			nm_log_dbg (LOGD_RFKILL, "%s rfkill state now '%s'",
 			            rfkill_type_to_desc (i),
-- 
1.7.3.4



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]