[PATCH 09/15] emulator: Implement dialing up for DUN

Zhenhua Zhang zhenhua.zhang at intel.com
Wed Jul 7 03:01:46 PDT 2010


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



More information about the ofono mailing list