It handles client ATD*99# request and complete GPRS connection. Pass
client IP address through IPCP packet to client side.
---
 include/emulator.h |   34 ++++++++
 src/emulator.c     |  226 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 260 insertions(+), 0 deletions(-)

diff --git a/include/emulator.h b/include/emulator.h
index 8b10f8c..b8fb0d5 100644
--- a/include/emulator.h
+++ b/include/emulator.h
@@ -34,6 +34,10 @@ enum ofono_emulator_status {
        OFONO_EMULATOR_STATUS_IDLE = 0,
        OFONO_EMULATOR_STATUS_CREATE,
        OFONO_EMULATOR_STATUS_DESTROY,
+       OFONO_EMULATOR_STATUS_GPRS_CONNECT,
+       OFONO_EMULATOR_STATUS_DUN_CONNECTING,
+       OFONO_EMULATOR_STATUS_DUN_CONNECTED,
+       OFONO_EMULATOR_STATUS_DUN_DISCONNECTED,
 };
 
 enum ofono_emulator_type {
@@ -52,6 +56,36 @@ struct ofono_emulator_driver {
 
 enum _GAtServerResult;
 
+typedef void (*ofono_emulator_cb_t)(enum _GAtServerResult res, void *data);
+
+struct ofono_emulator_req {
+       void *data;
+       ofono_emulator_cb_t cb;
+       void *cb_data;
+};
+
+typedef void (*ofono_emulator_gprs_connect_cb)(const struct ofono_error *error,
+                                               const char *interface,
+                                               const char *local,
+                                               const char *peer,
+                                               const char **dns, void *data);
+
+struct ofono_emulator_gprs_connect_req {
+       const char *dial_str;
+       ofono_emulator_gprs_connect_cb cb;
+       void *cb_data;
+};
+
+struct ofono_emulator_dun_connect_req {
+       const char *iface;
+       const char *local;
+       const char *peer;
+       const char *dns1;
+       const char *dns2;
+       ofono_emulator_cb_t cb;
+       void *cb_data;
+};
+
 const char *ofono_emulator_get_path(struct ofono_emulator *e);
 
 struct ofono_emulator *ofono_emulator_find(struct ofono_modem *modem,
diff --git a/src/emulator.c b/src/emulator.c
index aa203f1..dda74a1 100644
--- a/src/emulator.c
+++ b/src/emulator.c
@@ -29,10 +29,22 @@
 #include <glib.h>
 #include <gdbus.h>
 
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
 #include "ofono.h"
 #include "gatserver.h"
+#include "gatppp.h"
 #include "common.h"
 
+struct context_info {
+       char *interface;
+       char *local;
+       char *peer;
+       char *dns1;
+       char *dns2;
+};
+
 struct ofono_emulator {
        struct ofono_emulator_driver *driver;
        struct ofono_modem *modem;
@@ -40,9 +52,11 @@ struct ofono_emulator {
        unsigned int id;
        void *user_data;
        GAtServer *server;
+       GAtPPP *ppp;
        ofono_bool_t powered;
        enum ofono_emulator_status status;
        struct ofono_watchlist *status_watches;
+       struct context_info *info;
 };
 
 static GSList *emulator_list;
@@ -165,6 +179,210 @@ static void notify_status_watches(struct ofono_emulator 
*e, void *data)
        }
 }
 
+static void ppp_connect_cb(GAtServerResult res, void *user_data)
+{
+       struct ofono_emulator *e = user_data;
+
+       if (res == G_AT_SERVER_RESULT_OK) {
+               DBG("PPP actived!\n");
+               e->status = OFONO_EMULATOR_STATUS_DUN_CONNECTED;
+       } else {
+               DBG("Failed to active PPP connection!\n");
+               e->status = OFONO_EMULATOR_STATUS_IDLE;
+       }
+
+       notify_status_watches(e, NULL);
+}
+
+static void ppp_connect(const char *iface, const char *local, const char *peer,
+                               const char *dns1, const char *dns2,
+                               gpointer user_data)
+{
+       struct ofono_emulator *e = user_data;
+       struct ofono_emulator_dun_connect_req *req;
+
+       DBG("Network Device: %s\n", iface);
+       DBG("IP Address: %s\n", local);
+       DBG("Remote IP Address: %s\n", peer);
+       DBG("Primary DNS Server: %s\n", dns1);
+       DBG("Secondary DNS Server: %s\n", dns2);
+
+       req = g_try_new0(struct ofono_emulator_dun_connect_req, 1);
+       if (!req)
+               return;
+
+       req->iface = iface;
+       req->local = local;
+       req->peer = peer;
+       req->dns1 = dns1;
+       req->dns2 = dns2;
+       req->cb = ppp_connect_cb;
+       req->cb_data = e;
+
+       e->status = OFONO_EMULATOR_STATUS_DUN_CONNECTING;
+
+       notify_status_watches(e, req);
+
+       g_free(req);
+}
+
+static void ppp_disconnect(GAtPPPDisconnectReason reason, gpointer user_data)
+{
+       struct ofono_emulator *e = user_data;
+       struct context_info *info = e->info;
+       struct ofono_emulator_req *req;
+
+       DBG("");
+
+       g_at_ppp_unref(e->ppp);
+       e->ppp = NULL;
+
+       g_at_server_resume(e->server);
+
+       g_free(info->interface);
+       g_free(info->local);
+       g_free(info->peer);
+       g_free(info->dns1);
+       g_free(info->dns2);
+       g_free(info);
+
+       req = ofono_emulator_req_new(generic_cb, e);
+       if (!req)
+               return;
+
+       e->status = OFONO_EMULATOR_STATUS_DUN_DISCONNECTED;
+       notify_status_watches(e, req);
+
+       g_free(req);
+}
+
+static gboolean setup_ppp(gpointer user_data)
+{
+       struct ofono_emulator *e = user_data;
+       GAtServer *server = e->server;
+       GAtIO *io;
+       struct context_info *info = e->info;
+
+       DBG("");
+
+       io = g_at_server_get_io(server);
+
+       /* suspend server port */
+       g_at_server_suspend(server);
+
+       /* open ppp */
+       e->ppp = g_at_ppp_server_new_from_io(io, info->local);
+       if (e->ppp == NULL) {
+               g_at_server_resume(server);
+               return FALSE;
+       }
+
+       g_at_ppp_set_server_info(e->ppp, info->peer, info->dns1, info->dns2);
+       g_at_ppp_set_credentials(e->ppp, "", "");
+       g_at_ppp_set_debug(e->ppp, ofono_emulator_debug, "PPP");
+
+       /* set connect and disconnect callbacks */
+       g_at_ppp_set_connect_function(e->ppp, ppp_connect, e);
+       g_at_ppp_set_disconnect_function(e->ppp, ppp_disconnect, e);
+
+       return FALSE;
+}
+
+static void gprs_connect_cb(const struct ofono_error *error,
+                               const char *interface,
+                               const char *local,
+                               const char *peer,
+                               const char **dns, void *data)
+{
+       struct ofono_emulator *e = data;
+       struct context_info *info;
+
+       DBG("");
+
+       if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+               goto error;
+
+       if (!dns[0] || !dns[1])
+               goto error;
+
+       info = g_try_new0(struct context_info, 1);
+       if (!info)
+               goto error;
+
+       info->interface = g_strdup(interface);
+       info->local = g_strdup(local);
+       info->peer = g_strdup(peer);
+       info->dns1 = g_strdup(dns[0]);
+       info->dns2 = g_strdup(dns[1]);
+
+       e->info = info;
+
+       g_at_server_send_intermediate(e->server, "CONNECT");
+
+       g_idle_add(setup_ppp, e);
+
+       return;
+
+error:
+       g_at_server_send_final(e->server, G_AT_SERVER_RESULT_NO_CARRIER);
+}
+
+static gboolean dial_call(struct ofono_emulator *e, const char *dial_str)
+{
+       char c = *dial_str;
+
+       DBG("dial call %s", dial_str);
+
+       if (c == '*' || c == '#' || c == 'T' || c == 't') {
+               struct ofono_emulator_gprs_connect_req *req;
+
+               req = g_try_new0(struct ofono_emulator_gprs_connect_req, 1);
+               if (!req)
+                       return FALSE;
+
+               req->cb = gprs_connect_cb;
+               req->cb_data = e;
+               req->dial_str = dial_str;
+
+               e->status = OFONO_EMULATOR_STATUS_GPRS_CONNECT;
+               notify_status_watches(e, req);
+
+               g_free(req);
+       }
+
+       return TRUE;
+}
+
+static void dial_cb(GAtServerRequestType type, GAtResult *result,
+                                       gpointer user_data)
+{
+       struct ofono_emulator *e = user_data;
+       GAtServer *server = e->server;
+       GAtServerResult res = G_AT_SERVER_RESULT_ERROR;
+       GAtResultIter iter;
+       const char *dial_str;
+
+       if (type != G_AT_SERVER_REQUEST_TYPE_SET)
+               goto error;
+
+       g_at_result_iter_init(&iter, result);
+
+       if (!g_at_result_iter_next(&iter, "D"))
+               goto error;
+
+       dial_str = g_at_result_iter_raw_line(&iter);
+       if (!dial_str)
+               goto error;
+
+       if (!dial_call(e, dial_str))
+               goto error;
+
+       return;
+
+error:
+       g_at_server_send_final(server, res);
+}
+
 static void emulator_remove(struct ofono_atom *atom)
 {
        struct ofono_emulator *e =  __ofono_atom_get_data(atom);
@@ -190,6 +408,12 @@ void ofono_emulator_disable(struct ofono_emulator *e)
        if (e->server == NULL)
                return;
 
+       if (e->ppp) {
+               g_at_ppp_shutdown(e->ppp);
+               g_at_ppp_unref(e->ppp);
+               e->ppp = NULL;
+       }
+
        e->status = OFONO_EMULATOR_STATUS_DESTROY;
        notify_status_watches(e, NULL);
 
@@ -240,6 +464,8 @@ ofono_bool_t ofono_emulator_enable(struct ofono_emulator 
*e, int fd)
        g_at_server_set_debug(e->server, ofono_emulator_debug, "Server");
        g_at_server_set_disconnect_function(e->server, emulator_disconnect, e);
 
+       g_at_server_register(e->server, "D", dial_cb, e, NULL);
+
        g_io_channel_unref(channel);
 
        e->powered = TRUE;
-- 
1.6.3.3

_______________________________________________
ofono mailing list
ofono@ofono.org
http://lists.ofono.org/listinfo/ofono

Reply via email to