diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-12-28 10:23:52 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-12-28 11:50:27 +0100 |
commit | d1d856994edc3cb61201a78a527d7c33683bf733 (patch) | |
tree | a102eb20cbd05f5751e948da7f29f50491142a7d | |
parent | d40ef838986eb62b4c657a981791e8225ce3ce2c (diff) |
sierra: cache SIM PIN and re-send it after power-up if neededsierra-pin-after-power-up
When we recover from low-power mode without a modem reset, we may need to
re-send the PIN:
(ttyUSB6): --> 'AT+CFUN?<CR>'
(ttyUSB8): <-- '<CR><LF>OK<CR><LF>'
(ttyUSB6): <-- '<CR><LF>+CFUN: 4<CR><LF><CR><LF>OK<CR><LF>'
(ttyUSB6): --> 'AT+CFUN=1,0<CR>'
(ttyUSB6): <-- '<CR><LF>OK<CR><LF>'
(ttyUSB6): --> 'AT+CPIN?<CR>'
(ttyUSB6): <-- '<CR><LF>+CPIN: SIM PIN<CR><LF><CR><LF>OK<CR><LF>'
(ttyUSB6): --> 'AT+CPIN="1234"<CR>'
(ttyUSB6): <-- '<CR><LF>OK<CR><LF>'
The cached SIM PIN will be the last SIM PIN used to unlock the modem.
If, for any reason, sending the cached PIN fails, we'll end up removing the
cache, so that the user doesn't try to enable the modem too many times using
a possible wrong PIN.
If we get PIN-locked after the power-up and we didn't cache any PIN, which may
happen if MM crashes, reboots and the modem was already unlocked (we won't ask
for PIN during initialization), then we'll perform a device reset. This
situation is really a corner case to be handled nicely.
-rw-r--r-- | plugins/sierra/mm-common-sierra.c | 95 | ||||
-rw-r--r-- | plugins/sierra/mm-sim-sierra.c | 97 | ||||
-rw-r--r-- | plugins/sierra/mm-sim-sierra.h | 2 |
3 files changed, 190 insertions, 4 deletions
diff --git a/plugins/sierra/mm-common-sierra.c b/plugins/sierra/mm-common-sierra.c index d0bde95c..3bfbf2ca 100644 --- a/plugins/sierra/mm-common-sierra.c +++ b/plugins/sierra/mm-common-sierra.c @@ -32,12 +32,99 @@ mm_common_sierra_modem_power_up_finish (MMIfaceModem *self, return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); } +static void +send_pin_ready (MMSim *sim, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + GError *error = NULL; + + if (!MM_SIM_GET_CLASS (sim)->send_pin_finish (sim, res, &error)) { + mm_warn ("Error sending cached SIM PIN after power-up: '%s'", error->message); + + /* If the error is because PIN wasn't found, we need to fully reset the + * modem and re-start the state machine from the beginning, so that we + * ask the user for the PIN while in locked state. */ + if (g_error_matches (error, + MM_CORE_ERROR, + MM_CORE_ERROR_NOT_FOUND)) { + MMBroadbandModem *self = NULL; + + self = MM_BROADBAND_MODEM (g_async_result_get_source_object (G_ASYNC_RESULT (simple))); + /* Launch modem reset... if possible */ + if (MM_IFACE_MODEM_GET_INTERFACE (MM_IFACE_MODEM (self))->reset && + MM_IFACE_MODEM_GET_INTERFACE (MM_IFACE_MODEM (self))->reset_finish) { + mm_warn ("Launching modem reset..."); + MM_IFACE_MODEM_GET_INTERFACE (MM_IFACE_MODEM (self))->reset (MM_IFACE_MODEM (self), NULL, NULL); + } + g_object_unref (self); + } + + g_simple_async_result_take_error (simple, error); + } else { + mm_dbg ("Assuming we got unlocked after power-up"); + /* Assume we're done */ + g_simple_async_result_set_op_res_gboolean (simple, TRUE); + } + + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +unlock_check_ready (MMIfaceModem *self, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + MMModemLock lock; + GError *error = NULL; + + lock = MM_IFACE_MODEM_GET_INTERFACE (self)->load_unlock_required_finish (self, res, &error); + if (error) { + mm_dbg ("Couldn't check lock status after power up: '%s'", error->message); + g_error_free (error); + } else if (lock == MM_MODEM_LOCK_SIM_PIN) { + MMSim *sim = NULL; + + /* If we need SIM PIN unlocking, re-send the cached one */ + g_object_get (self, + MM_IFACE_MODEM_SIM, &sim, + NULL); + if (sim) { + mm_dbg ("Sending cached SIM PIN..."); + /* On the Sierra-specific SIM implementation, we do allow passing a + * NULL pin. It just means 'try to use the last cached one'. + * NOTE: do not call mm_sim_send_pin(), as that may ignore the errors. */ + MM_SIM_GET_CLASS (sim)->send_pin (sim, + NULL, + (GAsyncReadyCallback)send_pin_ready, + simple); + g_object_unref (sim); + return; + } + mm_dbg ("No SIM found, assuming we won't need re-unlock"); + } else + mm_info ("Modem is locked with '%s' after power-up", mm_modem_lock_get_string (lock)); + + /* On error, or READY, or other lock, or no SIM, just go on */ + g_simple_async_result_set_op_res_gboolean (simple, TRUE); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + static gboolean -sierra_power_up_wait_cb (GSimpleAsyncResult *result) +sierra_power_up_wait_cb (GSimpleAsyncResult *simple) { - g_simple_async_result_set_op_res_gboolean (result, TRUE); - g_simple_async_result_complete (result); - g_object_unref (result); + MMBroadbandModem *self; + + self = MM_BROADBAND_MODEM (g_async_result_get_source_object (G_ASYNC_RESULT (simple))); + + /* Some modems may actually need to unlock the SIM PIN again after powering up... + * We'll call the Modem inteface method of the modem directly */ + MM_IFACE_MODEM_GET_INTERFACE (MM_IFACE_MODEM (self))->load_unlock_required (MM_IFACE_MODEM (self), + (GAsyncReadyCallback)unlock_check_ready, + simple); + g_object_unref (self); return FALSE; } diff --git a/plugins/sierra/mm-sim-sierra.c b/plugins/sierra/mm-sim-sierra.c index 1b741de6..de5fa09e 100644 --- a/plugins/sierra/mm-sim-sierra.c +++ b/plugins/sierra/mm-sim-sierra.c @@ -33,6 +33,82 @@ G_DEFINE_TYPE (MMSimSierra, mm_sim_sierra, MM_TYPE_SIM); +struct _MMSimSierraPrivate { + gchar *cached_pin; +}; + +/*****************************************************************************/ +/* Send SIM PIN */ + +static gboolean +send_pin_finish (MMSim *self, + GAsyncResult *res, + GError **error) +{ + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); +} + +static void +parent_send_pin_ready (MMSim *_self, + GAsyncResult *res, + GSimpleAsyncResult *simple) +{ + MMSimSierra *self = MM_SIM_SIERRA (_self); + GError *error = NULL; + + if (!MM_SIM_CLASS (mm_sim_sierra_parent_class)->send_pin_finish (_self, res, &error)) { + /* Clear cached PIN if sending PIN fails */ + g_free (self->priv->cached_pin); + self->priv->cached_pin = NULL; + g_simple_async_result_take_error (simple, error); + } else + g_simple_async_result_set_op_res_gboolean (simple, TRUE); + + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static void +send_pin (MMSim *_self, + const gchar *pin, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MMSimSierra *self = MM_SIM_SIERRA (_self); + GSimpleAsyncResult *result; + + result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + send_pin); + + /* We allow passing NULL pin, when we want to use the last cached one. + * This will only happen when re-unlocking the SIM after powering up + * the modem, so it means that if any PIN was introduced already, + * it would be the correct one. */ + if (!pin) { + if (!self->priv->cached_pin) { + g_simple_async_result_set_error (result, + MM_CORE_ERROR, + MM_CORE_ERROR_NOT_FOUND, + "No cached PIN found"); + g_simple_async_result_complete_in_idle (result); + g_object_unref (result); + return; + } + } else { + /* Update cached PIN */ + g_free (self->priv->cached_pin); + self->priv->cached_pin = g_strdup (pin); + } + + /* Call parent's PIN sending code */ + MM_SIM_CLASS (mm_sim_sierra_parent_class)->send_pin (_self, + self->priv->cached_pin, + (GAsyncReadyCallback)parent_send_pin_ready, + result); +} + /*****************************************************************************/ /* SIM identifier loading */ @@ -179,13 +255,34 @@ mm_sim_sierra_new (MMBaseModem *modem, static void mm_sim_sierra_init (MMSimSierra *self) { + /* Initialize private data */ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + MM_TYPE_SIM_SIERRA, + MMSimSierraPrivate); +} + +static void +finalize (GObject *object) +{ + MMSimSierra *self = MM_SIM_SIERRA (object); + + g_free (self->priv->cached_pin); + + G_OBJECT_CLASS (mm_sim_sierra_parent_class)->finalize (object); } static void mm_sim_sierra_class_init (MMSimSierraClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); MMSimClass *sim_class = MM_SIM_CLASS (klass); + g_type_class_add_private (object_class, sizeof (MMSimSierraPrivate)); + + object_class->finalize = finalize; + sim_class->load_sim_identifier = load_sim_identifier; sim_class->load_sim_identifier_finish = load_sim_identifier_finish; + sim_class->send_pin = send_pin; + sim_class->send_pin_finish = send_pin_finish; } diff --git a/plugins/sierra/mm-sim-sierra.h b/plugins/sierra/mm-sim-sierra.h index 3595bd94..d89df35a 100644 --- a/plugins/sierra/mm-sim-sierra.h +++ b/plugins/sierra/mm-sim-sierra.h @@ -32,9 +32,11 @@ typedef struct _MMSimSierra MMSimSierra; typedef struct _MMSimSierraClass MMSimSierraClass; +typedef struct _MMSimSierraPrivate MMSimSierraPrivate; struct _MMSimSierra { MMSim parent; + MMSimSierraPrivate *priv; }; struct _MMSimSierraClass { |