diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2013-09-18 19:55:22 +0200 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2013-09-19 09:33:08 -0500 |
commit | 13c7319bffe80545a5c7e8399ad6279b8d3cd87d (patch) | |
tree | b96c8bcad19150d02fd7ed60dbc529ac27a8bfe9 | |
parent | 43d1c904e6f7668143007723d205d923feb620c0 (diff) | |
download | ModemManager-13c7319bffe80545a5c7e8399ad6279b8d3cd87d.tar.gz |
iface-modem: consolidate new unlock required check with retries
The new internal_load_unlock_required() method will take care of running the
subclassed load_unlock_required(), if available, and also retry the check up
to 6 times.
This method will be used both by the standard unlock required check and by the
check within the current capabilities loading for multimode devices.
-rw-r--r-- | src/mm-iface-modem.c | 231 |
1 files changed, 172 insertions, 59 deletions
diff --git a/src/mm-iface-modem.c b/src/mm-iface-modem.c index 02b03dbc7..433dbaca0 100644 --- a/src/mm-iface-modem.c +++ b/src/mm-iface-modem.c @@ -206,6 +206,146 @@ mm_iface_modem_wait_for_final_state (MMIfaceModem *self, } /*****************************************************************************/ +/* Helper method to load unlock required, considering retries */ + +#define MAX_RETRIES 6 + +typedef struct { + MMIfaceModem *self; + GSimpleAsyncResult *result; + guint retries; + guint pin_check_timeout_id; +} InternalLoadUnlockRequiredContext; + +static void +internal_load_unlock_required_context_complete_and_free (InternalLoadUnlockRequiredContext *ctx) +{ + g_simple_async_result_complete_in_idle (ctx->result); + g_object_unref (ctx->result); + g_object_unref (ctx->self); + g_slice_free (InternalLoadUnlockRequiredContext, ctx); +} + +static MMModemLock +internal_load_unlock_required_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return MM_MODEM_LOCK_UNKNOWN; + + return (MMModemLock) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); +} + +static void internal_load_unlock_required_context_step (InternalLoadUnlockRequiredContext *ctx); + +static gboolean +load_unlock_required_again (InternalLoadUnlockRequiredContext *ctx) +{ + ctx->pin_check_timeout_id = 0; + /* Retry the step */ + internal_load_unlock_required_context_step (ctx); + return FALSE; +} + +static void +load_unlock_required_ready (MMIfaceModem *self, + GAsyncResult *res, + InternalLoadUnlockRequiredContext *ctx) +{ + GError *error = NULL; + MMModemLock lock; + + lock = MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_required_finish (self, res, &error); + if (error) { + mm_dbg ("Couldn't check if unlock required: '%s'", error->message); + + /* For several kinds of errors, just return them directly */ + if (error->domain == MM_SERIAL_ERROR || + g_error_matches (error, + MM_CORE_ERROR, + MM_CORE_ERROR_CANCELLED) || + g_error_matches (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED) || + g_error_matches (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE) || + g_error_matches (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) { + g_simple_async_result_take_error (ctx->result, error); + internal_load_unlock_required_context_complete_and_free (ctx); + return; + } + + /* For the remaining ones, retry if possible */ + if (ctx->retries < MAX_RETRIES) { + ctx->retries++; + mm_dbg ("Retrying (%u) unlock required check", ctx->retries); + + g_assert (ctx->pin_check_timeout_id == 0); + ctx->pin_check_timeout_id = g_timeout_add_seconds (2, + (GSourceFunc)load_unlock_required_again, + ctx); + g_error_free (error); + return; + } + + /* If reached max retries and still reporting error... default to SIM error */ + g_error_free (error); + g_simple_async_result_set_error (ctx->result, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE, + "Couldn't get SIM lock status after %u retries", + MAX_RETRIES); + internal_load_unlock_required_context_complete_and_free (ctx); + return; + } + + /* Got the lock value, return it */ + g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (ctx->result), + GUINT_TO_POINTER (lock), + NULL); + internal_load_unlock_required_context_complete_and_free (ctx); +} + +static void +internal_load_unlock_required_context_step (InternalLoadUnlockRequiredContext *ctx) +{ + g_assert (ctx->pin_check_timeout_id == 0); + MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required ( + ctx->self, + (GAsyncReadyCallback)load_unlock_required_ready, + ctx); +} + +static void +internal_load_unlock_required (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + InternalLoadUnlockRequiredContext *ctx; + + ctx = g_slice_new0 (InternalLoadUnlockRequiredContext); + ctx->self = g_object_ref (self); + ctx->result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + internal_load_unlock_required); + + if (!MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required || + !MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required_finish) { + /* Just assume that no lock is required */ + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); + internal_load_unlock_required_context_complete_and_free (ctx); + return; + } + + internal_load_unlock_required_context_step (ctx); +} + +/*****************************************************************************/ static MMModemState get_current_consolidated_state (MMIfaceModem *self, MMModemState modem_state); @@ -2670,8 +2810,6 @@ typedef enum { typedef struct { MMIfaceModem *self; UpdateLockInfoContextStep step; - guint pin_check_tries; - guint pin_check_timeout_id; GSimpleAsyncResult *result; MmGdbusModem *skeleton; MMModemLock lock; @@ -2744,23 +2882,14 @@ modem_after_sim_unlock_ready (MMIfaceModem *self, update_lock_info_context_step (ctx); } -static gboolean -load_unlock_required_again (UpdateLockInfoContext *ctx) -{ - ctx->pin_check_timeout_id = 0; - /* Retry the step */ - update_lock_info_context_step (ctx); - return FALSE; -} - static void -load_unlock_required_ready (MMIfaceModem *self, - GAsyncResult *res, - UpdateLockInfoContext *ctx) +internal_load_unlock_required_ready (MMIfaceModem *self, + GAsyncResult *res, + UpdateLockInfoContext *ctx) { GError *error = NULL; - ctx->lock = MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_required_finish (self, res, &error); + ctx->lock = internal_load_unlock_required_finish (self, res, &error); if (error) { /* Treat several SIM related, serial and other core errors as critical * and abort the checks. These will end up moving the modem to a FAILED @@ -2773,44 +2902,32 @@ load_unlock_required_ready (MMIfaceModem *self, ctx->step = UPDATE_LOCK_INFO_CONTEXT_STEP_LAST; update_lock_info_context_step (ctx); return; - } else if (g_error_matches (error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED) || - g_error_matches (error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE) || - g_error_matches (error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) { - if (mm_iface_modem_is_cdma (self)) { - /* For mixed 3GPP+3GPP2 devices, skip SIM errors */ - mm_dbg ("Skipping SIM error in 3GPP2-capable device, assuming no lock is needed"); - g_error_free (error); - ctx->lock = MM_MODEM_LOCK_NONE; - } else { - /* SIM errors are only critical in 3GPP-only devices */ + } + + if (g_error_matches (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED) || + g_error_matches (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_FAILURE) || + g_error_matches (error, + MM_MOBILE_EQUIPMENT_ERROR, + MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) { + /* SIM errors are only critical in 3GPP-only devices */ + if (!mm_iface_modem_is_cdma (self)) { ctx->saved_error = error; ctx->step = UPDATE_LOCK_INFO_CONTEXT_STEP_LAST; update_lock_info_context_step (ctx); return; } + + /* For mixed 3GPP+3GPP2 devices, skip SIM errors */ + mm_dbg ("Skipping SIM error in 3GPP2-capable device, assuming no lock is needed"); + g_error_free (error); + ctx->lock = MM_MODEM_LOCK_NONE; } else { mm_dbg ("Couldn't check if unlock required: '%s'", error->message); g_error_free (error); - - /* Retry up to 6 times */ - if (mm_gdbus_modem_get_unlock_required (ctx->skeleton) != MM_MODEM_LOCK_NONE && - ++ctx->pin_check_tries < 6) { - mm_dbg ("Retrying (%u) unlock required check", ctx->pin_check_tries); - if (ctx->pin_check_timeout_id) - g_source_remove (ctx->pin_check_timeout_id); - ctx->pin_check_timeout_id = g_timeout_add_seconds (2, - (GSourceFunc)load_unlock_required_again, - ctx); - return; - } - - /* If reached max retries and still reporting error, set UNKNOWN */ ctx->lock = MM_MODEM_LOCK_UNKNOWN; } } @@ -2842,12 +2959,10 @@ update_lock_info_context_step (UpdateLockInfoContext *ctx) /* Don't re-ask if already known */ if (ctx->lock == MM_MODEM_LOCK_UNKNOWN) { /* If we're already unlocked, we're done */ - if (mm_gdbus_modem_get_unlock_required (ctx->skeleton) != MM_MODEM_LOCK_NONE && - MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required && - MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required_finish) { - MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required ( + if (mm_gdbus_modem_get_unlock_required (ctx->skeleton) != MM_MODEM_LOCK_NONE) { + internal_load_unlock_required ( ctx->self, - (GAsyncReadyCallback)load_unlock_required_ready, + (GAsyncReadyCallback)internal_load_unlock_required_ready, ctx); return; } @@ -3592,13 +3707,13 @@ initialization_context_complete_and_free_if_cancelled (InitializationContext *ct } static void -current_capabilities_load_unlock_required_ready (MMIfaceModem *self, - GAsyncResult *res, - InitializationContext *ctx) +current_capabilities_internal_load_unlock_required_ready (MMIfaceModem *self, + GAsyncResult *res, + InitializationContext *ctx) { GError *error = NULL; - MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_required_finish (self, res, &error); + internal_load_unlock_required_finish (self, res, &error); if (error) { /* These SIM errors indicate that there is NO valid SIM available. So, * remove all 3GPP caps from the current capabilities */ @@ -3657,13 +3772,11 @@ load_current_capabilities_ready (MMIfaceModem *self, /* If the device is a multimode device (3GPP+3GPP2) check whether we have a * SIM or not. */ if (caps & MM_MODEM_CAPABILITY_CDMA_EVDO && - (caps & MM_MODEM_CAPABILITY_GSM_UMTS || caps & MM_MODEM_CAPABILITY_LTE) && - MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required && - MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required_finish) { + (caps & MM_MODEM_CAPABILITY_GSM_UMTS || caps & MM_MODEM_CAPABILITY_LTE)) { mm_dbg ("Checking if multimode device has a SIM..."); - MM_IFACE_MODEM_GET_INTERFACE (ctx->self)->load_unlock_required ( + internal_load_unlock_required ( ctx->self, - (GAsyncReadyCallback)current_capabilities_load_unlock_required_ready, + (GAsyncReadyCallback)current_capabilities_internal_load_unlock_required_ready, ctx); return; } |