---
 drivers/atmodem/gprs-context.c |   80 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/drivers/atmodem/gprs-context.c b/drivers/atmodem/gprs-context.c
index 16893ce..d47d66a 100644
--- a/drivers/atmodem/gprs-context.c
+++ b/drivers/atmodem/gprs-context.c
@@ -51,6 +51,7 @@ static const char *none_prefix[] = { NULL };
 
 enum state {
        STATE_IDLE,
+       STATE_RECOVERING,
        STATE_ENABLING,
        STATE_DISABLING,
        STATE_ACTIVE,
@@ -61,11 +62,14 @@ struct gprs_context_data {
        unsigned int active_context;
        char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
        char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
+       char apn[OFONO_GPRS_MAX_APN_LENGTH + 1];
        GAtPPP *ppp;
        enum state state;
        ofono_gprs_context_cb_t cb;
        void *cb_data;                                  /* Callback data */
        unsigned int vendor;
+       guint no_carrier_watch;
+       guint timeout_source;
 };
 
 static void ppp_debug(const char *str, void *data)
@@ -100,6 +104,21 @@ static void ppp_connect(const char *interface, const char 
*local,
        CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
 }
 
+static gboolean remove_no_carrier_cb(gpointer user_data)
+{
+       struct ofono_gprs_context *gc = user_data;
+       struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+
+       DBG("");
+
+       gcd->timeout_source = 0;
+
+       g_at_chat_unregister(gcd->chat, gcd->no_carrier_watch);
+       CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
+
+       return FALSE;
+}
+
 static void ppp_disconnect(GAtPPPDisconnectReason reason, gpointer user_data)
 {
        struct ofono_gprs_context *gc = user_data;
@@ -114,6 +133,18 @@ static void ppp_disconnect(GAtPPPDisconnectReason reason, 
gpointer user_data)
        case STATE_ENABLING:
                CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
                break;
+       case STATE_RECOVERING:
+               gcd->state = STATE_ENABLING;
+               g_at_chat_resume(gcd->chat);
+
+               /*
+                * Place the no carrier callback for limited time because we
+                * don't want to have side effects on other ppp sessions.
+                */
+               gcd->timeout_source = g_timeout_add_seconds(5,
+                                                       remove_no_carrier_cb,
+                                                       gc);
+               return;
        case STATE_DISABLING:
                CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
                break;
@@ -219,6 +250,34 @@ static void at_cgdcont_cb(gboolean ok, GAtResult *result, 
gpointer user_data)
        CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
 }
 
+static void ppp_resume(GAtResult *result, gpointer user_data)
+{
+       struct ofono_gprs_context *gc = user_data;
+       struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+       char buf[OFONO_GPRS_MAX_APN_LENGTH + 128];
+       int len;
+
+       DBG("");
+
+       if (gcd->timeout_source > 0)
+               g_source_remove(gcd->timeout_source);
+
+       g_at_chat_unregister(gcd->chat, gcd->no_carrier_watch);
+
+       len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IP\"",
+                                               gcd->active_context);
+
+       if (gcd->apn)
+               snprintf(buf + len, sizeof(buf) - len - 3, ",\"%s\"",
+                               gcd->apn);
+
+       if (g_at_chat_send(gcd->chat, buf, none_prefix,
+                               at_cgdcont_cb, gc, NULL) > 0)
+               return;
+
+       CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
+}
+
 static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
                                const struct ofono_gprs_primary_context *ctx,
                                ofono_gprs_context_cb_t cb, void *data)
@@ -239,6 +298,27 @@ static void at_gprs_activate_primary(struct 
ofono_gprs_context *gc,
        memcpy(gcd->username, ctx->username, sizeof(ctx->username));
        memcpy(gcd->password, ctx->password, sizeof(ctx->password));
 
+       if (ctx->apn)
+               memcpy(gcd->apn, ctx->apn, sizeof(ctx->apn));
+
+       /*
+        * It might happen for Huawei modems that, when GPRS is no more
+        * attached to the network, oFono core will reset context but the
+        * modem has not ended ppp sesssion at driver level.
+        * In this case trigger a disconnection manually and try to reconnect.
+        */
+       if (gcd->ppp != NULL && gcd->state == STATE_ACTIVE &&
+                       gcd->vendor == OFONO_VENDOR_HUAWEI) {
+               gcd->no_carrier_watch = g_at_chat_register(gcd->chat,
+                                                       "NO CARRIER",
+                                                       ppp_resume, FALSE,
+                                                       gc, NULL);
+               gcd->state = STATE_RECOVERING;
+
+               g_at_ppp_shutdown(gcd->ppp);
+               return;
+       }
+
        gcd->state = STATE_ENABLING;
 
        if (gcd->vendor == OFONO_VENDOR_ZTE) {
-- 
1.7.4.1

_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono

Reply via email to