|
|
|
@@ -727,6 +727,331 @@ load_operator_name (MMBaseSim *self,
|
|
|
|
|
task);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* Load preferred networks */
|
|
|
|
|
|
|
|
|
|
static GList *
|
|
|
|
|
load_preferred_networks_finish (MMBaseSim *self,
|
|
|
|
|
GAsyncResult *res,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
return g_task_propagate_pointer (G_TASK (res), error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GList *
|
|
|
|
|
parse_get_preferred_networks (QmiMessageNasGetPreferredNetworksOutput *output)
|
|
|
|
|
{
|
|
|
|
|
GList *result = NULL;
|
|
|
|
|
GArray *preferred_nets_array = NULL;
|
|
|
|
|
GArray *preferred_nets_mnc_pcs_digit_array = NULL;
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
if (qmi_message_nas_get_preferred_networks_output_get_preferred_networks (output,
|
|
|
|
|
&preferred_nets_array,
|
|
|
|
|
NULL)) {
|
|
|
|
|
qmi_message_nas_get_preferred_networks_output_get_mnc_pcs_digit_include_status (output,
|
|
|
|
|
&preferred_nets_mnc_pcs_digit_array,
|
|
|
|
|
NULL);
|
|
|
|
|
for (i = 0; i < preferred_nets_array->len; i++) {
|
|
|
|
|
QmiMessageNasGetPreferredNetworksOutputPreferredNetworksElement *net;
|
|
|
|
|
QmiMessageNasGetPreferredNetworksOutputMncPcsDigitIncludeStatusElement *mnc_pcs_digit = NULL;
|
|
|
|
|
MMSimPreferredNetwork *new_item;
|
|
|
|
|
g_autofree gchar *operator_code = NULL;
|
|
|
|
|
MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
|
|
|
|
|
|
|
|
|
|
net = &g_array_index (preferred_nets_array,
|
|
|
|
|
QmiMessageNasGetPreferredNetworksOutputPreferredNetworksElement, i);
|
|
|
|
|
if (preferred_nets_mnc_pcs_digit_array && i < preferred_nets_mnc_pcs_digit_array->len)
|
|
|
|
|
mnc_pcs_digit = &g_array_index (preferred_nets_mnc_pcs_digit_array,
|
|
|
|
|
QmiMessageNasGetPreferredNetworksOutputMncPcsDigitIncludeStatusElement, i);
|
|
|
|
|
|
|
|
|
|
new_item = mm_sim_preferred_network_new ();
|
|
|
|
|
|
|
|
|
|
if (net->mnc > 99 || (mnc_pcs_digit != NULL && mnc_pcs_digit->includes_pcs_digit))
|
|
|
|
|
operator_code = g_strdup_printf ("%03d%03d", net->mcc, net->mnc);
|
|
|
|
|
else
|
|
|
|
|
operator_code = g_strdup_printf ("%03d%02d", net->mcc, net->mnc);
|
|
|
|
|
mm_sim_preferred_network_set_operator_code (new_item, operator_code);
|
|
|
|
|
|
|
|
|
|
if (net->radio_access_technology & QMI_NAS_PLMN_ACCESS_TECHNOLOGY_IDENTIFIER_GSM)
|
|
|
|
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_GSM;
|
|
|
|
|
if (net->radio_access_technology & QMI_NAS_PLMN_ACCESS_TECHNOLOGY_IDENTIFIER_GSM_COMPACT)
|
|
|
|
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT;
|
|
|
|
|
if (net->radio_access_technology & QMI_NAS_PLMN_ACCESS_TECHNOLOGY_IDENTIFIER_UTRAN)
|
|
|
|
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_UMTS;
|
|
|
|
|
if (net->radio_access_technology & QMI_NAS_PLMN_ACCESS_TECHNOLOGY_IDENTIFIER_EUTRAN)
|
|
|
|
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_LTE;
|
|
|
|
|
if (net->radio_access_technology & QMI_NAS_PLMN_ACCESS_TECHNOLOGY_IDENTIFIER_NGRAN)
|
|
|
|
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_5GNR;
|
|
|
|
|
mm_sim_preferred_network_set_access_technology (new_item, act);
|
|
|
|
|
|
|
|
|
|
result = g_list_append (result, new_item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
load_preferred_networks_ready (QmiClientNas *client,
|
|
|
|
|
GAsyncResult *res,
|
|
|
|
|
GTask *task)
|
|
|
|
|
{
|
|
|
|
|
QmiMessageNasGetPreferredNetworksOutput *output;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
output = qmi_client_nas_get_preferred_networks_finish (client, res, &error);
|
|
|
|
|
if (!output) {
|
|
|
|
|
g_prefix_error (&error, "QMI operation failed: ");
|
|
|
|
|
g_task_return_error (task, error);
|
|
|
|
|
} else if (!qmi_message_nas_get_preferred_networks_output_get_result (output, &error)) {
|
|
|
|
|
g_prefix_error (&error, "Couldn't get preferred networks: ");
|
|
|
|
|
g_task_return_error (task, error);
|
|
|
|
|
} else
|
|
|
|
|
g_task_return_pointer (task, parse_get_preferred_networks (output), (GDestroyNotify) mm_sim_preferred_network_list_free);
|
|
|
|
|
|
|
|
|
|
if (output)
|
|
|
|
|
qmi_message_nas_get_preferred_networks_output_unref (output);
|
|
|
|
|
g_object_unref (task);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
load_preferred_networks (MMBaseSim *self,
|
|
|
|
|
GAsyncReadyCallback callback,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
GTask *task;
|
|
|
|
|
QmiClient *client = NULL;
|
|
|
|
|
|
|
|
|
|
task = g_task_new (self, NULL, callback, user_data);
|
|
|
|
|
if (!ensure_qmi_client (task,
|
|
|
|
|
MM_SIM_QMI (self),
|
|
|
|
|
QMI_SERVICE_NAS, &client))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
mm_obj_dbg (self, "loading preferred network list...");
|
|
|
|
|
qmi_client_nas_get_preferred_networks (QMI_CLIENT_NAS (client),
|
|
|
|
|
NULL,
|
|
|
|
|
5,
|
|
|
|
|
NULL,
|
|
|
|
|
(GAsyncReadyCallback)load_preferred_networks_ready,
|
|
|
|
|
task);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* Set preferred networks */
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
/* Preferred network list to be set, used for after-check comparison */
|
|
|
|
|
GList *set_list;
|
|
|
|
|
} SetPreferredNetworksContext;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
set_preferred_network_context_free (SetPreferredNetworksContext *ctx)
|
|
|
|
|
{
|
|
|
|
|
g_list_free_full (ctx->set_list, (GDestroyNotify) mm_sim_preferred_network_free);
|
|
|
|
|
g_slice_free (SetPreferredNetworksContext, ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
set_preferred_networks_finish (MMBaseSim *self,
|
|
|
|
|
GAsyncResult *res,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
return g_task_propagate_boolean (G_TASK (res), error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
set_preferred_networks_reload_ready (MMBaseSim *self,
|
|
|
|
|
GAsyncResult *res,
|
|
|
|
|
GTask *task)
|
|
|
|
|
{
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
GList *loaded_list;
|
|
|
|
|
GList *loaded_iter;
|
|
|
|
|
GList *set_iter;
|
|
|
|
|
SetPreferredNetworksContext *ctx;
|
|
|
|
|
|
|
|
|
|
ctx = g_task_get_task_data (task);
|
|
|
|
|
|
|
|
|
|
loaded_list = load_preferred_networks_finish (self, res, &error);
|
|
|
|
|
if (error) {
|
|
|
|
|
mm_obj_warn (self, "couldn't reload list of preferred networks: %s", error->message);
|
|
|
|
|
g_task_return_error (task, error);
|
|
|
|
|
g_object_unref (task);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Compare the set and loaded network list for differences */
|
|
|
|
|
loaded_iter = loaded_list;
|
|
|
|
|
set_iter = ctx->set_list;
|
|
|
|
|
|
|
|
|
|
while (loaded_iter && set_iter) {
|
|
|
|
|
const gchar *loaded_op_code;
|
|
|
|
|
const gchar *set_op_code;
|
|
|
|
|
MMModemAccessTechnology loaded_act;
|
|
|
|
|
MMModemAccessTechnology set_act;
|
|
|
|
|
|
|
|
|
|
loaded_op_code = mm_sim_preferred_network_get_operator_code (loaded_iter->data);
|
|
|
|
|
set_op_code = mm_sim_preferred_network_get_operator_code (set_iter->data);
|
|
|
|
|
loaded_act = mm_sim_preferred_network_get_access_technology (loaded_iter->data);
|
|
|
|
|
set_act = mm_sim_preferred_network_get_access_technology (set_iter->data);
|
|
|
|
|
|
|
|
|
|
/* Operator code mismatch is never expected, but check it just in case */
|
|
|
|
|
if (g_strcmp0 (loaded_op_code, set_op_code)) {
|
|
|
|
|
mm_obj_warn (self, "operator code mismatch, expected '%s' loaded '%s'",
|
|
|
|
|
set_op_code, loaded_op_code);
|
|
|
|
|
error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
|
|
|
|
"Mismatch in requested and set operator code");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
/* Check if there are access technology bits requested but unset */
|
|
|
|
|
if ((loaded_act & set_act) != set_act) {
|
|
|
|
|
MMModemAccessTechnology unset = set_act & ~loaded_act;
|
|
|
|
|
|
|
|
|
|
mm_obj_warn (self, "access technologies '%s' not set for operator code '%s'",
|
|
|
|
|
mm_modem_access_technology_build_string_from_mask (unset),
|
|
|
|
|
set_op_code);
|
|
|
|
|
error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
|
|
|
|
|
"Access technology unsupported by modem or SIM");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
loaded_iter = g_list_next (loaded_iter);
|
|
|
|
|
set_iter = g_list_next (set_iter);
|
|
|
|
|
}
|
|
|
|
|
if (!error && loaded_iter == NULL && set_iter != NULL) {
|
|
|
|
|
/* Not all networks were written; some modems silently discard networks
|
|
|
|
|
* that exceed the SIM card capacity.
|
|
|
|
|
*/
|
|
|
|
|
error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_TOO_MANY,
|
|
|
|
|
"Too many networks; %u networks written",
|
|
|
|
|
g_list_length (loaded_list));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
/* Update the PreferredNetworks property to real SIM contents */
|
|
|
|
|
mm_gdbus_sim_set_preferred_networks (MM_GDBUS_SIM (self),
|
|
|
|
|
mm_sim_preferred_network_list_get_variant (loaded_list));
|
|
|
|
|
g_task_return_error (task, error);
|
|
|
|
|
} else
|
|
|
|
|
g_task_return_boolean (task, TRUE);
|
|
|
|
|
|
|
|
|
|
g_list_free_full (loaded_list, (GDestroyNotify) mm_sim_preferred_network_free);
|
|
|
|
|
g_object_unref (task);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
set_preferred_networks_ready (QmiClientNas *client,
|
|
|
|
|
GAsyncResult *res,
|
|
|
|
|
GTask *task)
|
|
|
|
|
{
|
|
|
|
|
QmiMessageNasSetPreferredNetworksOutput *output;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
MMBaseSim *self;
|
|
|
|
|
|
|
|
|
|
self = g_task_get_source_object (task);
|
|
|
|
|
|
|
|
|
|
output = qmi_client_nas_set_preferred_networks_finish (client, res, &error);
|
|
|
|
|
if (!output) {
|
|
|
|
|
g_prefix_error (&error, "QMI operation failed: ");
|
|
|
|
|
g_task_return_error (task, error);
|
|
|
|
|
} else if (!qmi_message_nas_set_preferred_networks_output_get_result (output, &error)) {
|
|
|
|
|
g_prefix_error (&error, "Couldn't set preferred networks: ");
|
|
|
|
|
g_task_return_error (task, error);
|
|
|
|
|
} else {
|
|
|
|
|
/* Reload the networks from modem to check whether everything was written */
|
|
|
|
|
load_preferred_networks (self, (GAsyncReadyCallback) set_preferred_networks_reload_ready, task);
|
|
|
|
|
qmi_message_nas_set_preferred_networks_output_unref (output);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (output)
|
|
|
|
|
qmi_message_nas_set_preferred_networks_output_unref (output);
|
|
|
|
|
g_object_unref (task);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
set_preferred_networks (MMBaseSim *self,
|
|
|
|
|
GList *preferred_network_list,
|
|
|
|
|
GAsyncReadyCallback callback,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
GTask *task;
|
|
|
|
|
QmiMessageNasSetPreferredNetworksInput *input;
|
|
|
|
|
QmiClient *client = NULL;
|
|
|
|
|
GArray *preferred_nets_array;
|
|
|
|
|
GArray *preferred_nets_mnc_pcs_digit_array;
|
|
|
|
|
SetPreferredNetworksContext *ctx;
|
|
|
|
|
|
|
|
|
|
task = g_task_new (self, NULL, callback, user_data);
|
|
|
|
|
if (!ensure_qmi_client (task,
|
|
|
|
|
MM_SIM_QMI (self),
|
|
|
|
|
QMI_SERVICE_NAS, &client))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ctx = g_slice_new0 (SetPreferredNetworksContext);
|
|
|
|
|
ctx->set_list = mm_sim_preferred_network_list_copy (preferred_network_list);
|
|
|
|
|
g_task_set_task_data (task, ctx, (GDestroyNotify) set_preferred_network_context_free);
|
|
|
|
|
|
|
|
|
|
mm_obj_dbg (self, "setting preferred networks...");
|
|
|
|
|
|
|
|
|
|
input = qmi_message_nas_set_preferred_networks_input_new ();
|
|
|
|
|
|
|
|
|
|
preferred_nets_array = g_array_new (FALSE, TRUE, sizeof (QmiMessageNasSetPreferredNetworksInputPreferredNetworksElement));
|
|
|
|
|
preferred_nets_mnc_pcs_digit_array = g_array_new (FALSE, TRUE, sizeof (QmiMessageNasSetPreferredNetworksInputMncPcsDigitIncludeStatusElement));
|
|
|
|
|
|
|
|
|
|
while (preferred_network_list) {
|
|
|
|
|
QmiMessageNasSetPreferredNetworksInputPreferredNetworksElement preferred_nets_element;
|
|
|
|
|
QmiMessageNasSetPreferredNetworksInputMncPcsDigitIncludeStatusElement pcs_digit_element;
|
|
|
|
|
const gchar *operator_code;
|
|
|
|
|
MMModemAccessTechnology act;
|
|
|
|
|
|
|
|
|
|
memset (&preferred_nets_element, 0, sizeof (preferred_nets_element));
|
|
|
|
|
memset (&pcs_digit_element, 0, sizeof (pcs_digit_element));
|
|
|
|
|
|
|
|
|
|
operator_code = mm_sim_preferred_network_get_operator_code (preferred_network_list->data);
|
|
|
|
|
act = mm_sim_preferred_network_get_access_technology (preferred_network_list->data);
|
|
|
|
|
if (mm_3gpp_parse_operator_id (operator_code, &preferred_nets_element.mcc, &preferred_nets_element.mnc, NULL)) {
|
|
|
|
|
pcs_digit_element.mcc = preferred_nets_element.mcc;
|
|
|
|
|
pcs_digit_element.mnc = preferred_nets_element.mnc;
|
|
|
|
|
pcs_digit_element.includes_pcs_digit = strlen(operator_code) > 5;
|
|
|
|
|
|
|
|
|
|
preferred_nets_element.radio_access_technology = QMI_NAS_PLMN_ACCESS_TECHNOLOGY_IDENTIFIER_UNSPECIFIED;
|
|
|
|
|
if (act & MM_MODEM_ACCESS_TECHNOLOGY_GSM)
|
|
|
|
|
preferred_nets_element.radio_access_technology |= QMI_NAS_PLMN_ACCESS_TECHNOLOGY_IDENTIFIER_GSM;
|
|
|
|
|
if (act & MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT)
|
|
|
|
|
preferred_nets_element.radio_access_technology |= QMI_NAS_PLMN_ACCESS_TECHNOLOGY_IDENTIFIER_GSM_COMPACT;
|
|
|
|
|
if (act & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
|
|
|
|
|
preferred_nets_element.radio_access_technology |= QMI_NAS_PLMN_ACCESS_TECHNOLOGY_IDENTIFIER_UTRAN;
|
|
|
|
|
if (act & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
|
|
|
|
|
preferred_nets_element.radio_access_technology |= QMI_NAS_PLMN_ACCESS_TECHNOLOGY_IDENTIFIER_EUTRAN;
|
|
|
|
|
if (act & MM_MODEM_ACCESS_TECHNOLOGY_5GNR)
|
|
|
|
|
preferred_nets_element.radio_access_technology |= QMI_NAS_PLMN_ACCESS_TECHNOLOGY_IDENTIFIER_NGRAN;
|
|
|
|
|
|
|
|
|
|
g_array_append_val (preferred_nets_array, preferred_nets_element);
|
|
|
|
|
g_array_append_val (preferred_nets_mnc_pcs_digit_array, pcs_digit_element);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
preferred_network_list = g_list_next (preferred_network_list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qmi_message_nas_set_preferred_networks_input_set_preferred_networks (input, preferred_nets_array, NULL);
|
|
|
|
|
qmi_message_nas_set_preferred_networks_input_set_mnc_pcs_digit_include_status (input, preferred_nets_mnc_pcs_digit_array, NULL);
|
|
|
|
|
/* Always clear any pre-existing networks */
|
|
|
|
|
qmi_message_nas_set_preferred_networks_input_set_clear_previous_preferred_networks (input, TRUE, NULL);
|
|
|
|
|
|
|
|
|
|
qmi_client_nas_set_preferred_networks (QMI_CLIENT_NAS (client),
|
|
|
|
|
input,
|
|
|
|
|
5,
|
|
|
|
|
NULL,
|
|
|
|
|
(GAsyncReadyCallback)set_preferred_networks_ready,
|
|
|
|
|
task);
|
|
|
|
|
|
|
|
|
|
qmi_message_nas_set_preferred_networks_input_unref (input);
|
|
|
|
|
g_array_unref (preferred_nets_array);
|
|
|
|
|
g_array_unref (preferred_nets_mnc_pcs_digit_array);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* Send PIN */
|
|
|
|
|
|
|
|
|
@@ -1547,6 +1872,10 @@ mm_sim_qmi_class_init (MMSimQmiClass *klass)
|
|
|
|
|
base_sim_class->load_operator_identifier_finish = load_operator_identifier_finish;
|
|
|
|
|
base_sim_class->load_operator_name = load_operator_name;
|
|
|
|
|
base_sim_class->load_operator_name_finish = load_operator_name_finish;
|
|
|
|
|
base_sim_class->load_preferred_networks = load_preferred_networks;
|
|
|
|
|
base_sim_class->load_preferred_networks_finish = load_preferred_networks_finish;
|
|
|
|
|
base_sim_class->set_preferred_networks = set_preferred_networks;
|
|
|
|
|
base_sim_class->set_preferred_networks_finish = set_preferred_networks_finish;
|
|
|
|
|
base_sim_class->send_pin = send_pin;
|
|
|
|
|
base_sim_class->send_pin_finish = send_pin_finish;
|
|
|
|
|
base_sim_class->send_puk = send_puk;
|
|
|
|
|