summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksandermj@chromium.org>2023-03-27 13:42:33 +0000
committerAleksander Morgado <aleksandermj@chromium.org>2023-04-13 11:54:04 +0000
commit7e0663f922425cb33e9c53745e51eec1e5dd89c4 (patch)
treed924a1a9f17587d8c7139cff2ad564e58b193351
parent79b15cf87ce3d94a061f2f37eec2f00eb3987cc6 (diff)
downloadModemManager-7e0663f922425cb33e9c53745e51eec1e5dd89c4.tar.gz
udev: new ID_MM_REQUIRED tag
Users with QMI or MBIM capable modems may want to ensure that these are never managed using plain AT commands, as that also involves using PPP. This fallback to AT could happen if the QMI or MBIM port probing fails for whatever reason. The new `ID_MM_REQUIRED` udev tag allows specifying that a given port MUST be successfully grabbed when creating a new modem object, or otherwise the modem object will not be created at all (even if there are other fallback control ports like AT that could have been used). Use this tag with caution. It is assumed that when this tag is used some other external process may be monitoring the existence of the modem object in DBus as exposed by ModemManager, and if it does not appear for any reason then the modem would be reseted with some other mechanism (e.g. GPIOs, if available). If no such mechanism to autorecover the modem is in place, using this tag may leave the modem exposed in the kernel but ignored by ModemManager. This tag must be applied on the specific port for which the existence and usability must be ensured. E.g. flagging the MBIM port of the Fibocom L850 module as required: $ vim /lib/udev/rules.d/78-mm-test.rules ACTION!="add|change|move|bind", GOTO="mm_test_rules_end" SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}" ATTRS{idVendor}=="2cb7", ATTRS{idProduct}=="0007", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_REQUIRED}="1" LABEL="mm_test_rules_end" $ sudo udevadm control --reload $ sudo udevadm trigger $ sudo udevadm info -p /sys/class/usbmisc/cdc-wdm0 ... E: ID_MM_REQUIRED=1 E: ID_MM_CANDIDATE=1
-rw-r--r--include/ModemManager-tags.h18
-rw-r--r--src/mm-base-modem.c15
-rw-r--r--src/mm-plugin.c9
3 files changed, 41 insertions, 1 deletions
diff --git a/include/ModemManager-tags.h b/include/ModemManager-tags.h
index 2029aa909..d3a06d248 100644
--- a/include/ModemManager-tags.h
+++ b/include/ModemManager-tags.h
@@ -252,6 +252,24 @@
*/
#define ID_MM_TTY_FLOW_CONTROL "ID_MM_TTY_FLOW_CONTROL"
+/**
+ * ID_MM_REQUIRED:
+ *
+ * This is a port-specific tag that allows users to specify that the modem
+ * must be able to successfully probe and use the given control port.
+ *
+ * If this tag is set and the port probing procedure fails, the modem object
+ * will not be created, which is the same as if the port didn't exist in the
+ * first place.
+ *
+ * E.g. this tag may be set on a QMI control port if we want to make sure the
+ * modem object exposed by ModemManager is QMI-capable and never an AT-based
+ * modem created due to falling back on a failed QMI port probing procedure.
+ *
+ * Since: 1.22
+ */
+#define ID_MM_REQUIRED "ID_MM_REQUIRED"
+
/*
* The following symbols are deprecated. We don't add them to -compat
* because this -tags file is not really part of the installed API.
diff --git a/src/mm-base-modem.c b/src/mm-base-modem.c
index 58fbf450e..f5a983c0e 100644
--- a/src/mm-base-modem.c
+++ b/src/mm-base-modem.c
@@ -470,8 +470,21 @@ mm_base_modem_grab_port (MMBaseModem *self,
MMPortSerialAtFlag at_pflags,
GError **error)
{
- if (!base_modem_internal_grab_port (self, kernel_device, FALSE, ptype, at_pflags, error))
+ g_autoptr(GError) inner_error = NULL;
+
+ if (!base_modem_internal_grab_port (self, kernel_device, FALSE, ptype, at_pflags, &inner_error)) {
+ /* If the port was REQUIRED via udev tags and we failed to grab it, we will report
+ * a fatal error. */
+ if (mm_kernel_device_get_property_as_boolean (kernel_device, ID_MM_REQUIRED)) {
+ mm_obj_err (self, "required port '%s/%s' failed to be grabbed",
+ mm_kernel_device_get_subsystem (kernel_device),
+ mm_kernel_device_get_name (kernel_device));
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED,
+ "Required port failed to be grabbed");
+ } else
+ g_propagate_error (error, g_steal_pointer (&inner_error));
return FALSE;
+ }
mm_obj_dbg (self, "port '%s/%s' grabbed",
mm_kernel_device_get_subsystem (kernel_device),
diff --git a/src/mm-plugin.c b/src/mm-plugin.c
index 725391fc2..464e3fd7e 100644
--- a/src/mm-plugin.c
+++ b/src/mm-plugin.c
@@ -1084,6 +1084,15 @@ mm_plugin_create_modem (MMPlugin *self,
next:
if (!grabbed) {
mm_obj_warn (self, "could not grab port %s: %s", name, inner_error ? inner_error->message : "unknown error");
+
+ /* An ABORTED error is emitted exclusively when the port grabbing operation
+ * detects that a REQUIRED port is unusable. */
+ if (g_error_matches (inner_error, MM_CORE_ERROR, MM_CORE_ERROR_ABORTED)) {
+ g_propagate_error (error, inner_error);
+ g_clear_object (&modem);
+ return NULL;
+ }
+
g_clear_error (&inner_error);
}
}