aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Shienbrood <ers@chromium.org>2011-08-11 16:58:34 -0400
committerDan Williams <dcbw@redhat.com>2012-08-24 09:25:22 -0500
commit31b3c0f8ff9842bf1f05aefcb9f9ffaf61626b16 (patch)
tree0511cf3e38d331a89ee75917cabd9e9b8249d148
parentecdb5191aad98aa623dde8cce6548305c4e282c8 (diff)
icera: retry configuring PDP context if it fails.
If a connect operation is attempted immediately after a disconnect, it sometimes fails with CME error 583 - "a profile (CID) is currently active". Apparently, even though the preceding operation (%IPDPACT) to deactivate the PDP context returned an OK response, the context is not really completely available until a fraction of a second later. This causes the %IPDPCFG operation that is part of the subsequent connect attempt to fail with error 583. This change retries the %IPDPCFG after a one second delay. BUG=chrome-os-partner:4936 TEST=This can be tested from the UI, but I found it easier to produce the timing needed to trigger the bug by running mm-disconnect and mm-connect from a shell. Start out with the modem in the connected state. In the shell, run sudo /usr/local/lib/flimflam/test/mm-disconnect; sudo /usr/local/lib/flimflam/test/mm-connect --number='*99#' --apn=wap.cingular modem-manager should emit the log line "Invalid error code: 583". Prior to this change, the connect operation would fail. Now it should succeed. Change-Id: I6ae0e6a9f5405b54b0b465fe91d9542529f365c2 Reviewed-on: http://gerrit.chromium.org/gerrit/5781 Tested-by: Eric Shienbrood <ers@chromium.org> Reviewed-by: Nathan J. Williams <njw@chromium.org>
-rw-r--r--plugins/mm-modem-icera.c79
1 files changed, 59 insertions, 20 deletions
diff --git a/plugins/mm-modem-icera.c b/plugins/mm-modem-icera.c
index 4256a486..2bbf677b 100644
--- a/plugins/mm-modem-icera.c
+++ b/plugins/mm-modem-icera.c
@@ -39,6 +39,8 @@ struct _MMModemIceraPrivate {
/* Pending connection attempt */
MMCallbackInfo *connect_pending_data;
guint connect_pending_id;
+ guint configure_context_id;
+ guint configure_context_tries;
char *username;
char *password;
@@ -563,6 +565,24 @@ old_context_clear_done (MMAtSerialPort *port,
icera_call_control (MM_MODEM_ICERA (info->modem), TRUE, icera_connected, info);
}
+static void configure_context(MMAtSerialPort *port, MMCallbackInfo *info,
+ char *username, char *password, gint cid);
+
+static gboolean
+retry_config_context (gpointer data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) data;
+ MMModemIcera *self = MM_MODEM_ICERA (info->modem);
+ MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self);
+ MMAtSerialPort *primary;
+
+ priv->configure_context_id = 0;
+ primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_AT_PORT_FLAG_PRIMARY);
+ g_assert (primary);
+ configure_context (primary, info, priv->username, priv->password, _get_cid(self));
+ return FALSE;
+}
+
static void
auth_done (MMAtSerialPort *port,
GString *response,
@@ -570,20 +590,51 @@ auth_done (MMAtSerialPort *port,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ MMModemIcera *self = MM_MODEM_ICERA (info->modem);
+ MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self);
/* If the modem has already been removed, return without
* scheduling callback */
if (mm_callback_info_check_modem_removed (info))
return;
- if (error)
+ if (error) {
+ /* Retry configuring the context. It sometimes fails with a 583
+ * error ["a profile (CID) is currently active"] if a connect
+ * is attempted too soon after a disconnect. */
+ if (++priv->configure_context_tries < 3) {
+ priv->configure_context_id =
+ g_timeout_add_seconds (1, retry_config_context, info);
+ return;
+ }
mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), error, info);
- else {
+ } else {
/* Ensure the PDP context is deactivated */
icera_call_control (MM_MODEM_ICERA (info->modem), FALSE, old_context_clear_done, info);
}
}
+static void
+configure_context(MMAtSerialPort *port, MMCallbackInfo *info,
+ char *username, char *password, gint cid)
+{
+ char *command;
+
+ /* Both user and password are required; otherwise firmware returns an error */
+ if (!username || !password)
+ command = g_strdup_printf ("%%IPDPCFG=%d,0,0,\"\",\"\"", cid);
+ else {
+ command = g_strdup_printf ("%%IPDPCFG=%d,0,1,\"%s\",\"%s\"",
+ cid,
+ username ? username : "",
+ password ? password : "");
+
+ }
+
+ mm_at_serial_port_queue_command (port, command, 3, auth_done, info);
+ g_free (command);
+}
+
void
mm_modem_icera_do_connect (MMModemIcera *self,
const char *number,
@@ -594,8 +645,6 @@ mm_modem_icera_do_connect (MMModemIcera *self,
MMModemIceraPrivate *priv = MM_MODEM_ICERA_GET_PRIVATE (self);
MMCallbackInfo *info;
MMAtSerialPort *primary;
- gint cid;
- char *command;
mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE);
@@ -604,22 +653,8 @@ mm_modem_icera_do_connect (MMModemIcera *self,
primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_AT_PORT_FLAG_PRIMARY);
g_assert (primary);
- cid = _get_cid (self);
-
-
- /* Both user and password are required; otherwise firmware returns an error */
- if (!priv->username || !priv->password)
- command = g_strdup_printf ("%%IPDPCFG=%d,0,0,\"\",\"\"", cid);
- else {
- command = g_strdup_printf ("%%IPDPCFG=%d,0,1,\"%s\",\"%s\"",
- cid,
- priv->username ? priv->username : "",
- priv->password ? priv->password : "");
-
- }
-
- mm_at_serial_port_queue_command (primary, command, 3, auth_done, info);
- g_free (command);
+ priv->configure_context_tries = 0;
+ configure_context(primary, info, priv->username, priv->password, _get_cid(self));
}
/****************************************************************/
@@ -1338,6 +1373,10 @@ mm_modem_icera_cleanup (MMModemIcera *self)
/* Clear the pending connection if necessary */
connect_pending_done (self);
+ if (priv->configure_context_id != 0) {
+ g_source_remove (priv->configure_context_id);
+ priv->configure_context_id = 0;
+ }
g_free (priv->username);
priv->username = NULL;