sim: load emergency numbers from EF_ECC

This commit is contained in:
Aleksander Morgado
2019-09-25 11:28:53 +02:00
parent 1f6c006976
commit d6f9d5e9ec
4 changed files with 197 additions and 1 deletions

View File

@@ -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 * static gchar *
parse_iccid (const gchar *response, 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_identifier_finish = load_operator_identifier_finish;
klass->load_operator_name = load_operator_name; klass->load_operator_name = load_operator_name;
klass->load_operator_name_finish = load_operator_name_finish; 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 = send_pin;
klass->send_pin_finish = common_send_pin_puk_finish; klass->send_pin_finish = common_send_pin_puk_finish;
klass->send_puk = send_puk; klass->send_puk = send_puk;

View File

@@ -4352,6 +4352,70 @@ mm_3gpp_parse_operator_id (const gchar *operator_id,
return TRUE; return TRUE;
} }
/*************************************************************************/
/* 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 gboolean

View File

@@ -445,6 +445,8 @@ gboolean mm_3gpp_rsrp_level_to_rsrp (guint rsrp_level,
gboolean mm_3gpp_rssnr_level_to_rssnr (gint rssnr_level, gboolean mm_3gpp_rssnr_level_to_rssnr (gint rssnr_level,
gdouble *out_rssnr); gdouble *out_rssnr);
GStrv mm_3gpp_parse_emergency_numbers (const char *raw, GError **error);
/*****************************************************************************/ /*****************************************************************************/
/* CDMA specific helpers and utilities */ /* CDMA specific helpers and utilities */
/*****************************************************************************/ /*****************************************************************************/

View File

@@ -4337,6 +4337,55 @@ test_clcc_response_multiple (void)
common_test_clcc_response (response, expected_call_info_list, G_N_ELEMENTS (expected_call_info_list)); common_test_clcc_response (response, expected_call_info_list, G_N_ELEMENTS (expected_call_info_list));
} }
/*****************************************************************************/
/* 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 { typedef struct {
@@ -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_single_long, NULL));
g_test_suite_add (suite, TESTCASE (test_clcc_response_multiple, 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_parse_uint_list, NULL));
g_test_suite_add (suite, TESTCASE (test_bcd_to_string, NULL)); g_test_suite_add (suite, TESTCASE (test_bcd_to_string, NULL));