diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-broadband-modem-qmi.c | 402 |
1 files changed, 299 insertions, 103 deletions
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c index ee4a97b5..d692cef7 100644 --- a/src/mm-broadband-modem-qmi.c +++ b/src/mm-broadband-modem-qmi.c @@ -176,6 +176,7 @@ struct _MMBroadbandModemQmiPrivate { /* WDS Profile changed notification ID (3gpp Profile Manager) */ guint profile_changed_indication_id; + gint profile_changed_indication_enabled; gint profile_changed_indication_ignored; /* PS registration helpers when using NAS System Info and DSD @@ -6503,12 +6504,130 @@ modem_3gpp_profile_manager_list_profiles (MMIfaceModem3gppProfileManager *self, task); } +/*******************************************************************************/ +/* Enable/Disable/Ignore profile changed events (3gppProfileManager interface) */ + +static gboolean +profile_changed_indication_configure_finish (MMBroadbandModemQmi *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +register_wds_profile_change_ready (QmiClientWds *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageWdsIndicationRegisterOutput) output = NULL; + GError *error = NULL; + + output = qmi_client_wds_indication_register_finish (client, res, &error); + if (!output || !qmi_message_wds_indication_register_output_get_result (output, &error)) + g_task_return_error (task, error); + else + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +profile_changed_indication_configure (MMBroadbandModemQmi *self, + QmiClientWds *client, + gboolean state_needed, + GTask *task) +{ + g_autoptr(QmiMessageWdsIndicationRegisterInput) input = NULL; + + input = qmi_message_wds_indication_register_input_new (); + qmi_message_wds_indication_register_input_set_report_profile_changes (input, state_needed, NULL); + qmi_client_wds_indication_register (client, + input, + 10, + NULL, + (GAsyncReadyCallback) register_wds_profile_change_ready, + task); +} + +static void +profile_changed_indication_configure_ignore (MMBroadbandModemQmi *self, + QmiClientWds *client, + gboolean ignore, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + gboolean state_needed_before; + gboolean state_needed_after; + + task = g_task_new (self, NULL, callback, user_data); + + state_needed_before = (self->priv->profile_changed_indication_enabled && + self->priv->profile_changed_indication_ignored == 0); + + /* Note: multiple concurrent profile create/update/deletes may be happening, + * so ensure the indication ignore logic applies as long as at least one + * operation is ongoing. */ + if (ignore) { + g_assert_cmpint (self->priv->profile_changed_indication_ignored, >=, 0); + self->priv->profile_changed_indication_ignored++; + mm_obj_dbg (self, "ignore profile update indications during our own operations (%d ongoing)", + self->priv->profile_changed_indication_ignored); + } else { + g_assert_cmpint (self->priv->profile_changed_indication_ignored, >, 0); + self->priv->profile_changed_indication_ignored--; + if (self->priv->profile_changed_indication_ignored > 0) + mm_obj_dbg (self, "still ignoring profile update indications during our own operations (%d ongoing)", + self->priv->profile_changed_indication_ignored); + else + mm_obj_dbg (self, "no longer ignoring profile update indications during our own operations"); + } + + state_needed_after = (self->priv->profile_changed_indication_enabled && + self->priv->profile_changed_indication_ignored == 0); + + if (state_needed_before == state_needed_after) { + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + + profile_changed_indication_configure (self, client, state_needed_after, task); +} + +static void +profile_changed_indication_configure_enable (MMBroadbandModemQmi *self, + QmiClientWds *client, + gboolean enable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + gboolean state_needed_before; + gboolean state_needed_after; + + task = g_task_new (self, NULL, callback, user_data); + + state_needed_before = (self->priv->profile_changed_indication_enabled && + self->priv->profile_changed_indication_ignored == 0); + + self->priv->profile_changed_indication_enabled = enable; + + state_needed_after = (self->priv->profile_changed_indication_enabled && + self->priv->profile_changed_indication_ignored == 0); + + if (state_needed_before == state_needed_after) { + g_task_return_boolean (task, TRUE); + g_object_unref (task); + return; + } + + profile_changed_indication_configure (self, client, state_needed_after, task); +} + /*****************************************************************************/ /* Store profile (3GPP profile management interface) */ -static void profile_changed_indication_ignore (MMBroadbandModemQmi *self, - gboolean ignore); - typedef struct { QmiClientWds *client; gint profile_id; @@ -6519,11 +6638,13 @@ typedef struct { QmiWdsApnTypeMask qmi_apn_type; QmiWdsAuthentication qmi_auth; QmiWdsPdpType qmi_pdp_type; + GError *saved_error; } StoreProfileContext; static void store_profile_context_free (StoreProfileContext *ctx) { + g_assert (!ctx->saved_error); g_free (ctx->profile_name); g_free (ctx->apn); g_free (ctx->user); @@ -6552,6 +6673,46 @@ modem_3gpp_profile_manager_store_profile_finish (MMIfaceModem3gppProfileManager return TRUE; } +static void +profile_changed_indication_configure_after_store_ready (MMBroadbandModemQmi *self, + GAsyncResult *res, + GTask *task) +{ + StoreProfileContext *ctx; + g_autoptr(GError) error = NULL; + + ctx = g_task_get_task_data (task); + + if (!profile_changed_indication_configure_finish (self, res, &error)) + mm_obj_warn (self, "Couldn't configure profile change indications after store operation: %s", error->message); + + if (ctx->saved_error) + g_task_return_error (task, g_steal_pointer (&ctx->saved_error)); + else + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +store_profile_complete (GTask *task, + GError *error) +{ + MMBroadbandModemQmi *self; + StoreProfileContext *ctx; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + ctx->saved_error = error; + + profile_changed_indication_configure_ignore ( + self, + ctx->client, + FALSE, + (GAsyncReadyCallback) profile_changed_indication_configure_after_store_ready, + task); +} + static void store_profile_run (GTask *task); static void @@ -6559,17 +6720,14 @@ modify_profile_ready (QmiClientWds *client, GAsyncResult *res, GTask *task) { - MMBroadbandModemQmi *self; - GError *error = NULL; - g_autoptr(QmiMessageWdsModifyProfileOutput) output = NULL; + MMBroadbandModemQmi *self; + g_autoptr(GError) error = NULL; + g_autoptr(QmiMessageWdsModifyProfileOutput) output = NULL; self = g_task_get_source_object (task); - profile_changed_indication_ignore (self, FALSE); output = qmi_client_wds_modify_profile_finish (client, res, &error); - if (!output) { - g_task_return_error (task, error); - } else if (!qmi_message_wds_modify_profile_output_get_result (output, &error)) { + if (output && !qmi_message_wds_modify_profile_output_get_result (output, &error)) { QmiWdsDsProfileError ds_profile_error; if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_PROFILE_TYPE) && @@ -6578,20 +6736,18 @@ modify_profile_ready (QmiClientWds *client, * in newer devices. */ mm_obj_dbg (self, "APN type flagged as not supported: failed to modify profile"); self->priv->apn_type_not_supported = TRUE; - g_clear_error (&error); store_profile_run (task); return; } + if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_EXTENDED_INTERNAL) && qmi_message_wds_modify_profile_output_get_extended_error_code (output, &ds_profile_error, NULL)) { g_prefix_error (&error, "DS profile error: %s: ", qmi_wds_ds_profile_error_get_string (ds_profile_error)); } g_prefix_error (&error, "Couldn't modify profile: "); - g_task_return_error (task, error); - } else { - g_task_return_boolean (task, TRUE); } - g_object_unref (task); + + store_profile_complete (task, g_steal_pointer (&error)); } static void @@ -6601,18 +6757,15 @@ create_profile_ready (QmiClientWds *client, { MMBroadbandModemQmi *self; StoreProfileContext *ctx; - GError *error = NULL; guint8 profile_index; + g_autoptr(GError) error = NULL; g_autoptr(QmiMessageWdsCreateProfileOutput) output = NULL; ctx = g_task_get_task_data (task); self = g_task_get_source_object (task); - profile_changed_indication_ignore (self, FALSE); output = qmi_client_wds_create_profile_finish (client, res, &error); - if (!output) { - g_task_return_error (task, error); - } else if (!qmi_message_wds_create_profile_output_get_result (output, &error)) { + if (output && !qmi_message_wds_create_profile_output_get_result (output, &error)) { QmiWdsDsProfileError ds_profile_error; if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_INVALID_PROFILE_TYPE) && @@ -6621,23 +6774,21 @@ create_profile_ready (QmiClientWds *client, * in newer devices. */ mm_obj_dbg (self, "APN type flagged as not supported: failed to create profile"); self->priv->apn_type_not_supported = TRUE; - g_clear_error (&error); store_profile_run (task); return; } + if (g_error_matches (error, QMI_PROTOCOL_ERROR, QMI_PROTOCOL_ERROR_EXTENDED_INTERNAL) && qmi_message_wds_create_profile_output_get_extended_error_code (output, &ds_profile_error, NULL)) { g_prefix_error (&error, "DS profile error: %s: ", qmi_wds_ds_profile_error_get_string (ds_profile_error)); } g_prefix_error (&error, "Couldn't create profile: "); - g_task_return_error (task, error); - } else if (!qmi_message_wds_create_profile_output_get_profile_identifier (output, NULL, &profile_index, &error)) { - g_task_return_error (task, error); - } else { - ctx->profile_id = profile_index; - g_task_return_boolean (task, TRUE); } - g_object_unref (task); + + if (!error && qmi_message_wds_create_profile_output_get_profile_identifier (output, NULL, &profile_index, &error)) + ctx->profile_id = profile_index; + + store_profile_complete (task, g_steal_pointer (&error)); } static void @@ -6664,7 +6815,6 @@ store_profile_run (GTask *task) if (!self->priv->apn_type_not_supported) qmi_message_wds_create_profile_input_set_apn_type_mask (input, ctx->qmi_apn_type, NULL); - profile_changed_indication_ignore (self, TRUE); qmi_client_wds_create_profile (ctx->client, input, 10, @@ -6685,7 +6835,6 @@ store_profile_run (GTask *task) if (!self->priv->apn_type_not_supported) qmi_message_wds_modify_profile_input_set_apn_type_mask (input, ctx->qmi_apn_type, NULL); - profile_changed_indication_ignore (self, TRUE); qmi_client_wds_modify_profile (ctx->client, input, 10, @@ -6696,6 +6845,19 @@ store_profile_run (GTask *task) } static void +profile_changed_indication_configure_before_store_ready (MMBroadbandModemQmi *self, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(GError) error = NULL; + + if (!profile_changed_indication_configure_finish (self, res, &error)) + mm_obj_warn (self, "Couldn't configure profile change indications before store operation: %s", error->message); + + store_profile_run (task); +} + +static void modem_3gpp_profile_manager_store_profile (MMIfaceModem3gppProfileManager *self, MM3gppProfile *profile, const gchar *index_field, @@ -6756,12 +6918,31 @@ modem_3gpp_profile_manager_store_profile (MMIfaceModem3gppProfileManager *self, return; } - store_profile_run (task); + profile_changed_indication_configure_ignore ( + MM_BROADBAND_MODEM_QMI (self), + ctx->client, + TRUE, + (GAsyncReadyCallback) profile_changed_indication_configure_before_store_ready, + task); } /*****************************************************************************/ /* Delete profile (3GPP profile management interface) */ +typedef struct { + QmiClientWds *client; + gint profile_id; + GError *saved_error; +} DeleteProfileContext; + +static void +delete_profile_context_free (DeleteProfileContext *ctx) +{ + g_assert (!ctx->saved_error); + g_clear_object (&ctx->client); + g_slice_free (DeleteProfileContext, ctx); +} + static gboolean modem_3gpp_profile_manager_delete_profile_finish (MMIfaceModem3gppProfileManager *self, GAsyncResult *res, @@ -6771,24 +6952,76 @@ modem_3gpp_profile_manager_delete_profile_finish (MMIfaceModem3gppProfileManager } static void +profile_changed_indication_configure_after_delete_ready (MMBroadbandModemQmi *self, + GAsyncResult *res, + GTask *task) +{ + DeleteProfileContext *ctx; + g_autoptr(QmiMessageWdsDeleteProfileInput) input = NULL; + g_autoptr(GError) error = NULL; + + ctx = g_task_get_task_data (task); + + if (!profile_changed_indication_configure_finish (self, res, &error)) + mm_obj_warn (self, "Couldn't configure profile change indications after delete operation: %s", error->message); + + if (ctx->saved_error) + g_task_return_error (task, g_steal_pointer (&ctx->saved_error)); + else + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void delete_profile_ready (QmiClientWds *client, GAsyncResult *res, GTask *task) { - MMBroadbandModemQmi *self; - GError *error = NULL; + MMBroadbandModemQmi *self; + DeleteProfileContext *ctx; + g_autoptr(GError) error = NULL; g_autoptr(QmiMessageWdsDeleteProfileOutput) output = NULL; self = g_task_get_source_object (task); - profile_changed_indication_ignore (self, FALSE); + ctx = g_task_get_task_data (task); output = qmi_client_wds_delete_profile_finish (client, res, &error); - if (!output || !qmi_message_wds_delete_profile_output_get_result (output, &error)) { + if (!output || !qmi_message_wds_delete_profile_output_get_result (output, &error)) g_prefix_error (&error, "Couldn't delete profile: "); - g_task_return_error (task, error); - } else - g_task_return_boolean (task, TRUE); - g_object_unref (task); + + /* Store as task data to complete the task later */ + ctx->saved_error = g_steal_pointer (&error); + + profile_changed_indication_configure_ignore ( + self, + ctx->client, + FALSE, + (GAsyncReadyCallback) profile_changed_indication_configure_after_delete_ready, + task); +} + +static void +profile_changed_indication_configure_before_delete_ready (MMBroadbandModemQmi *self, + GAsyncResult *res, + GTask *task) +{ + DeleteProfileContext *ctx; + g_autoptr(QmiMessageWdsDeleteProfileInput) input = NULL; + g_autoptr(GError) error = NULL; + + ctx = g_task_get_task_data (task); + + if (!profile_changed_indication_configure_finish (self, res, &error)) + mm_obj_warn (self, "Couldn't configure profile change indications before delete operation: %s", error->message); + + input = qmi_message_wds_delete_profile_input_new (); + qmi_message_wds_delete_profile_input_set_profile_identifier (input, QMI_WDS_PROFILE_TYPE_3GPP, ctx->profile_id, NULL); + qmi_client_wds_delete_profile (QMI_CLIENT_WDS (ctx->client), + input, + 10, + NULL, + (GAsyncReadyCallback)delete_profile_ready, + task); } static void @@ -6798,10 +7031,9 @@ modem_3gpp_profile_manager_delete_profile (MMIfaceModem3gppProfileManager *self, GAsyncReadyCallback callback, gpointer user_data) { - GTask *task; - QmiClient *client = NULL; - gint profile_id; - g_autoptr(QmiMessageWdsDeleteProfileInput) input = NULL; + DeleteProfileContext *ctx; + GTask *task; + QmiClient *client = NULL; g_assert (g_strcmp0 (index_field, "profile-id") == 0); @@ -6811,22 +7043,20 @@ modem_3gpp_profile_manager_delete_profile (MMIfaceModem3gppProfileManager *self, return; task = g_task_new (self, NULL, callback, user_data); + ctx = g_slice_new0 (DeleteProfileContext); + ctx->client = QMI_CLIENT_WDS (g_object_ref (client)); + ctx->profile_id = mm_3gpp_profile_get_profile_id (profile); + g_assert (ctx->profile_id != MM_3GPP_PROFILE_ID_UNKNOWN); + g_task_set_task_data (task, ctx, (GDestroyNotify) delete_profile_context_free); - profile_id = mm_3gpp_profile_get_profile_id (profile); - g_assert (profile_id != MM_3GPP_PROFILE_ID_UNKNOWN); - - mm_obj_dbg (self, "deleting profile '%d'", profile_id); - - input = qmi_message_wds_delete_profile_input_new (); - qmi_message_wds_delete_profile_input_set_profile_identifier (input, QMI_WDS_PROFILE_TYPE_3GPP, profile_id, NULL); + mm_obj_dbg (self, "deleting profile '%d'", ctx->profile_id); - profile_changed_indication_ignore (MM_BROADBAND_MODEM_QMI (self), TRUE); - qmi_client_wds_delete_profile (QMI_CLIENT_WDS (client), - input, - 10, - NULL, - (GAsyncReadyCallback)delete_profile_ready, - task); + profile_changed_indication_configure_ignore ( + MM_BROADBAND_MODEM_QMI (self), + ctx->client, + TRUE, + (GAsyncReadyCallback) profile_changed_indication_configure_before_delete_ready, + task); } /*****************************************************************************/ @@ -6849,38 +7079,10 @@ profile_changed_indication_received (QmiClientWds *clien QmiIndicationWdsProfileChangedOutput *output, MMBroadbandModemQmi *self) { - if (self->priv->profile_changed_indication_ignored > 0) { - mm_obj_dbg (self, "profile changed indication ignored"); - return; - } - mm_obj_dbg (self, "profile changed indication was received"); mm_iface_modem_3gpp_profile_manager_updated (MM_IFACE_MODEM_3GPP_PROFILE_MANAGER (self)); } -static void -profile_changed_indication_ignore (MMBroadbandModemQmi *self, - gboolean ignore) -{ - /* Note: multiple concurrent profile create/update/deletes may be happening, - * so ensure the indication ignore logic applies as long as at least one - * operation is ongoing. */ - if (ignore) { - g_assert_cmpint (self->priv->profile_changed_indication_ignored, >=, 0); - self->priv->profile_changed_indication_ignored++; - mm_obj_dbg (self, "ignoring profile update indications during our own operations (%d ongoing)", - self->priv->profile_changed_indication_ignored); - } else { - g_assert_cmpint (self->priv->profile_changed_indication_ignored, >, 0); - self->priv->profile_changed_indication_ignored--; - if (self->priv->profile_changed_indication_ignored > 0) - mm_obj_dbg (self, "still ignoring profile update indications during our own operations (%d ongoing)", - self->priv->profile_changed_indication_ignored); - else - mm_obj_dbg (self, "no longer ignoring profile update indications during our own operations"); - } -} - /*****************************************************************************/ /* Enable/Disable unsolicited events (3gppProfileManager interface) */ @@ -6940,18 +7142,16 @@ register_pdc_refresh_ready (QmiClientPdc *client, } static void -register_wds_profile_change_ready (QmiClientWds *client, - GAsyncResult *res, - GTask *task) +profile_changed_indication_configure_ready (MMBroadbandModemQmi *self, + GAsyncResult *res, + GTask *task) { - g_autoptr(QmiMessageWdsIndicationRegisterOutput) output = NULL; - RegisterProfileRefreshContext *ctx; - GError *error = NULL; + RegisterProfileRefreshContext *ctx; + GError *error = NULL; ctx = g_task_get_task_data (task); - output = qmi_client_wds_indication_register_finish (client, res, &error); - if (!output || !qmi_message_wds_indication_register_output_get_result (output, &error)) { + if (!profile_changed_indication_configure_finish (self, res, &error)) { g_task_return_error (task, error); g_object_unref (task); return; @@ -7016,16 +7216,12 @@ register_profile_refresh_context_step (GTask *task) case REGISTER_PROFILE_REFRESH_STEP_PROFILE_CHANGE: if (ctx->client_wds) { - g_autoptr(QmiMessageWdsIndicationRegisterInput) input = NULL; - - input = qmi_message_wds_indication_register_input_new (); - qmi_message_wds_indication_register_input_set_report_profile_changes (input, ctx->enable, NULL); - qmi_client_wds_indication_register (ctx->client_wds, - input, - 10, - NULL, - (GAsyncReadyCallback) register_wds_profile_change_ready, - task); + profile_changed_indication_configure_enable ( + self, + ctx->client_wds, + ctx->enable, + (GAsyncReadyCallback) profile_changed_indication_configure_ready, + task); return; } ctx->step++; |