aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksandermj@chromium.org>2023-10-25 16:59:22 +0000
committerAleksander Morgado <aleksandermj@chromium.org>2023-10-26 12:35:50 +0000
commit81d2655950a3fc2381c81708074f10e665e75660 (patch)
tree4d39bf45a354351b0fe1725d1c673eee8c6d91d9
parent59aae421a1169ff77edb8f83e6f078b09ca20ce0 (diff)
error-helpers: allow registering error mappings
E.g. from QMI/MBIM errors into MM errors.
-rw-r--r--src/mm-error-helpers.c111
-rw-r--r--src/mm-error-helpers.h4
2 files changed, 113 insertions, 2 deletions
diff --git a/src/mm-error-helpers.c b/src/mm-error-helpers.c
index 81fc995c..daa1e550 100644
--- a/src/mm-error-helpers.c
+++ b/src/mm-error-helpers.c
@@ -519,6 +519,113 @@ cdma_activation_error_get_string (MMCdmaActivationError code)
}
/******************************************************************************/
+/* Registered error mappings */
+
+typedef struct {
+ GQuark error_domain;
+ gint error_code;
+} DomainCodePair;
+
+static guint
+domain_code_pair_hash_func (const DomainCodePair *pair)
+{
+ gint64 val;
+
+ /* The value of the GQuark error domain is selected during runtime based on the amount of
+ * error types that are registered in the type system. */
+ val = ((gint64)pair->error_domain << 31) | pair->error_code;
+ return g_int64_hash (&val);
+}
+
+static gboolean
+domain_code_pair_equal_func (const DomainCodePair *a,
+ const DomainCodePair *b)
+{
+ return (a->error_domain == b->error_domain) && (a->error_code == b->error_code);
+}
+
+static void
+domain_code_pair_free (DomainCodePair *pair)
+{
+ g_slice_free (DomainCodePair, pair);
+}
+
+/* Map of a input domain/code error to an output domain/code error. This HT exists
+ * for as long as the process is running, it is not explicitly freed on exit. */
+static GHashTable *error_mappings;
+
+void
+mm_register_error_mapping (GQuark input_error_domain,
+ gint input_error_code,
+ GQuark output_error_domain,
+ gint output_error_code)
+{
+ DomainCodePair *input;
+ DomainCodePair *output;
+
+ if (G_UNLIKELY (!error_mappings))
+ error_mappings = g_hash_table_new_full ((GHashFunc)domain_code_pair_hash_func,
+ (GEqualFunc)domain_code_pair_equal_func,
+ (GDestroyNotify)domain_code_pair_free,
+ (GDestroyNotify)domain_code_pair_free);
+
+ input = g_slice_new0 (DomainCodePair);
+ input->error_domain = input_error_domain;
+ input->error_code = input_error_code;
+
+ /* ensure no other error is registered with the same hash, we don't want or
+ * expect dupicates*/
+ g_assert (!g_hash_table_lookup (error_mappings, input));
+
+ output = g_slice_new0 (DomainCodePair);
+ output->error_domain = output_error_domain;
+ output->error_code = output_error_code;
+
+ g_hash_table_insert (error_mappings, input, output);
+}
+
+static GError *
+normalize_mapped_error (const GError *error)
+{
+ DomainCodePair *output = NULL;
+ const gchar *input_error_type;
+
+#if defined WITH_QMI
+ if (error->domain == QMI_CORE_ERROR)
+ input_error_type = "QMI core";
+ else if (error->domain == QMI_PROTOCOL_ERROR)
+ input_error_type = "QMI protocol";
+ else
+#endif
+#if defined WITH_MBIM
+ if (error->domain == MBIM_CORE_ERROR)
+ input_error_type = "MBIM core";
+ else if (error->domain == MBIM_PROTOCOL_ERROR)
+ input_error_type = "MBIM protocol";
+ else if (error->domain == MBIM_STATUS_ERROR)
+ input_error_type = "MBIM status";
+ else
+#endif
+ input_error_type = "unknown domain";
+
+ if (error_mappings) {
+ DomainCodePair input;
+
+ input.error_domain = error->domain;
+ input.error_code = error->code;
+ output = g_hash_table_lookup (error_mappings, &input);
+ }
+
+ if (!output)
+ return g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Unhandled %s error (%u): %s",
+ input_error_type, error->code, error->message);
+
+ return g_error_new (output->error_domain, output->error_code,
+ "%s error: %s", input_error_type, error->message);
+}
+
+/******************************************************************************/
/* Takes a GError of any kind and ensures that the returned GError is a
* MM-defined one. */
@@ -570,6 +677,6 @@ mm_normalize_error (const GError *error)
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);
+ /* Normalize mapped errors */
+ return normalize_mapped_error (error);
}
diff --git a/src/mm-error-helpers.h b/src/mm-error-helpers.h
index d0effac7..ec1c2c6b 100644
--- a/src/mm-error-helpers.h
+++ b/src/mm-error-helpers.h
@@ -29,5 +29,9 @@ GError *mm_mobile_equipment_error_for_string (const gchar *str, gpo
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);
+void mm_register_error_mapping (GQuark input_error_domain,
+ gint input_error_code,
+ GQuark output_error_domain,
+ gint output_error_code);
#endif /* MM_ERROR_HELPERS_H */