aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mm-port-probe.c28
-rw-r--r--src/mm-port-serial-qcdm.c16
2 files changed, 38 insertions, 6 deletions
diff --git a/src/mm-port-probe.c b/src/mm-port-probe.c
index b9a7d422..dcedc3a8 100644
--- a/src/mm-port-probe.c
+++ b/src/mm-port-probe.c
@@ -114,10 +114,12 @@ struct _MMPortProbePrivate {
/*****************************************************************************/
-void
-mm_port_probe_reset (MMPortProbe *self)
+static void
+mm_port_probe_clear (MMPortProbe *self)
{
- g_assert (!self->priv->task);
+ /* Clears existing probe results so probing can restart from the beginning.
+ * Should only be used internally as it does not ensure `task` is NULL.
+ */
self->priv->flags = 0;
self->priv->is_at = FALSE;
self->priv->is_qcdm = FALSE;
@@ -129,6 +131,14 @@ mm_port_probe_reset (MMPortProbe *self)
self->priv->is_mbim = FALSE;
}
+void
+mm_port_probe_reset (MMPortProbe *self)
+{
+ /* Clears existing probe results after probing is complete */
+ g_assert (!self->priv->task);
+ mm_port_probe_clear (self);
+}
+
/*****************************************************************************/
/* Probe task completions.
* Always make sure that the stored task is NULL when the task is completed.
@@ -669,7 +679,7 @@ serial_probe_qcdm_parse_response (MMPortSerialQcdm *port,
gint err = QCDM_SUCCESS;
gboolean is_qcdm = FALSE;
gboolean retry = FALSE;
- GError *error = NULL;
+ g_autoptr(GError) error = NULL;
GByteArray *response;
PortProbeRunContext *ctx;
@@ -695,11 +705,17 @@ serial_probe_qcdm_parse_response (MMPortSerialQcdm *port,
} else if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_PARSE_FAILED)) {
/* Failed to unescape QCDM packet: don't retry */
mm_obj_dbg (self, "QCDM parsing error: %s", error->message);
- g_error_free (error);
+ } else if (g_error_matches (error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_CARRIER)) {
+ /* Special-case: the port may have been in PPP mode (if system is restarted
+ * but the modem still had power) and failed AT probing. QCDM probing
+ * sends empty HDLC frames that PPP parses and then terminates the
+ * connection with "NO CARRIER". Match this and go back to AT probing.
+ */
+ mm_obj_dbg (self, "QCDM parsing got NO CARRIER; retrying AT probing");
+ mm_port_probe_clear (self);
} else {
if (!g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT))
mm_obj_dbg (self, "QCDM probe error: (%d) %s", error->code, error->message);
- g_error_free (error);
retry = TRUE;
}
diff --git a/src/mm-port-serial-qcdm.c b/src/mm-port-serial-qcdm.c
index 08f24303..080f639f 100644
--- a/src/mm-port-serial-qcdm.c
+++ b/src/mm-port-serial-qcdm.c
@@ -12,6 +12,7 @@
*
* Copyright (C) 2008 - 2009 Novell, Inc.
* Copyright (C) 2009 - 2010 Red Hat, Inc.
+ * Copyright (C) 2024 JUCR GmbH
*/
#include <stdio.h>
@@ -70,6 +71,9 @@ find_qcdm_start (GByteArray *response, gsize *start)
return FALSE;
}
+/* /r/nNO CARRIER/r/n */
+static const gchar no_carrier[] = { 0x0d, 0x0a, 0x4e, 0x4f, 0x20, 0x43, 0x41, 0x52, 0x52, 0x49, 0x45, 0x52, 0x0d, 0x0a };
+
static MMPortSerialResponseType
parse_qcdm (GByteArray *response,
gboolean want_log,
@@ -84,6 +88,18 @@ parse_qcdm (GByteArray *response,
/* Get the offset into the buffer of where the QCDM frame starts */
if (!find_qcdm_start (response, &start)) {
+ /* As a special case detect \r\nNO CARRIER\r\n which happens when a port
+ * is in PPP mode and QCDM attemps to send QCDM requests. The modem will
+ * often terminate PPP when it receives the bogus frame.
+ */
+ if (response->len >= sizeof (no_carrier) && memcmp (response->data, no_carrier, sizeof (no_carrier)) == 0) {
+ g_set_error (error,
+ MM_CONNECTION_ERROR,
+ MM_CONNECTION_ERROR_NO_CARRIER,
+ "Received NO CARRIER response");
+ return MM_PORT_SERIAL_RESPONSE_ERROR;
+ }
+
/* Discard the unparsable data right away, we do need a QCDM
* start, and anything that comes before it is unknown data
* that we'll never use. */