Blob Blame History Raw
From 3e76601295d8a43acb7c36e62e89fb7e9205f7f0 Mon Sep 17 00:00:00 2001
From: Lubomir Rintel <lkundrak@v3.sk>
Date: Wed, 1 Oct 2014 12:02:36 +0200
Subject: [PATCH 1/3] device: Keep track of devices as they are move across
 sysfs

For certain devices the name changes with their status. Notably, RFCOMM
devices move from /devices/virtual/ to underneath the HCI that is used
for the connection as the session is estabilished, and return back when
it's torn down.
---
 src/mm-device.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/mm-device.c b/src/mm-device.c
index 54f6456..46824ee 100644
--- a/src/mm-device.c
+++ b/src/mm-device.c
@@ -85,6 +85,11 @@ device_find_probe_with_device (MMDevice    *self,
     for (l = self->priv->port_probes; l; l = g_list_next (l)) {
         MMPortProbe *probe = MM_PORT_PROBE (l->data);
 
+        if (   g_udev_device_has_property (udev_port, "DEVPATH_OLD")
+            && g_str_has_suffix (g_udev_device_get_sysfs_path (mm_port_probe_peek_port (probe)),
+                                 g_udev_device_get_property (udev_port, "DEVPATH_OLD")))
+            return probe;
+
         if (g_str_equal (g_udev_device_get_sysfs_path (mm_port_probe_peek_port (probe)),
                          g_udev_device_get_sysfs_path (udev_port)))
             return probe;
@@ -96,6 +101,11 @@ device_find_probe_with_device (MMDevice    *self,
     for (l = self->priv->ignored_port_probes; l; l = g_list_next (l)) {
         MMPortProbe *probe = MM_PORT_PROBE (l->data);
 
+        if (   g_udev_device_has_property (udev_port, "DEVPATH_OLD")
+            && g_str_has_suffix (g_udev_device_get_sysfs_path (mm_port_probe_peek_port (probe)),
+                                 g_udev_device_get_property (udev_port, "DEVPATH_OLD")))
+            return probe;
+
         if (g_str_equal (g_udev_device_get_sysfs_path (mm_port_probe_peek_port (probe)),
                          g_udev_device_get_sysfs_path (udev_port)))
             return probe;
-- 
2.4.3

From c3ea9c4f6fecdd2363bdaeceb660e21c4139ab47 Mon Sep 17 00:00:00 2001
From: Lubomir Rintel <lkundrak@v3.sk>
Date: Wed, 1 Oct 2014 12:00:14 +0200
Subject: [PATCH 2/3] manager: Remove devices which are deemed unfit during
 addition attempt

device_added() might be called in response to a "change" or "move" attempt that
might have changed a candidate device to a non-candidate one.
---
 src/mm-manager.c | 118 +++++++++++++++++++++++++++++--------------------------
 1 file changed, 62 insertions(+), 56 deletions(-)

diff --git a/src/mm-manager.c b/src/mm-manager.c
index 7103a00..73173e8 100644
--- a/src/mm-manager.c
+++ b/src/mm-manager.c
@@ -220,6 +220,61 @@ find_physical_device (GUdevDevice *child)
 }
 
 static void
+device_removed (MMManager *self,
+                GUdevDevice *udev_device)
+{
+    MMDevice *device;
+    const gchar *subsys;
+    const gchar *name;
+
+    g_return_if_fail (udev_device != NULL);
+
+    subsys = g_udev_device_get_subsystem (udev_device);
+    name = g_udev_device_get_name (udev_device);
+
+    if (!g_str_has_prefix (subsys, "usb") ||
+        (name && g_str_has_prefix (name, "cdc-wdm"))) {
+        /* Handle tty/net/wdm port removal */
+        device = find_device_by_port (self, udev_device);
+        if (device) {
+            mm_info ("(%s/%s): released by modem %s",
+                     subsys,
+                     name,
+                     g_udev_device_get_sysfs_path (mm_device_peek_udev_device (device)));
+            mm_device_release_port (device, udev_device);
+
+            /* If port probe list gets empty, remove the device object iself */
+            if (!mm_device_peek_port_probe_list (device)) {
+                mm_dbg ("Removing empty device '%s'", mm_device_get_path (device));
+                mm_device_remove_modem (device);
+                g_hash_table_remove (self->priv->devices, mm_device_get_path (device));
+            }
+        }
+
+        return;
+    }
+
+    /* This case is designed to handle the case where, at least with kernel 2.6.31, unplugging
+     * an in-use ttyACMx device results in udev generating remove events for the usb, but the
+     * ttyACMx device (subsystem tty) is not removed, since it was in-use.  So if we have not
+     * found a modem for the port (above), we're going to look here to see if we have a modem
+     * associated with the newly removed device.  If so, we'll remove the modem, since the
+     * device has been removed.  That way, if the device is reinserted later, we'll go through
+     * the process of exporting it.
+     */
+    device = find_device_by_udev_device (self, udev_device);
+    if (device) {
+        mm_dbg ("Removing device '%s'", mm_device_get_path (device));
+        mm_device_remove_modem (device);
+        g_hash_table_remove (self->priv->devices, mm_device_get_path (device));
+        return;
+    }
+
+    /* Maybe a plugin is checking whether or not the port is supported.
+     * TODO: Cancel every possible supports check in this port. */
+}
+
+static void
 device_added (MMManager *manager,
               GUdevDevice *port,
               gboolean hotplugged,
@@ -247,8 +302,14 @@ device_added (MMManager *manager,
      * rules have been processed before handling a device.
      */
     is_candidate = g_udev_device_get_property_as_boolean (port, "ID_MM_CANDIDATE");
-    if (!is_candidate)
+    if (!is_candidate) {
+        /* This could mean that device changed, loosing its ID_MM_CANDIDATE
+         * flags (such as Bluetooth RFCOMM devices upon disconnect.
+         * Try to forget it. */
+        if (hotplugged && !manual_scan)
+            device_removed (manager, port);
         return;
+    }
 
     if (find_device_by_port (manager, port))
         return;
@@ -332,61 +393,6 @@ out:
 }
 
 static void
-device_removed (MMManager *self,
-                GUdevDevice *udev_device)
-{
-    MMDevice *device;
-    const gchar *subsys;
-    const gchar *name;
-
-    g_return_if_fail (udev_device != NULL);
-
-    subsys = g_udev_device_get_subsystem (udev_device);
-    name = g_udev_device_get_name (udev_device);
-
-    if (!g_str_has_prefix (subsys, "usb") ||
-        (name && g_str_has_prefix (name, "cdc-wdm"))) {
-        /* Handle tty/net/wdm port removal */
-        device = find_device_by_port (self, udev_device);
-        if (device) {
-            mm_info ("(%s/%s): released by modem %s",
-                     subsys,
-                     name,
-                     g_udev_device_get_sysfs_path (mm_device_peek_udev_device (device)));
-            mm_device_release_port (device, udev_device);
-
-            /* If port probe list gets empty, remove the device object iself */
-            if (!mm_device_peek_port_probe_list (device)) {
-                mm_dbg ("Removing empty device '%s'", mm_device_get_path (device));
-                mm_device_remove_modem (device);
-                g_hash_table_remove (self->priv->devices, mm_device_get_path (device));
-            }
-        }
-
-        return;
-    }
-
-    /* This case is designed to handle the case where, at least with kernel 2.6.31, unplugging
-     * an in-use ttyACMx device results in udev generating remove events for the usb, but the
-     * ttyACMx device (subsystem tty) is not removed, since it was in-use.  So if we have not
-     * found a modem for the port (above), we're going to look here to see if we have a modem
-     * associated with the newly removed device.  If so, we'll remove the modem, since the
-     * device has been removed.  That way, if the device is reinserted later, we'll go through
-     * the process of exporting it.
-     */
-    device = find_device_by_udev_device (self, udev_device);
-    if (device) {
-        mm_dbg ("Removing device '%s'", mm_device_get_path (device));
-        mm_device_remove_modem (device);
-        g_hash_table_remove (self->priv->devices, mm_device_get_path (device));
-        return;
-    }
-
-    /* Maybe a plugin is checking whether or not the port is supported.
-     * TODO: Cancel every possible supports check in this port. */
-}
-
-static void
 handle_uevent (GUdevClient *client,
                const char *action,
                GUdevDevice *device,
-- 
2.4.3

From 71665f3a81000db156b72d135cffc0c9355d12df Mon Sep 17 00:00:00 2001
From: Lubomir Rintel <lkundrak@v3.sk>
Date: Wed, 1 Oct 2014 12:00:14 +0200
Subject: [PATCH 3/3] udev: Don't mark disconnected RFCOMM ttys as candidates

Bluetooth serial devices are weird. They begin life being bound with
RFCOMMCREATEDEV ioctl() and then move around the sysfs tree when they are
connected and disconnected. The connection is estabilished upon the first
open() and torn down upon last close(), their first user virtually being
"owner" of the connection. We don't want to be that process, we're only
interested in actually connected modems. However, currently we have no
knowledge of that and therefore we connect and disconnect multiple times while
probing.

This patch marks unconnected RFCOMM devices as uninteresting to us.
The actual connection and disconnection will be handled by NetworkManager.
---
 src/80-mm-candidate.rules | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/80-mm-candidate.rules b/src/80-mm-candidate.rules
index 2e938d7..52e6882 100644
--- a/src/80-mm-candidate.rules
+++ b/src/80-mm-candidate.rules
@@ -9,6 +9,10 @@
 
 ACTION!="add|change|move", GOTO="mm_candidate_end"
 
+# Opening bound but disconnected Bluetooth RFCOMM ttys would initiate the
+# connection. Don't do that.
+KERNEL=="rfcomm[0-9]*", DEVPATH=="*/virtual/*", GOTO="mm_candidate_end"
+
 SUBSYSTEM=="tty", ENV{ID_MM_CANDIDATE}="1"
 SUBSYSTEM=="net", ENV{ID_MM_CANDIDATE}="1"
 KERNEL=="cdc-wdm*", SUBSYSTEM=="usb", ENV{ID_MM_CANDIDATE}="1"
-- 
2.4.3