diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-port-probe.c | 28 | ||||
-rw-r--r-- | src/mm-port-serial-qcdm.c | 16 |
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. */ |