aboutsummaryrefslogtreecommitdiff
path: root/src/mm-sim.c
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2011-11-22 18:43:33 +0100
committerAleksander Morgado <aleksander@lanedo.com>2012-03-15 14:14:23 +0100
commite3e3b32b0a2586ab0d507b7cee4721fdc9257169 (patch)
tree8087128583402073cc6c13006102e41bce375630 /src/mm-sim.c
parentbdd1d23ed25cf9539db13052547cce7a62db840c (diff)
sim: load OperatorIdentifier during init
Diffstat (limited to 'src/mm-sim.c')
-rw-r--r--src/mm-sim.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/src/mm-sim.c b/src/mm-sim.c
index 3935e0f0..4d238c95 100644
--- a/src/mm-sim.c
+++ b/src/mm-sim.c
@@ -300,12 +300,152 @@ load_imsi (MMSim *self,
}
/*****************************************************************************/
+/* Operator ID */
+
+static gboolean
+parse_mnc_length (MMSim *self,
+ gpointer none,
+ const gchar *command,
+ const gchar *response,
+ const GError *error,
+ GVariant **result,
+ GError **result_error)
+{
+ gint sw1;
+ gint sw2;
+ gboolean success = FALSE;
+ gchar hex[51];
+
+ if (error) {
+ *result_error = g_error_copy (error);
+ return FALSE;
+ }
+
+ memset (hex, 0, sizeof (hex));
+ if (sscanf (response, "+CRSM:%d,%d,\"%50c\"", &sw1, &sw2, (char *) &hex) == 3)
+ success = TRUE;
+ else {
+ /* May not include quotes... */
+ if (sscanf (response, "+CRSM:%d,%d,%50c", &sw1, &sw2, (char *) &hex) == 3)
+ success = TRUE;
+ }
+
+ if (!success) {
+ *result_error = g_error_new_literal (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Could not parse the CRSM response");
+ return FALSE;
+ }
+
+ if ((sw1 == 0x90 && sw2 == 0x00) ||
+ (sw1 == 0x91) ||
+ (sw1 == 0x92) ||
+ (sw1 == 0x9f)) {
+ gsize buflen = 0;
+ guint32 mnc_len;
+ gchar *bin;
+
+ /* Make sure the buffer is only hex characters */
+ while (buflen < sizeof (hex) && hex[buflen]) {
+ if (!isxdigit (hex[buflen])) {
+ hex[buflen] = 0x0;
+ break;
+ }
+ buflen++;
+ }
+
+ /* Convert hex string to binary */
+ bin = utils_hexstr2bin (hex, &buflen);
+ if (!bin || buflen < 4) {
+ *result_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "SIM returned malformed response '%s'",
+ hex);
+ g_free (bin);
+ return FALSE;
+ }
+
+ /* MNC length is byte 4 of this SIM file */
+ mnc_len = bin[3] & 0xFF;
+ if (mnc_len == 2 || mnc_len == 3) {
+ *result = g_variant_new_uint32 (mnc_len);
+ g_free (bin);
+ return TRUE;
+ }
+
+ *result_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "SIM returned invalid MNC length %d (should be either 2 or 3)",
+ mnc_len);
+ g_free (bin);
+ return FALSE;
+ }
+
+ *result_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "SIM failed to handle CRSM request (sw1 %d sw2 %d)",
+ sw1, sw2);
+ return FALSE;
+}
+
+static gchar *
+load_operator_identifier_finish (MMSim *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ GVariant *result;
+ gchar *operator_id;
+ const gchar *imsi;
+
+ result = mm_at_command_finish (G_OBJECT (self), res, error);
+ if (!result)
+ return NULL;
+
+ imsi = mm_gdbus_sim_get_imsi (MM_GDBUS_SIM (self));
+ if (!imsi) {
+ g_variant_unref (result);
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Cannot load Operator ID without IMSI");
+ return NULL;
+ }
+
+ /* Build Operator ID */
+ operator_id = g_strndup (imsi,
+ 3 + g_variant_get_uint32 (result));
+ g_variant_unref (result);
+ return operator_id;
+}
+
+static void
+load_operator_identifier (MMSim *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ mm_dbg ("loading Operator ID...");
+
+ /* READ BINARY of EFad (Administrative Data) ETSI 51.011 section 10.3.18 */
+ mm_at_command (G_OBJECT (self),
+ mm_base_modem_get_port_primary (MM_BASE_MODEM (self->priv->modem)),
+ "+CRSM=176,28589,0,0,4",
+ 3,
+ (MMAtResponseProcessor)parse_mnc_length,
+ NULL, /* response_processor_context */
+ "u", /* mnc length */
+ NULL, /*TODO: cancellable */
+ callback,
+ user_data);
+}
+
+/*****************************************************************************/
typedef enum {
INITIALIZATION_STEP_FIRST,
INITIALIZATION_STEP_SIM_IDENTIFIER,
INITIALIZATION_STEP_IMSI,
+ INITIALIZATION_STEP_OPERATOR_ID,
INITIALIZATION_STEP_LAST
} InitializationStep;
@@ -408,6 +548,7 @@ load_sim_identifier_ready (MMSim *self,
}
STR_REPLY_READY_FN (imsi, "IMSI")
+STR_REPLY_READY_FN (operator_identifier, "Operator identifier")
static void
interface_initialization_step (InitAsyncContext *ctx)
@@ -443,6 +584,19 @@ interface_initialization_step (InitAsyncContext *ctx)
}
break;
+ case INITIALIZATION_STEP_OPERATOR_ID:
+ /* Operator ID is meant to be loaded only once during the whole
+ * lifetime of the modem. Therefore, if we already have them loaded,
+ * don't try to load them again. */
+ if (mm_gdbus_sim_get_operator_identifier (MM_GDBUS_SIM (ctx->self)) == NULL) {
+ load_operator_identifier (
+ ctx->self,
+ (GAsyncReadyCallback)load_operator_identifier_ready,
+ ctx);
+ return;
+ }
+ break;
+
case INITIALIZATION_STEP_LAST:
/* We are done without errors! */
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);