base-manager: reprobe device on late port additions

There is no guarantee from the kernel that the ports of a given device
will all be notified via uevents on a timely manner. We assume it, but
we cannot be completely sure.

There are two main scenarios that we have been seen when the ports of a
device are not notified close enough to each other:

 * A modem object is created, but not with the desired control protocol.
   E.g. a QMI or MBIM modem would end up controlled via AT commands if
   the cdc-wdm port was added too late.

 * A modem object is not created at all, and the device object was
   removed completely. E.g. when the net port addition in a QMI or MBIM
   modem happens too late.

In order to avoid those cases, we will now fully reprobe all the ports
of the device from scratch whenever a new valid port addition happens
after the initial probing of the device has already been completed. If a
modem object is available at that time, we will remove it right away.
This commit is contained in:
Aleksander Morgado
2024-03-12 10:15:59 +00:00
parent 07f1f58642
commit bd255849dc
7 changed files with 310 additions and 132 deletions
+21 -22
View File
@@ -10,7 +10,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details:
*
* Copyright (C) 2012 Google, Inc.
* Copyright (C) 2012-2024 Google, Inc.
*/
#include <config.h>
@@ -26,6 +26,7 @@
#include "mm-device.h"
#include "mm-plugin.h"
#include "mm-log-object.h"
#include "mm-daemon-enums-types.h"
static void log_object_iface_init (MMLogObjectInterface *iface);
@@ -46,7 +47,6 @@ enum {
};
enum {
SIGNAL_PORT_GRABBED,
SIGNAL_PORT_RELEASED,
SIGNAL_LAST
};
@@ -76,7 +76,8 @@ struct _MMDevicePrivate {
/* Kernel drivers managing this device */
gchar **drivers;
/* Best plugin to manage this device */
/* Best plugin to manage this device, only if the device probing
* has finished successfully. */
MMPlugin *plugin;
/* Lists of port probes in the device */
@@ -213,7 +214,7 @@ add_port_driver (MMDevice *self,
self->priv->drivers[n_items + 1] = NULL;
}
void
gboolean
mm_device_grab_port (MMDevice *self,
MMKernelDevice *kernel_port)
{
@@ -221,22 +222,19 @@ mm_device_grab_port (MMDevice *self,
MMKernelDevice *lower_port;
if (mm_device_owns_port (self, kernel_port))
return;
return TRUE;
lower_port = mm_kernel_device_peek_lower_device (kernel_port);
if (lower_port) {
g_autoptr(GError) error = NULL;
/* No port probing done, at this point this is not something we require
* as all the virtual instantiated ports are net devices. We also avoid
* emitting the PORT_GRABBED signal in the MMDevice, because that is
* exclusively linked to a port being added to the list of probes, which
* we don't do here. */
* as all the virtual instantiated ports are net devices. */
if (self->priv->modem && !mm_base_modem_grab_link_port (self->priv->modem, kernel_port, &error))
mm_obj_dbg (self, "fully ignoring link port %s from now on: %s",
mm_kernel_device_get_name (kernel_port),
error->message);
return;
return FALSE;
}
if (!g_strcmp0 ("net", mm_kernel_device_get_subsystem (kernel_port)) &&
mm_kernel_device_get_wwandev_sysfs_path (kernel_port)) {
@@ -256,7 +254,7 @@ mm_device_grab_port (MMDevice *self,
mm_obj_dbg (self, "fully ignoring link port %s from now on: %s",
mm_kernel_device_get_name (kernel_port),
error->message);
return;
return FALSE;
}
}
@@ -278,8 +276,7 @@ mm_device_grab_port (MMDevice *self,
probe = mm_port_probe_new (self, kernel_port);
self->priv->port_probes = g_list_prepend (self->priv->port_probes, probe);
/* Notify about the grabbed port */
g_signal_emit (self, signals[SIGNAL_PORT_GRABBED], 0, kernel_port);
return TRUE;
}
void
@@ -627,6 +624,17 @@ mm_device_peek_port_probe_list (MMDevice *self)
return self->priv->port_probes;
}
void
mm_device_reset_port_probe_list (MMDevice *self)
{
GList *l;
mm_obj_dbg (self, "port probe list reset...");
for (l = self->priv->port_probes; l; l = g_list_next (l)) {
mm_port_probe_reset (MM_PORT_PROBE (l->data));
}
}
gboolean
mm_device_get_hotplugged (MMDevice *self)
{
@@ -981,15 +989,6 @@ mm_device_class_init (MMDeviceClass *klass)
G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_INHIBITED, properties[PROP_INHIBITED]);
signals[SIGNAL_PORT_GRABBED] =
g_signal_new (MM_DEVICE_PORT_GRABBED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (MMDeviceClass, port_grabbed),
NULL, NULL,
g_cclosure_marshal_generic,
G_TYPE_NONE, 1, MM_TYPE_KERNEL_DEVICE);
signals[SIGNAL_PORT_RELEASED] =
g_signal_new (MM_DEVICE_PORT_RELEASED,
G_OBJECT_CLASS_TYPE (object_class),