aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/intel/mm-sim-xmm7360.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/intel/mm-sim-xmm7360.c')
-rw-r--r--src/plugins/intel/mm-sim-xmm7360.c445
1 files changed, 445 insertions, 0 deletions
diff --git a/src/plugins/intel/mm-sim-xmm7360.c b/src/plugins/intel/mm-sim-xmm7360.c
new file mode 100644
index 00000000..912e66e8
--- /dev/null
+++ b/src/plugins/intel/mm-sim-xmm7360.c
@@ -0,0 +1,445 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2024 Thomas Vogt
+ */
+
+#include "mm-broadband-modem-xmm7360.h"
+#include "mm-broadband-modem-xmm7360-rpc.h"
+#include "mm-log-object.h"
+#include "mm-sim-xmm7360.h"
+
+G_DEFINE_TYPE (MMSimXmm7360, mm_sim_xmm7360, MM_TYPE_BASE_SIM)
+
+#define PIN_PADDED { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
+#define PIN_PADDED_SIZE 8
+
+static void
+copy_pin (const gchar *pin, gchar *pin_padded)
+{
+ gsize i;
+
+ for (i = 0; pin[i] != 0 && i < PIN_PADDED_SIZE; i++)
+ pin_padded[i] = pin[i];
+}
+
+static void
+update_modem_unlock_retries (MMSimXmm7360 *self,
+ MMModemLock lock_type,
+ guint32 remaining_attempts)
+{
+ g_autoptr(MMBaseModem) modem = NULL;
+
+ g_object_get (G_OBJECT (self),
+ MM_BASE_SIM_MODEM, &modem,
+ NULL);
+ g_assert (MM_IS_BASE_MODEM (modem));
+
+ mm_broadband_modem_xmm7360_set_unlock_retries (MM_BROADBAND_MODEM_XMM7360 (modem),
+ lock_type,
+ remaining_attempts);
+ g_object_unref (modem);
+}
+
+/*****************************************************************************/
+/* Enable PIN */
+
+static gboolean
+enable_pin_finish (MMBaseSim *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+gen_pin_enable_ready (MMBroadbandModem *modem,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMSimXmm7360 *self;
+ GError *error = NULL;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+ Xmm7360RpcMsgArg *arg;
+ guint8 err_code_1;
+ guint8 err_code_2;
+ guint32 remaining_attempts;
+ Xmm7360GenPinOp op;
+ MMModemLock lock_type;
+
+ self = g_task_get_source_object (task);
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (MM_BROADBAND_MODEM_XMM7360 (modem),
+ res,
+ &error);
+
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 2);
+ remaining_attempts = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 3);
+ err_code_1 = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 4);
+ err_code_2 = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 7);
+ op = (Xmm7360GenPinOp) XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ lock_type = remaining_attempts > 0 ? MM_MODEM_LOCK_SIM_PIN : MM_MODEM_LOCK_SIM_PUK;
+ update_modem_unlock_retries (self, lock_type, remaining_attempts);
+
+ if (err_code_1 == 0x83 && err_code_2 == 0x69) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "%s PIN failed (need to unlock PUK first)",
+ op == XMM7360_GEN_PIN_OP_ENABLE ? "Enabling" : "Disabling");
+ g_object_unref (task);
+ return;
+ } else if (err_code_1 == 0x84 && err_code_2 == 0x69) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "%s PIN failed (already %s)",
+ op == XMM7360_GEN_PIN_OP_ENABLE ? "Enabling" : "Disabling",
+ op == XMM7360_GEN_PIN_OP_ENABLE ? "enabled" : "disabled");
+ g_object_unref (task);
+ return;
+ } else if (err_code_2 == 0x63 && (err_code_1 == 0xc2 || err_code_1 == 0xc1 || err_code_1 == 0xc0)) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "%s PIN failed (wrong PIN, %d retries left)",
+ op == XMM7360_GEN_PIN_OP_ENABLE ? "Enabling" : "Disabling",
+ remaining_attempts);
+ g_object_unref (task);
+ return;
+ } else if (err_code_1 != 0x00 || err_code_2 != 0x90) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "%s PIN failed (unknown error: 0x%02x, 0x%02x)",
+ op == XMM7360_GEN_PIN_OP_ENABLE ? "Enabling" : "Disabling",
+ err_code_1, err_code_2);
+ g_object_unref (task);
+ return;
+ }
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static GByteArray *
+padded_pack_gen_pin_enable (const gchar *pin_padded, const Xmm7360GenPinOp op)
+{
+ const Xmm7360RpcMsgArg args[] = {
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = op } },
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 1 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = pin_padded }, 8, 2 },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN },
+ };
+ return xmm7360_rpc_args_to_byte_array (args);
+}
+
+static GByteArray *
+pack_gen_pin_enable (const gchar *pin, gboolean enabled)
+{
+ gchar pin_padded[] = PIN_PADDED;
+ copy_pin (pin, pin_padded);
+ return padded_pack_gen_pin_enable (
+ pin_padded,
+ enabled ? XMM7360_GEN_PIN_OP_ENABLE : XMM7360_GEN_PIN_OP_DISABLE
+ );
+}
+
+static void
+enable_pin (MMBaseSim *self,
+ const gchar *pin,
+ gboolean enabled,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ g_autoptr(MMBaseModem) modem = NULL;
+ MMPortSerialXmmrpcXmm7360 *port;
+ g_autoptr(GByteArray) body = NULL;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ g_object_get (G_OBJECT (self),
+ MM_BASE_SIM_MODEM, &modem,
+ NULL);
+ g_assert (MM_IS_BASE_MODEM (modem));
+
+ port = mm_broadband_modem_xmm7360_peek_port_xmmrpc (MM_BROADBAND_MODEM_XMM7360 (modem));
+ g_object_unref (modem);
+
+ if (!port) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Couldn't peek XMMRPC port");
+ g_object_unref (task);
+ return;
+ }
+
+ body = pack_gen_pin_enable (pin, enabled);
+
+ mm_broadband_modem_xmm7360_rpc_command_full (MM_BROADBAND_MODEM_XMM7360 (modem),
+ port,
+ XMM7360_RPC_CALL_UTA_MS_SIM_GEN_PIN_REQ,
+ TRUE,
+ body,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)gen_pin_enable_ready,
+ task);
+}
+
+/*****************************************************************************/
+/* Change PIN */
+
+static gboolean
+change_pin_finish (MMBaseSim *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+gen_pin_change_ready (MMBroadbandModem *modem,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMSimXmm7360 *self;
+ GError *error = NULL;
+ g_autoptr(Xmm7360RpcResponse) response = NULL;
+ Xmm7360RpcMsgArg *arg;
+ guint8 err_code_1;
+ guint8 err_code_2;
+ guint32 remaining_attempts;
+ MMModemLock lock_type;
+
+ self = g_task_get_source_object (task);
+
+ response = mm_broadband_modem_xmm7360_rpc_command_finish (MM_BROADBAND_MODEM_XMM7360 (modem),
+ res,
+ &error);
+
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+
+ if (response->content->len < 10) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Changing PIN failed (response too short)");
+ g_object_unref (task);
+ return;
+ }
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 2);
+ remaining_attempts = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 3);
+ err_code_1 = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ arg = (Xmm7360RpcMsgArg *) g_ptr_array_index (response->content, 4);
+ err_code_2 = XMM7360_RPC_MSG_ARG_GET_INT (arg);
+
+ lock_type = remaining_attempts > 0 ? MM_MODEM_LOCK_SIM_PIN : MM_MODEM_LOCK_SIM_PUK;
+ update_modem_unlock_retries (self, lock_type, remaining_attempts);
+
+ if (err_code_1 == 0x83 && err_code_2 == 0x69) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Changing PIN failed (need to unlock PUK first)");
+ g_object_unref (task);
+ return;
+ } else if (err_code_1 == 0x84 && err_code_2 == 0x69) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Changing PIN failed (PIN lock is disabled)");
+ g_object_unref (task);
+ return;
+ } else if (err_code_2 == 0x63 && (err_code_1 == 0xc2 || err_code_1 == 0xc1 || err_code_1 == 0xc0)) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Changing PIN failed (wrong PIN, %d retries left)",
+ remaining_attempts);
+ g_object_unref (task);
+ return;
+ } else if (err_code_1 != 0x00 || err_code_2 != 0x90) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Changing PIN failed (unknown error: 0x%02x, 0x%02x)",
+ err_code_1, err_code_2);
+ g_object_unref (task);
+ return;
+ }
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static GByteArray *
+padded_pack_gen_pin_change (const gchar *old_pin_padded, const gchar *new_pin_padded)
+{
+ const Xmm7360RpcMsgArg args[] = {
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = XMM7360_GEN_PIN_OP_CHANGE } },
+ { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 1 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = new_pin_padded }, 8, 2},
+ { XMM7360_RPC_MSG_ARG_TYPE_STRING, { .string = old_pin_padded }, 8, 2},
+ { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
+ { XMM7360_RPC_MSG_ARG_TYPE_UNKNOWN },
+ };
+ return xmm7360_rpc_args_to_byte_array (args);
+}
+
+static GByteArray *
+pack_gen_pin_change (const gchar *old_pin, const gchar *new_pin)
+{
+ gchar old_pin_padded[] = PIN_PADDED;
+ gchar new_pin_padded[] = PIN_PADDED;
+ copy_pin (old_pin, old_pin_padded);
+ copy_pin (new_pin, new_pin_padded);
+ return padded_pack_gen_pin_change (old_pin_padded, new_pin_padded);
+}
+
+static void
+change_pin (MMBaseSim *self,
+ const gchar *old_pin,
+ const gchar *new_pin,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ g_autoptr(MMBaseModem) modem = NULL;
+ MMPortSerialXmmrpcXmm7360 *port;
+ g_autoptr(GByteArray) body = NULL;
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ g_object_get (G_OBJECT (self),
+ MM_BASE_SIM_MODEM, &modem,
+ NULL);
+ g_assert (MM_IS_BASE_MODEM (modem));
+
+ port = mm_broadband_modem_xmm7360_peek_port_xmmrpc (MM_BROADBAND_MODEM_XMM7360 (modem));
+ g_object_unref (modem);
+
+ if (!port) {
+ g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Couldn't peek XMMRPC port");
+ g_object_unref (task);
+ return;
+ }
+
+ body = pack_gen_pin_change (old_pin, new_pin);
+
+ mm_broadband_modem_xmm7360_rpc_command_full (MM_BROADBAND_MODEM_XMM7360 (modem),
+ port,
+ XMM7360_RPC_CALL_UTA_MS_SIM_GEN_PIN_REQ,
+ TRUE,
+ body,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)gen_pin_change_ready,
+ task);
+}
+
+/*****************************************************************************/
+
+MMBaseSim *
+mm_sim_xmm7360_new_finish (GAsyncResult *res,
+ GError **error)
+{
+ GObject *source;
+ GObject *sim;
+
+ source = g_async_result_get_source_object (res);
+ sim = g_async_initable_new_finish (G_ASYNC_INITABLE (source), res, error);
+ g_object_unref (source);
+
+ if (!sim)
+ return NULL;
+
+ /* Only export valid SIMs */
+ mm_base_sim_export (MM_BASE_SIM (sim));
+
+ return MM_BASE_SIM (sim);
+}
+
+void
+mm_sim_xmm7360_new (MMBaseModem *modem,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_async_initable_new_async (MM_TYPE_SIM_XMM7360,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ callback,
+ user_data,
+ MM_BASE_SIM_MODEM, modem,
+ "active", TRUE, /* by default always active */
+ NULL);
+}
+
+MMBaseSim *
+mm_sim_xmm7360_new_initialized (MMBaseModem *modem,
+ guint slot_number,
+ gboolean active,
+ MMSimType sim_type,
+ MMSimEsimStatus esim_status,
+ const gchar *sim_identifier,
+ const gchar *imsi,
+ const gchar *eid,
+ const gchar *operator_identifier,
+ const gchar *operator_name,
+ const GStrv emergency_numbers)
+{
+ MMBaseSim *sim;
+
+ sim = MM_BASE_SIM (g_object_new (MM_TYPE_SIM_XMM7360,
+ MM_BASE_SIM_MODEM, modem,
+ MM_BASE_SIM_SLOT_NUMBER, slot_number,
+ "active", active,
+ "sim-type", sim_type,
+ "esim-status", esim_status,
+ "sim-identifier", sim_identifier,
+ "eid", eid,
+ "operator-identifier", operator_identifier,
+ "operator-name", operator_name,
+ "emergency-numbers", emergency_numbers,
+ NULL));
+
+ mm_base_sim_export (sim);
+ return sim;
+}
+
+static void
+mm_sim_xmm7360_init (MMSimXmm7360 *self)
+{
+}
+
+static void
+mm_sim_xmm7360_class_init (MMSimXmm7360Class *klass)
+{
+ MMBaseSimClass *base_sim_class = MM_BASE_SIM_CLASS (klass);
+
+ base_sim_class->enable_pin = enable_pin;
+ base_sim_class->enable_pin_finish = enable_pin_finish;
+ base_sim_class->change_pin = change_pin;
+ base_sim_class->change_pin_finish = change_pin_finish;
+}