about summary refs log tree commit diff
path: root/src/nm-udev-manager.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2011-05-04 21:35:57 +0200
committerMichael Biebl <biebl@debian.org>2011-05-04 21:35:57 +0200
commit3241555aff5c969104e492501097f4cb8837bcca (patch)
tree6d15a02d02a9f1bfcda6075ae2b8c71537d8038d /src/nm-udev-manager.c
parente1b66c145e71e7bc6a06845dd17788fb7b8e158e (diff)
parent9f806e97a24bba61417ae312fcc0da40914266fb (diff)
Merge commit 'upstream/0.8.999' into experimental
Diffstat (limited to 'src/nm-udev-manager.c')
-rw-r--r--src/nm-udev-manager.c135
1 files changed, 106 insertions, 29 deletions
diff --git a/src/nm-udev-manager.c b/src/nm-udev-manager.c
index 3563a574..41a4e15b 100644
--- a/src/nm-udev-manager.c
+++ b/src/nm-udev-manager.c
@@ -74,6 +74,7 @@ typedef struct {
 	char *driver;
 	RfKillType rtype;
 	gint state;
+	gboolean platform;
 } Killswitch;
 
 RfKillState
@@ -91,7 +92,7 @@ rfkill_type_to_desc (RfKillType rtype)
 	if (rtype == 0)
 		return "WiFi";
 	else if (rtype == 1)
-		return "WWan";
+		return "WWAN";
 	else if (rtype == 2)
 		return "WiMAX";
 	return "unknown";
@@ -113,8 +114,8 @@ static Killswitch *
 killswitch_new (GUdevDevice *device, RfKillType rtype)
 {
 	Killswitch *ks;
-	GUdevDevice *parent = NULL;
-	const char *driver;
+	GUdevDevice *parent = NULL, *grandparent = NULL;
+	const char *driver, *subsys, *parent_subsys = NULL;
 
 	ks = g_malloc0 (sizeof (Killswitch));
 	ks->name = g_strdup (g_udev_device_get_name (device));
@@ -123,17 +124,33 @@ killswitch_new (GUdevDevice *device, RfKillType rtype)
 	ks->rtype = rtype;
 
 	driver = g_udev_device_get_property (device, "DRIVER");
-	if (!driver) {
-		parent = g_udev_device_get_parent (device);
-		if (parent)
+	subsys = g_udev_device_get_subsystem (device);
+
+	/* Check parent for various attributes */
+	parent = g_udev_device_get_parent (device);
+	if (parent) {
+		parent_subsys = g_udev_device_get_subsystem (parent);
+		if (!driver)
 			driver = g_udev_device_get_property (parent, "DRIVER");
+		if (!driver) {
+			/* Sigh; try the grandparent */
+			grandparent = g_udev_device_get_parent (parent);
+			if (grandparent)
+				driver = g_udev_device_get_property (parent, "DRIVER");
+		}
 	}
-	if (driver)
-		ks->driver = g_strdup (driver);
 
+	if (!driver)
+		driver = "(unknown)";
+	ks->driver = g_strdup (driver);
+
+	if (g_strcmp0 (subsys, "platform") == 0 || g_strcmp0 (parent_subsys, "platform") == 0)
+		ks->platform = TRUE;
+
+	if (grandparent)
+		g_object_unref (grandparent);
 	if (parent)
 		g_object_unref (parent);
-
 	return ks;
 }
 
@@ -178,28 +195,77 @@ recheck_killswitches (NMUdevManager *self)
 	NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
 	GSList *iter;
 	RfKillState poll_states[RFKILL_TYPE_MAX];
+	gboolean platform_checked[RFKILL_TYPE_MAX];
 	int i;
 
 	/* Default state is unblocked */
-	for (i = 0; i < RFKILL_TYPE_MAX; i++)
+	for (i = 0; i < RFKILL_TYPE_MAX; i++) {
 		poll_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 */
 	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);
+				if (dev_state > poll_states[ks->rtype])
+					poll_states[ks->rtype] = dev_state;
+				g_object_unref (device);
+			}
+		}
+	}
 
-		device = g_udev_client_query_by_subsystem_and_name (priv->client, "rfkill", ks->name);
-		if (!device)
-			continue;
-
-		dev_state = sysfs_state_to_nm_state (g_udev_device_get_property_as_int (device, "RFKILL_STATE"));
-		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);
+			}
+		}
 	}
 
+	/* Log and emit change signal for final rfkill states */
 	for (i = 0; i < RFKILL_TYPE_MAX; i++) {
 		if (poll_states[i] != priv->rfkill_states[i]) {
 			nm_log_dbg (LOGD_RFKILL, "%s rfkill state now '%s'",
@@ -385,8 +451,12 @@ device_creator (NMUdevManager *manager,
 	}
 
 	if (!driver) {
-		nm_log_warn (LOGD_HW, "%s: couldn't determine device driver; ignoring...", path);
-		goto out;
+		if (g_str_has_prefix (ifname, "easytether")) {
+			driver = "easytether";
+		} else {
+			nm_log_warn (LOGD_HW, "%s: couldn't determine device driver; ignoring...", path);
+			goto out;
+		}
 	}
 
 	ifindex = g_udev_device_get_sysfs_attr_as_int (udev_device, "ifindex");
@@ -420,13 +490,26 @@ net_add (NMUdevManager *self, GUdevDevice *device)
 	gint etype;
 	const char *iface;
 	const char *tmp;
+	gboolean is_ctc;
 
 	g_return_if_fail (device != NULL);
 
+	iface = g_udev_device_get_name (device);
+	if (!iface) {
+		nm_log_dbg (LOGD_HW, "failed to get device's interface");
+		return;
+	}
+
 	etype = g_udev_device_get_sysfs_attr_as_int (device, "type");
-	if (etype != 1) {
+	is_ctc = (strncmp (iface, "ctc", 3) == 0) && (etype == 256);
+
+	/* Ignore devices that don't report Ethernet encapsulation, except for
+	 * s390 CTC-type devices that report 256 for some reason.
+	 * FIXME: use something other than interface name to detect CTC here.
+	 */
+	if ((etype != 1) && (is_ctc == FALSE)) {
 		nm_log_dbg (LOGD_HW, "ignoring interface with type %d", etype);
-		return; /* Not using ethernet encapsulation, don't care */
+		return;
 	}
 
 	/* Not all ethernet devices are immediately usable; newer mobile broadband
@@ -454,12 +537,6 @@ net_add (NMUdevManager *self, GUdevDevice *device)
 		}
 	}
 
-	iface = g_udev_device_get_name (device);
-	if (!iface) {
-		nm_log_dbg (LOGD_HW, "failed to get device's interface");
-		return;
-	}
-
 	g_signal_emit (self, signals[DEVICE_ADDED], 0, device, device_creator);
 }