aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2019-09-25 11:28:53 +0200
committerAleksander Morgado <aleksander@aleksander.es>2019-10-17 10:51:50 +0200
commitd6f9d5e9ec36e403be9836c55c8ffd19422605ef (patch)
tree04252ff9a7d3d8bf2bda8b1fb102a5f3873eb4ed
parent1f6c006976211111c1ccdbe7cbbd146c8338ba38 (diff)
sim: load emergency numbers from EF_ECC
-rw-r--r--src/mm-base-sim.c81
-rw-r--r--src/mm-modem-helpers.c64
-rw-r--r--src/mm-modem-helpers.h2
-rw-r--r--src/tests/test-modem-helpers.c51
4 files changed, 197 insertions, 1 deletions
diff --git a/src/mm-base-sim.c b/src/mm-base-sim.c
index 1bd6a5c5..acb44125 100644
--- a/src/mm-base-sim.c
+++ b/src/mm-base-sim.c
@@ -973,7 +973,84 @@ mm_base_sim_get_path (MMBaseSim *self)
}
/*****************************************************************************/
-/* SIM IDENTIFIER */
+/* Emergency numbers */
+
+static GStrv
+parse_emergency_numbers (const gchar *response,
+ GError **error)
+{
+ guint sw1 = 0;
+ guint sw2 = 0;
+ gchar *hex = 0;
+ GStrv ret;
+
+ if (!mm_3gpp_parse_crsm_response (response, &sw1, &sw2, &hex, error))
+ return NULL;
+
+ if ((sw1 == 0x90 && sw2 == 0x00) ||
+ (sw1 == 0x91) ||
+ (sw1 == 0x92) ||
+ (sw1 == 0x9f)) {
+ ret = mm_3gpp_parse_emergency_numbers (hex, error);
+ g_free (hex);
+ return ret;
+ }
+
+ g_free (hex);
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "SIM failed to handle CRSM request (sw1 %d sw2 %d)",
+ sw1, sw2);
+ return NULL;
+}
+
+static GStrv
+load_emergency_numbers_finish (MMBaseSim *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ gchar *result;
+ GStrv emergency_numbers;
+ guint i;
+
+ result = g_task_propagate_pointer (G_TASK (res), error);
+ if (!result)
+ return NULL;
+
+ emergency_numbers = parse_emergency_numbers (result, error);
+ g_free (result);
+
+ if (!emergency_numbers)
+ return NULL;
+
+ for (i = 0; emergency_numbers[i]; i++)
+ mm_dbg ("loaded emergency number: %s", emergency_numbers[i]);
+
+ return emergency_numbers;
+}
+
+STR_REPLY_READY_FN (load_emergency_numbers)
+
+static void
+load_emergency_numbers (MMBaseSim *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ mm_dbg ("loading emergency numbers...");
+
+ /* READ BINARY of EF_ECC (Emergency Call Codes) ETSI TS 51.011 section 10.3.27 */
+ mm_base_modem_at_command (
+ self->priv->modem,
+ "+CRSM=176,28599,0,0,15",
+ 20,
+ FALSE,
+ (GAsyncReadyCallback)load_emergency_numbers_command_ready,
+ g_task_new (self, NULL, callback, user_data));
+}
+
+/*****************************************************************************/
+/* ICCID */
static gchar *
parse_iccid (const gchar *response,
@@ -1784,6 +1861,8 @@ mm_base_sim_class_init (MMBaseSimClass *klass)
klass->load_operator_identifier_finish = load_operator_identifier_finish;
klass->load_operator_name = load_operator_name;
klass->load_operator_name_finish = load_operator_name_finish;
+ klass->load_emergency_numbers = load_emergency_numbers;
+ klass->load_emergency_numbers_finish = load_emergency_numbers_finish;
klass->send_pin = send_pin;
klass->send_pin_finish = common_send_pin_puk_finish;
klass->send_puk = send_puk;
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index 69e8823e..ec07aada 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -4353,6 +4353,70 @@ mm_3gpp_parse_operator_id (const gchar *operator_id,
}
/*************************************************************************/
+/* Emergency numbers (+CRSM output) */
+
+GStrv
+mm_3gpp_parse_emergency_numbers (const char *raw, GError **error)
+{
+ gsize rawlen;
+ guint8 *bin;
+ gsize binlen;
+ gsize max_items;
+ GPtrArray *out;
+ guint i;
+
+ /* The emergency call code is of a variable length with a maximum length of
+ * 6 digits. Each emergency call code is coded on three bytes, with each
+ * digit within the code being coded on four bits. If a code of less that 6
+ * digits is chosen, then the unused nibbles shall be set to 'F'. */
+
+ rawlen = strlen (raw);
+ if (!rawlen) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "empty emergency numbers list");
+ return NULL;
+ }
+
+ if (rawlen % 6 != 0) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "invalid raw emergency numbers list length: %" G_GSIZE_FORMAT, rawlen);
+ return NULL;
+ }
+
+ bin = (guint8 *) mm_utils_hexstr2bin (raw, &binlen);
+ if (!bin) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "invalid raw emergency numbers list contents: %s", raw);
+ return NULL;
+ }
+
+ max_items = binlen / 3;
+ out = g_ptr_array_sized_new (max_items + 1);
+
+ for (i = 0; i < max_items; i++) {
+ gchar *number;
+
+ number = mm_bcd_to_string (&bin[i*3], 3);
+ if (number && number[0])
+ g_ptr_array_add (out, number);
+ else
+ g_free (number);
+ }
+
+ g_free (bin);
+
+ if (!out->len) {
+ g_ptr_array_unref (out);
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "uninitialized emergency numbers list");
+ return NULL;
+ }
+
+ g_ptr_array_add (out, NULL);
+ return (GStrv) g_ptr_array_free (out, FALSE);
+}
+
+/*************************************************************************/
gboolean
mm_cdma_parse_spservice_read_response (const gchar *reply,
diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
index 73a13ddd..28a69996 100644
--- a/src/mm-modem-helpers.h
+++ b/src/mm-modem-helpers.h
@@ -445,6 +445,8 @@ gboolean mm_3gpp_rsrp_level_to_rsrp (guint rsrp_level,
gboolean mm_3gpp_rssnr_level_to_rssnr (gint rssnr_level,
gdouble *out_rssnr);
+GStrv mm_3gpp_parse_emergency_numbers (const char *raw, GError **error);
+
/*****************************************************************************/
/* CDMA specific helpers and utilities */
/*****************************************************************************/
diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c
index ea693079..0e63e41f 100644
--- a/src/tests/test-modem-helpers.c
+++ b/src/tests/test-modem-helpers.c
@@ -4338,6 +4338,55 @@ test_clcc_response_multiple (void)
}
/*****************************************************************************/
+/* Test +CRSM EF_ECC read data parsing */
+
+#define MAX_EMERGENCY_NUMBERS 5
+typedef struct {
+ const gchar *raw;
+ guint n_numbers;
+ gchar *numbers[MAX_EMERGENCY_NUMBERS];
+} EmergencyNumbersTest;
+
+static const EmergencyNumbersTest emergency_numbers_tests[] = {
+ { "", 0 },
+ { "FFF", 0 },
+ { "FFFFFF" "FFFFFF" "FFFFFF" "FFFFFF" "FFFFFF", 0 },
+ { "00F0FF" "11F2FF" "88F8FF", 3, { "000", "112", "888" } },
+ { "00F0FF" "11F2FF" "88F8FF" "FFFFFF" "FFFFFF", 3, { "000", "112", "888" } },
+ { "00F0FF" "11F2FF" "88F8FF" "214365" "08FFFF", 5, { "000", "112", "888", "123456", "80" } },
+};
+
+static void
+test_emergency_numbers (void)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (emergency_numbers_tests); i++) {
+ GStrv numbers;
+ GError *error = NULL;
+ guint j;
+
+ g_debug (" testing %s...", emergency_numbers_tests[i].raw);
+
+ numbers = mm_3gpp_parse_emergency_numbers (emergency_numbers_tests[i].raw, &error);
+ if (!emergency_numbers_tests[i].n_numbers) {
+ g_assert (error);
+ g_assert (!numbers);
+ continue;
+ }
+
+ g_assert_no_error (error);
+ g_assert (numbers);
+
+ g_assert_cmpuint (emergency_numbers_tests[i].n_numbers, ==, g_strv_length (numbers));
+ for (j = 0; j < emergency_numbers_tests[i].n_numbers; j++)
+ g_assert_cmpstr (emergency_numbers_tests[i].numbers[j], ==, numbers[j]);
+
+ g_strfreev (numbers);
+ }
+}
+
+/*****************************************************************************/
typedef struct {
gchar *str;
@@ -4659,6 +4708,8 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_clcc_response_single_long, NULL));
g_test_suite_add (suite, TESTCASE (test_clcc_response_multiple, NULL));
+ g_test_suite_add (suite, TESTCASE (test_emergency_numbers, NULL));
+
g_test_suite_add (suite, TESTCASE (test_parse_uint_list, NULL));
g_test_suite_add (suite, TESTCASE (test_bcd_to_string, NULL));