aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksander Morgado <aleksandermj@chromium.org>2023-10-20 12:20:35 +0000
committerAleksander Morgado <aleksandermj@chromium.org>2023-10-26 12:35:50 +0000
commit59aae421a1169ff77edb8f83e6f078b09ca20ce0 (patch)
treef7963ce6d89e954a8baf6f8c5590d1f43c8b1c26 /src
parente0bcf0a3c4cd6b39eb4ee7d1ed368346509b8ff4 (diff)
core,error-helpers: new method to normalize GErrors
The ModemManager API should not expose or return error types out of the error domains it supports. Default to a generic core error "Failed", while keeping the original error description.
Diffstat (limited to 'src')
-rw-r--r--src/mm-error-helpers.c195
-rw-r--r--src/mm-error-helpers.h11
-rw-r--r--src/tests/test-error-helpers.c84
3 files changed, 264 insertions, 26 deletions
diff --git a/src/mm-error-helpers.c b/src/mm-error-helpers.c
index f7b0ba9c..81fc995c 100644
--- a/src/mm-error-helpers.c
+++ b/src/mm-error-helpers.c
@@ -15,11 +15,22 @@
* Copyright (C) 2011 - 2012 Google, Inc.
*/
+#include <config.h>
+
#include "mm-error-helpers.h"
+#include "mm-errors-types.h"
#include "mm-log.h"
#include <ctype.h>
+#if defined WITH_QMI
+# include <libqmi-glib.h>
+#endif
+
+#if defined WITH_MBIM
+# include <libmbim-glib.h>
+#endif
+
/******************************************************************************/
static gchar *
@@ -41,6 +52,38 @@ normalize_error_string (const gchar *str)
}
/******************************************************************************/
+/* Core errors */
+
+/* Human friendly messages for each error type */
+static const gchar *core_error_messages[] = {
+ [MM_CORE_ERROR_FAILED] = "Failed",
+ [MM_CORE_ERROR_CANCELLED] = "Cancelled",
+ [MM_CORE_ERROR_ABORTED] = "Aborted",
+ [MM_CORE_ERROR_UNSUPPORTED] = "Unsupported",
+ [MM_CORE_ERROR_NO_PLUGINS] = "No plugins",
+ [MM_CORE_ERROR_UNAUTHORIZED] = "Unauthorized",
+ [MM_CORE_ERROR_INVALID_ARGS] = "Invalid arguments",
+ [MM_CORE_ERROR_IN_PROGRESS] = "In progress",
+ [MM_CORE_ERROR_WRONG_STATE] = "Wrong state",
+ [MM_CORE_ERROR_CONNECTED] = "Connected",
+ [MM_CORE_ERROR_TOO_MANY] = "Too many",
+ [MM_CORE_ERROR_NOT_FOUND] = "Not found",
+ [MM_CORE_ERROR_RETRY] = "Retry",
+ [MM_CORE_ERROR_EXISTS] = "Exists",
+ [MM_CORE_ERROR_WRONG_SIM_STATE] = "Wrong SIM state",
+ [MM_CORE_ERROR_RESET_AND_RETRY] = "Reset and retry",
+ [MM_CORE_ERROR_TIMEOUT] = "Timed out",
+ [MM_CORE_ERROR_PROTOCOL] = "Protocol failure",
+ [MM_CORE_ERROR_THROTTLED] = "Throttled",
+};
+
+static const gchar *
+core_error_get_string (MMCoreError code)
+{
+ return (code < G_N_ELEMENTS (core_error_messages)) ? core_error_messages[code] : NULL;
+}
+
+/******************************************************************************/
/* Connection errors */
/* Human friendly messages for each error type */
@@ -52,17 +95,21 @@ static const gchar *connection_error_messages[] = {
[MM_CONNECTION_ERROR_NO_ANSWER] = "No answer",
};
+static const gchar *
+connection_error_get_string (MMConnectionError code)
+{
+ return (code < G_N_ELEMENTS (connection_error_messages)) ? connection_error_messages[code] : NULL;
+}
+
GError *
mm_connection_error_for_code (MMConnectionError code,
gpointer log_object)
{
- if (code < G_N_ELEMENTS (connection_error_messages)) {
- const gchar *error_message;
+ const gchar *description;
- error_message = connection_error_messages[code];
- if (error_message)
- return g_error_new_literal (MM_CONNECTION_ERROR, code, error_message);
- }
+ description = connection_error_get_string (code);
+ if (description)
+ return g_error_new_literal (MM_CONNECTION_ERROR, code, description);
/* Not found? Then, default to 'no carrier' */
mm_obj_dbg (log_object, "unknown connection error: %u", code);
@@ -244,17 +291,21 @@ static const gchar *me_error_messages[] = {
/* All generic ME errors should be < 255, as those are the only reserved ones in the 3GPP spec */
G_STATIC_ASSERT (G_N_ELEMENTS (me_error_messages) <= 256);
+static const gchar *
+me_error_get_string (MMMobileEquipmentError code)
+{
+ return (code < G_N_ELEMENTS (me_error_messages)) ? me_error_messages[code] : NULL;
+}
+
GError *
mm_mobile_equipment_error_for_code (MMMobileEquipmentError code,
gpointer log_object)
{
- if (code < G_N_ELEMENTS (me_error_messages)) {
- const gchar *error_message;
+ const gchar *description;
- error_message = me_error_messages[code];
- if (error_message)
- return g_error_new_literal (MM_MOBILE_EQUIPMENT_ERROR, code, error_message);
- }
+ description = me_error_get_string (code);
+ if (description)
+ return g_error_new_literal (MM_MOBILE_EQUIPMENT_ERROR, code, description);
/* Not found? Then, default */
mm_obj_dbg (log_object, "unknown mobile equipment error: %u", code);
@@ -264,6 +315,27 @@ mm_mobile_equipment_error_for_code (MMMobileEquipmentError code,
}
/******************************************************************************/
+/* Serial errors */
+
+static const gchar *serial_error_messages[] = {
+ [MM_SERIAL_ERROR_UNKNOWN] = "Unknown",
+ [MM_SERIAL_ERROR_OPEN_FAILED] = "Open failed",
+ [MM_SERIAL_ERROR_SEND_FAILED] = "Send failed",
+ [MM_SERIAL_ERROR_RESPONSE_TIMEOUT] = "Response timeout",
+ [MM_SERIAL_ERROR_OPEN_FAILED_NO_DEVICE] = "Open failed, no device",
+ [MM_SERIAL_ERROR_FLASH_FAILED] = "Flash failed",
+ [MM_SERIAL_ERROR_NOT_OPEN] = "Not open",
+ [MM_SERIAL_ERROR_PARSE_FAILED] = "Parse failed",
+ [MM_SERIAL_ERROR_FRAME_NOT_FOUND] = "Frame not found",
+};
+
+static const gchar *
+serial_error_get_string (MMSerialError code)
+{
+ return (code < G_N_ELEMENTS (serial_error_messages)) ? serial_error_messages[code] : NULL;
+}
+
+/******************************************************************************/
/* Message errors
*
* The message errors are all >300, so we define a common offset for all error
@@ -302,23 +374,26 @@ static const gchar *msg_error_messages[] = {
/* All generic message errors should be <= 500 (500-common=200), as those are the only reserved ones in the 3GPP spec */
G_STATIC_ASSERT (G_N_ELEMENTS (msg_error_messages) <= 201);
+static const gchar *
+message_error_get_string (MMMessageError code)
+{
+ return ((code >= MM_MESSAGE_ERROR_COMMON_OFFSET) && ((code - MM_MESSAGE_ERROR_COMMON_OFFSET) < G_N_ELEMENTS (msg_error_messages))) ?
+ msg_error_messages[code - MM_MESSAGE_ERROR_COMMON_OFFSET] : NULL;
+}
+
GError *
mm_message_error_for_code (MMMessageError code,
gpointer log_object)
{
- if ((code >= MM_MESSAGE_ERROR_COMMON_OFFSET) && ((code - MM_MESSAGE_ERROR_COMMON_OFFSET) < G_N_ELEMENTS (msg_error_messages))) {
- const gchar *error_message;
+ const gchar *description;
- error_message = msg_error_messages[code - MM_MESSAGE_ERROR_COMMON_OFFSET];
- if (error_message)
- return g_error_new_literal (MM_MESSAGE_ERROR, code, error_message);
- }
+ description = message_error_get_string (code);
+ if (description)
+ return g_error_new_literal (MM_MESSAGE_ERROR, code, description);
/* Not found? Then, default */
mm_obj_dbg (log_object, "unknown message error: %u", code);
- return g_error_new (MM_MESSAGE_ERROR,
- MM_MESSAGE_ERROR_UNKNOWN,
- "Unknown message error: %u", code);
+ return g_error_new (MM_MESSAGE_ERROR, MM_MESSAGE_ERROR_UNKNOWN, "Unknown message error: %u", code);
}
/******************************************************************************/
@@ -420,3 +495,81 @@ mm_message_error_for_string (const gchar *str,
MM_MESSAGE_ERROR_UNKNOWN,
"Unknown message error string: %s", str);
}
+
+/******************************************************************************/
+/* CDMA activation errors */
+
+static const gchar *cdma_activation_error_messages[] = {
+ [MM_CDMA_ACTIVATION_ERROR_NONE] = "None",
+ [MM_CDMA_ACTIVATION_ERROR_UNKNOWN] = "Unknown",
+ [MM_CDMA_ACTIVATION_ERROR_ROAMING] = "Roaming",
+ [MM_CDMA_ACTIVATION_ERROR_WRONG_RADIO_INTERFACE] = "Wrong radio interface",
+ [MM_CDMA_ACTIVATION_ERROR_COULD_NOT_CONNECT] = "Could not connect",
+ [MM_CDMA_ACTIVATION_ERROR_SECURITY_AUTHENTICATION_FAILED] = "Security authentication failed",
+ [MM_CDMA_ACTIVATION_ERROR_PROVISIONING_FAILED] = "Provisioning failed",
+ [MM_CDMA_ACTIVATION_ERROR_NO_SIGNAL] = "No signal",
+ [MM_CDMA_ACTIVATION_ERROR_TIMED_OUT] = "Timed out",
+ [MM_CDMA_ACTIVATION_ERROR_START_FAILED] = "Start failed",
+};
+
+static const gchar *
+cdma_activation_error_get_string (MMCdmaActivationError code)
+{
+ return (code < G_N_ELEMENTS (cdma_activation_error_messages)) ? cdma_activation_error_messages[code] : NULL;
+}
+
+/******************************************************************************/
+/* Takes a GError of any kind and ensures that the returned GError is a
+ * MM-defined one. */
+
+static GError *
+normalize_mm_error (const GError *error,
+ const gchar *error_description,
+ const gchar *error_type)
+{
+ if (error_description) {
+ GError *copy;
+
+ copy = g_error_copy (error);
+ /* Add error type name only if it isn't already the same string */
+ if (g_strcmp0 (copy->message, error_description) != 0)
+ g_prefix_error (&copy, "%s: ", error_description);
+ return copy;
+ }
+
+ return g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Unhandled %s error (%u): %s",
+ error_type, error->code, error->message);
+}
+
+GError *
+mm_normalize_error (const GError *error)
+{
+ g_assert (error);
+
+ if (error->domain == G_IO_ERROR) {
+ /* G_IO_ERROR_CANCELLED is an exception, because we map it to
+ * MM_CORE_ERROR_CANCELLED implicitly when building the DBus error name. */
+ if (error->code == G_IO_ERROR_CANCELLED)
+ return g_error_copy (error);
+
+ return g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Unhandled GIO error (%u): %s", error->code, error->message);
+ }
+
+ /* Ensure all errors reported in the MM domains are known errors */
+ if (error->domain == MM_CORE_ERROR)
+ return normalize_mm_error (error, core_error_get_string (error->code), "core");
+ if (error->domain == MM_MOBILE_EQUIPMENT_ERROR)
+ return normalize_mm_error (error, me_error_get_string (error->code), "mobile equipment");
+ if (error->domain == MM_CONNECTION_ERROR)
+ return normalize_mm_error (error, connection_error_get_string (error->code), "connection");
+ if (error->domain == MM_SERIAL_ERROR)
+ return normalize_mm_error (error, serial_error_get_string (error->code), "serial");
+ if (error->domain == MM_MESSAGE_ERROR)
+ return normalize_mm_error (error, message_error_get_string (error->code), "message");
+ if (error->domain == MM_CDMA_ACTIVATION_ERROR)
+ return normalize_mm_error (error, cdma_activation_error_get_string (error->code), "CDMA activation");
+
+ /* Generic fallback */
+ return g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "%s", error->message);
+}
diff --git a/src/mm-error-helpers.h b/src/mm-error-helpers.h
index e99d1662..d0effac7 100644
--- a/src/mm-error-helpers.h
+++ b/src/mm-error-helpers.h
@@ -23,10 +23,11 @@
#include <ModemManager.h>
#include <libmm-glib.h>
-GError *mm_connection_error_for_code (MMConnectionError code, gpointer log_object);
-GError *mm_mobile_equipment_error_for_code (MMMobileEquipmentError code, gpointer log_object);
-GError *mm_mobile_equipment_error_for_string (const gchar *str, gpointer log_object);
-GError *mm_message_error_for_code (MMMessageError code, gpointer log_object);
-GError *mm_message_error_for_string (const gchar *str, gpointer log_object);
+GError *mm_connection_error_for_code (MMConnectionError code, gpointer log_object);
+GError *mm_mobile_equipment_error_for_code (MMMobileEquipmentError code, gpointer log_object);
+GError *mm_mobile_equipment_error_for_string (const gchar *str, gpointer log_object);
+GError *mm_message_error_for_code (MMMessageError code, gpointer log_object);
+GError *mm_message_error_for_string (const gchar *str, gpointer log_object);
+GError *mm_normalize_error (const GError *error);
#endif /* MM_ERROR_HELPERS_H */
diff --git a/src/tests/test-error-helpers.c b/src/tests/test-error-helpers.c
index 03bcab98..68e6daf3 100644
--- a/src/tests/test-error-helpers.c
+++ b/src/tests/test-error-helpers.c
@@ -13,6 +13,8 @@
* Copyright (C) 2019 Aleksander Morgado <aleksander@aleksander.es>
*/
+#include <config.h>
+
#include <glib.h>
#include <glib-object.h>
#include <string.h>
@@ -24,6 +26,14 @@
#include "mm-error-helpers.h"
#include "mm-log.h"
+#if defined WITH_QMI
+# include <libqmi-glib.h>
+#endif
+
+#if defined WITH_MBIM
+# include <libmbim-glib.h>
+#endif
+
#define TEST_ERROR_HELPER(ERROR_CAPS,ERROR_SMALL,ERROR_CAMEL) \
static void \
test_error_helpers_## ERROR_SMALL (void) \
@@ -131,6 +141,78 @@ test_error_helpers_message_error_for_string (void)
/*****************************************************************************/
+static void
+normalize_and_assert_mm_error (gboolean expect_fallback,
+ GQuark domain,
+ int code,
+ const gchar *description)
+{
+ g_autoptr(GError) input_error = NULL;
+ g_autoptr(GError) normalized_error = NULL;
+
+ g_debug ("Checking normalized error: %s", description);
+
+ input_error = g_error_new_literal (domain, code, description);
+ normalized_error = mm_normalize_error (input_error);
+
+ g_assert (normalized_error);
+ g_assert ((normalized_error->domain == MM_CORE_ERROR) ||
+ (normalized_error->domain == MM_MOBILE_EQUIPMENT_ERROR) ||
+ (normalized_error->domain == MM_CONNECTION_ERROR) ||
+ (normalized_error->domain == MM_SERIAL_ERROR) ||
+ (normalized_error->domain == MM_MESSAGE_ERROR) ||
+ (normalized_error->domain == MM_CDMA_ACTIVATION_ERROR) ||
+ g_error_matches (normalized_error, G_IO_ERROR, G_IO_ERROR_CANCELLED));
+
+ g_assert (expect_fallback == g_error_matches (normalized_error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED));
+}
+
+static void
+test_error_helpers_normalize (void)
+{
+ normalize_and_assert_mm_error (TRUE, G_IO_ERROR, G_IO_ERROR_FAILED, "GIO error");
+ normalize_and_assert_mm_error (FALSE, G_IO_ERROR, G_IO_ERROR_CANCELLED, "GIO error cancelled");
+
+ normalize_and_assert_mm_error (TRUE, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Known core error"); /* This is exactly the fallback */
+ normalize_and_assert_mm_error (TRUE, MM_CORE_ERROR, 123456, "Unknown core error");
+
+ normalize_and_assert_mm_error (FALSE, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_NO_NETWORK, "Known ME error");
+ normalize_and_assert_mm_error (TRUE, MM_MOBILE_EQUIPMENT_ERROR, 123456789, "Unknown ME error");
+
+ normalize_and_assert_mm_error (FALSE, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_CARRIER, "Known connection error");
+ normalize_and_assert_mm_error (TRUE, MM_CONNECTION_ERROR, 123456, "Unknown connection error");
+
+ normalize_and_assert_mm_error (FALSE, MM_SERIAL_ERROR, MM_SERIAL_ERROR_OPEN_FAILED, "Known serial error");
+ normalize_and_assert_mm_error (TRUE, MM_SERIAL_ERROR, 123456, "Unknown serial error");
+
+ normalize_and_assert_mm_error (FALSE, MM_MESSAGE_ERROR, MM_MESSAGE_ERROR_ME_FAILURE, "Known message error");
+ normalize_and_assert_mm_error (TRUE, MM_MESSAGE_ERROR, 123456, "Unknown message error");
+
+ normalize_and_assert_mm_error (FALSE, MM_CDMA_ACTIVATION_ERROR, MM_CDMA_ACTIVATION_ERROR_ROAMING, "Known CDMA activation error");
+ normalize_and_assert_mm_error (TRUE, MM_CDMA_ACTIVATION_ERROR, 123456, "Unknown CDMA activation error");
+
+#if defined WITH_QMI
+ normalize_and_assert_mm_error (TRUE, QMI_CORE_ERROR, QMI_CORE_ERROR_TIMEOUT, "Known QMI core error");
+ normalize_and_assert_mm_error (TRUE, QMI_CORE_ERROR, 123456, "Unknown QMI core error");
+
+ normalize_and_assert_mm_error (TRUE, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_ABORTED, "Known QMI protocol error");
+ normalize_and_assert_mm_error (TRUE, QMI_PROTOCOL_ERROR, 123456, "Unknown QMI protocol error");
+#endif
+
+#if defined WITH_MBIM
+ normalize_and_assert_mm_error (TRUE, MBIM_CORE_ERROR, MBIM_CORE_ERROR_ABORTED, "Known MBIM core error");
+ normalize_and_assert_mm_error (TRUE, MBIM_CORE_ERROR, 123456, "Unknown MBIM core error");
+
+ normalize_and_assert_mm_error (TRUE, MBIM_PROTOCOL_ERROR, MBIM_PROTOCOL_ERROR_CANCEL, "Known MBIM protocol error");
+ normalize_and_assert_mm_error (TRUE, MBIM_PROTOCOL_ERROR, 123456, "Unknown MBIM protocol error");
+
+ normalize_and_assert_mm_error (TRUE, MBIM_STATUS_ERROR, MBIM_STATUS_ERROR_BUSY, "Known MBIM status error");
+ normalize_and_assert_mm_error (TRUE, MBIM_STATUS_ERROR, 123456, "Unknown MBIM status error");
+#endif
+}
+
+/*****************************************************************************/
+
int main (int argc, char **argv)
{
setlocale (LC_ALL, "");
@@ -147,5 +229,7 @@ int main (int argc, char **argv)
g_test_add_func ("/MM/error-helpers/mobile-equipment-error/for-string", test_error_helpers_mobile_equipment_error_for_string);
g_test_add_func ("/MM/error-helpers/message-error/for-string", test_error_helpers_message_error_for_string);
+ g_test_add_func ("/MM/error-helpers/normalize", test_error_helpers_normalize);
+
return g_test_run ();
}