Initial implementation of the PPP gprs context
authorDenis Kenzior <denkenz@gmail.com>
Wed, 31 Mar 2010 23:49:39 +0000 (18:49 -0500)
committerDenis Kenzior <denkenz@gmail.com>
Wed, 31 Mar 2010 23:49:39 +0000 (18:49 -0500)
drivers/atmodem/gprs-context.c

index a89dcf7..848616a 100644 (file)
 
 #include "gatchat.h"
 #include "gatresult.h"
+#include "gatppp.h"
 
 #include "atmodem.h"
 
-static const char *cgact_prefix[] = { "+CGACT:", NULL };
+#define STATIC_IP_NETMASK "255.255.255.248"
+
 static const char *none_prefix[] = { NULL };
 
+enum state {
+       STATE_IDLE,
+       STATE_ENABLING,
+       STATE_DISABLING,
+       STATE_ACTIVE,
+};
+
 struct gprs_context_data {
        GAtChat *chat;
        unsigned int active_context;
+       char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
+       char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
+       GAtPPP *ppp;
+       enum state state;
+       union {
+               ofono_gprs_context_cb_t down_cb;        /* Down callback */
+               ofono_gprs_context_up_cb_t up_cb;       /* Up callback */
+       };
+       void *cb_data;                                  /* Callback data */
 };
 
 static void at_cgact_down_cb(gboolean ok, GAtResult *result, gpointer user_data)
@@ -63,50 +81,120 @@ static void at_cgact_down_cb(gboolean ok, GAtResult *result, gpointer user_data)
        cb(&error, cbd->data);
 }
 
-static void at_cgact_up_cb(gboolean ok, GAtResult *result, gpointer user_data)
+static void ppp_connect(GAtPPPConnectStatus success,
+                       const char *interface, const char *ip,
+                       const char *dns1, const char *dns2,
+                       gpointer user_data)
 {
-       struct cb_data *cbd = user_data;
-       ofono_gprs_context_up_cb_t cb = cbd->cb;
-       struct ofono_error error;
+       struct ofono_gprs_context *gc = user_data;
+       struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+       const char *dns[3];
 
-       decode_at_error(&error, g_at_result_final_response(result));
+       if (success != G_AT_PPP_CONNECT_SUCCESS) {
+               gcd->active_context = 0;
+               gcd->state = STATE_IDLE;
+
+               CALLBACK_WITH_FAILURE(gcd->up_cb, NULL, 0, NULL, NULL, NULL,
+                                       NULL, gcd->cb_data);
+               return;
+       }
 
-       cb(&error, NULL, 0, NULL, NULL, NULL, NULL, cbd->data);
+       dns[0] = dns1;
+       dns[1] = dns2;
+       dns[2] = 0;
+
+       gcd->state = STATE_ACTIVE;
+       CALLBACK_WITH_SUCCESS(gcd->up_cb, interface, TRUE, ip,
+                                       STATIC_IP_NETMASK, NULL,
+                                       dns, gcd->cb_data);
 }
 
-static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data)
+static void ppp_disconnect(gpointer user_data)
 {
-       struct cb_data *cbd = user_data;
-       ofono_gprs_context_up_cb_t cb = cbd->cb;
-       struct ofono_gprs_context *gc = cbd->user;
+       struct ofono_gprs_context *gc = user_data;
+       struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+
+       ofono_gprs_context_deactivated(gc, gcd->active_context);
+       gcd->active_context = 0;
+       gcd->state = STATE_IDLE;
+}
+
+static gboolean setup_ppp(struct ofono_gprs_context *gc)
+{
+       struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+       GIOChannel *channel;
+
+       channel = g_at_chat_get_channel(gcd->chat);
+       g_at_chat_shutdown(gcd->chat);
+
+       /* open ppp */
+       gcd->ppp = g_at_ppp_new(channel);
+
+       if (gcd->ppp == NULL)
+               return FALSE;
+
+       g_at_ppp_set_credentials(gcd->ppp, gcd->username, gcd->password);
+
+       /* set connect and disconnect callbacks */
+       g_at_ppp_set_connect_function(gcd->ppp, ppp_connect, gc);
+       g_at_ppp_set_disconnect_function(gcd->ppp, ppp_disconnect, gc);
+
+       /* open the ppp connection */
+       g_at_ppp_open(gcd->ppp);
+
+       return TRUE;
+}
+
+static void at_cgdata_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+       struct ofono_gprs_context *gc = user_data;
        struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
-       struct cb_data *ncbd;
-       char buf[64];
 
        if (!ok) {
                struct ofono_error error;
 
+               ofono_info("Unable to enter data state");
+
                gcd->active_context = 0;
+               gcd->state = STATE_IDLE;
 
                decode_at_error(&error, g_at_result_final_response(result));
-               cb(&error, NULL, 0, NULL, NULL, NULL, NULL, cbd->data);
+               gcd->up_cb(&error, NULL, 0, NULL, NULL, NULL, NULL,
+                               gcd->cb_data);
                return;
        }
 
-       ncbd = g_memdup(cbd, sizeof(struct cb_data));
+       setup_ppp(gc);
+}
 
-       snprintf(buf, sizeof(buf), "AT+CGACT=1,%u", gcd->active_context);
+static void at_cgdcont_cb(gboolean ok, 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[64];
 
-       if (g_at_chat_send(gcd->chat, buf, none_prefix,
-                               at_cgact_up_cb, ncbd, g_free) > 0)
+       if (!ok) {
+               struct ofono_error error;
+
+               gcd->active_context = 0;
+               gcd->state = STATE_IDLE;
+
+               decode_at_error(&error, g_at_result_final_response(result));
+               gcd->up_cb(&error, NULL, 0, NULL, NULL, NULL, NULL,
+                               gcd->cb_data);
                return;
+       }
 
-       if (ncbd)
-               g_free(ncbd);
+       sprintf(buf, "AT+CGDATA=\"PPP\",%u", gcd->active_context);
+       if (g_at_chat_send(gcd->chat, buf, none_prefix,
+                               at_cgdata_cb, gc, NULL) > 0)
+               return;
 
        gcd->active_context = 0;
+       gcd->state = STATE_IDLE;
 
-       CALLBACK_WITH_FAILURE(cb, NULL, 0, NULL, NULL, NULL, NULL, cbd->data);
+       CALLBACK_WITH_FAILURE(gcd->up_cb, NULL, 0, NULL, NULL, NULL, NULL,
+                               gcd->cb_data);
 }
 
 static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
@@ -114,18 +202,17 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
                                ofono_gprs_context_up_cb_t cb, void *data)
 {
        struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
-       struct cb_data *cbd = cb_data_new(cb, data);
        char buf[OFONO_GPRS_MAX_APN_LENGTH + 128];
        int len;
 
-       if (!cbd)
-               goto error;
-
        gcd->active_context = ctx->cid;
+       gcd->up_cb = cb;
+       gcd->cb_data = data;
+       memcpy(gcd->username, ctx->username, sizeof(ctx->username));
+       memcpy(gcd->password, ctx->password, sizeof(ctx->password));
 
-       cbd->user = gc;
+       gcd->state = STATE_ENABLING;
 
-       /* TODO: Handle username / password fields */
        len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IP\"", ctx->cid);
 
        if (ctx->apn)
@@ -133,11 +220,8 @@ static void at_gprs_activate_primary(struct ofono_gprs_context *gc,
                                ctx->apn);
 
        if (g_at_chat_send(gcd->chat, buf, none_prefix,
-                               at_cgdcont_cb, cbd, g_free) > 0)
+                               at_cgdcont_cb, gc, NULL) > 0)
                return;
-error:
-       if (cbd)
-               g_free(cbd);
 
        CALLBACK_WITH_FAILURE(cb, NULL, 0, NULL, NULL, NULL, NULL, data);
 }
@@ -168,61 +252,6 @@ error:
        CALLBACK_WITH_FAILURE(cb, data);
 }
 
-static void at_cgact_read_cb(gboolean ok, GAtResult *result,
-                               gpointer user_data)
-{
-       struct ofono_gprs_context *gc = user_data;
-       struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
-       gint cid, state;
-       GAtResultIter iter;
-
-       if (!ok)
-               return;
-
-       while (g_at_result_iter_next(&iter, "+CGACT:")) {
-               if (!g_at_result_iter_next_number(&iter, &cid))
-                       continue;
-
-               if ((unsigned int) cid != gcd->active_context)
-                       continue;
-
-               if (!g_at_result_iter_next_number(&iter, &state))
-                       continue;
-
-               if (state == 1)
-                       continue;
-
-               ofono_gprs_context_deactivated(gc, gcd->active_context);
-               gcd->active_context = 0;
-
-               break;
-       }
-}
-
-static void cgev_notify(GAtResult *result, gpointer user_data)
-{
-       struct ofono_gprs_context *gc = user_data;
-       struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
-       GAtResultIter iter;
-       const char *event;
-
-       if (!g_at_result_iter_next(&iter, "+CGEV:"))
-               return;
-
-       if (!g_at_result_iter_next_unquoted_string(&iter, &event))
-               return;
-
-       if (g_str_has_prefix(event, "NW REACT ") ||
-                       g_str_has_prefix(event, "NW DEACT ") ||
-                       g_str_has_prefix(event, "ME DEACT ")) {
-               /* Ask what primary contexts are active now */
-               g_at_chat_send(gcd->chat, "AT+CGACT?", cgact_prefix,
-                               at_cgact_read_cb, gc, NULL);
-
-               return;
-       }
-}
-
 static int at_gprs_context_probe(struct ofono_gprs_context *gc,
                                        unsigned int vendor, void *data)
 {
@@ -232,8 +261,6 @@ static int at_gprs_context_probe(struct ofono_gprs_context *gc,
        gcd = g_new0(struct gprs_context_data, 1);
        gcd->chat = chat;
 
-       g_at_chat_register(gcd->chat, "+CGEV:", cgev_notify, FALSE, gc, NULL);
-
        ofono_gprs_context_set_data(gc, gcd);
 
        return 0;