All of lore.kernel.org
 help / color / mirror / Atom feed
* GPRS support for Ofono
@ 2009-09-01 11:09 Ismo Puustinen
  2009-09-01 19:02 ` Jean-Christian de Rivaz
  2009-09-01 21:36 ` Denis Kenzior
  0 siblings, 2 replies; 42+ messages in thread
From: Ismo Puustinen @ 2009-09-01 11:09 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 845 bytes --]

Hello List,

I started working on Ofono GPRS support.

The patch set contains:

1) Documentation describing how an Ofono GPRS D-Bus API would look like.
2) Common Ofono GPRS support.
3) Ofono GPRS ISI driver.
4) Test script for trying out the GPRS functionality.

Note that the GPRS support is in no way completed -- many things are
still TODO or have rough edges. However, I thought that it would be a
good idea to send the patches to the mailing list to gather comments
and improvement suggestions before finalizing the work.

PS. A disclaimer: I'm a Nokia engineer, even though I'm sending this
email from my personal email account (due to incompatibilities with
Nokia email servers). If you need to contact me off-the-list, please
use the email address ismo.h.puustinen(a)nokia.com .

-- 
Ismo Puustinen <ismo@iki.fi>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-GPRS-API-documentation.patch --]
[-- Type: text/x-patch, Size: 5922 bytes --]

From 77d342e3404f5ba7374505f5a65191fa200f52cc Mon Sep 17 00:00:00 2001
From: Ismo Puustinen <ismo.h.puustinen@nokia.com>
Date: Mon, 31 Aug 2009 13:40:22 +0300
Subject: [PATCH] GPRS API documentation

---
 doc/gprs-api.txt        |   69 +++++++++++++++++++++++++++++++++++++++++++
 doc/gprsmanager-api.txt |   74 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 143 insertions(+), 0 deletions(-)
 create mode 100644 doc/gprs-api.txt
 create mode 100644 doc/gprsmanager-api.txt

diff --git a/doc/gprs-api.txt b/doc/gprs-api.txt
new file mode 100644
index 0000000..15daaae
--- /dev/null
+++ b/doc/gprs-api.txt
@@ -0,0 +1,69 @@
+GPRS context hierarchy
+======================
+
+Service     org.ofono
+Interface   org.ofono.GprsContext
+Object path [variable prefix]/{modem0,modem1,...}/{context0,context1,...}
+
+Methods     dict GetProperties()
+
+            Returns all global system properties. See the
+            properties section for available properties.
+
+Signals     PropertyChanged(string property, variant value)
+
+            Signal is emitted whenever a property has changed.
+            The new value is passed as the signal argument.
+
+        ConnectionStatistics(dict statistics)
+
+            Signal is emitted whenever a connection has ended. The
+            signal argument contains a dict with the connection
+            statistics (connection time, transferred bytes).
+
+Properties  string State [readonly]
+
+            Contains the state of the current GPRS context. The state
+            can be one of:
+                - "connecting" - The context is being connected
+                - "connected" - The context is connected
+                - "disconnected" - The context is disconnected, further
+                    use forbidden, since the context will be destroyed
+                    shortly.
+
+        string Type [readonly]
+
+            Contains the connection type ("IPv4" or "IPv6").
+
+        string Address [readonly]
+
+            Contains the IPv4 or IPv6 address of the connection.
+
+        string PrimaryDNSAddress [readonly]
+
+            Contains the primary DNS address returned by the network.
+
+        string SecondaryDNSAddress [readonly]
+
+            Contains the secondary DNS address returned by the network.
+
+        string Interface [readonly]
+
+            Contains the network interface name for the GPRS connection.
+
+        uint32 TransmittedBytes [readonly]
+
+            Contains the amount of bytes transmitted with this GPRS
+            context. This property is not sent with the PropertyChanged
+            signal.
+
+        uint32 ReceivedBytes [readonly]
+
+            Contains the amount of bytes transmitted with this GPRS
+            context. This property is not sent with the PropertyChanged
+            signal.
+
+        uint32 ConnectionTime [readonly]
+
+            Contains the duration of the connection in seconds. This
+            property is not sent with the PropertyChanged signal.
diff --git a/doc/gprsmanager-api.txt b/doc/gprsmanager-api.txt
new file mode 100644
index 0000000..12cfb27
--- /dev/null
+++ b/doc/gprsmanager-api.txt
@@ -0,0 +1,74 @@
+GPRS manager hierarchy
+======================
+
+Service     org.ofono
+Interface   org.ofono.GprsManager
+Object path [variable prefix]/{modem0,modem1,...}
+
+Methods     dict GetProperties()
+
+            Returns all global system properties. See the properties
+            section for available properties.
+
+            Possible Errors: [service].Error.InvalidArguments
+
+        void Attach
+
+            If the GPRS subsystem state is "detached", this will attempt
+            to attach it.
+
+            Possible Errors: [service].Error.AttachFailed
+
+        void Detach
+
+            If the GPRS subsystem state is "attached" or "suspended",
+            this will attempt to detach it.
+
+            Possible Errors: [service].Error.DetachFailed
+
+        object Connect(string apn, string type, string username,
+                        string password, dict optionalArguments)
+
+            Creates a new GPRS context and connects it.  The first
+            parameter is the GPRS Access point name, the second
+            parameter is the connection type ("IPv4" or "IPv6"), the
+            third parameter is the username ("" for no username), and
+            the fourth parameter is the password ("" for no password).
+
+            The last parameter is a dictionary of optional arguments to
+            the GPRS context as key/value pairs. It contains more rarely
+            used connection parameters which already have good default
+            values. An empty dict means that the default values are
+            used.
+
+            The available keys are: TBD.
+
+            Possible Errors: [service].Error.ConnectFailed
+
+        void Disconnect(object context)
+
+            Disconnects and destroys a GPRS context. The context will
+            emit the ConnectionStatistics signal, but its methods or
+            properties may not be called or queried anymore.
+
+            Possible Errors: [service].Error.DisconnectFailed
+
+Signals     PropertyChanged(string property, variant value)
+
+            Signal is emitted whenever a property has changed.  The new
+            value is passed as the signal argument.
+
+Properties  array{object} Contexts [readonly]
+
+            Returns the list of GPRS contexts present in the system. If
+            there are no GPRS contexts, the list will be empty.
+
+        string State [readonly]
+
+            Contains the state of the GPRS subsystem. The state can be
+            one of:
+                - "attached" - the GPRS subsystem is available
+                - "detached" - the GPRS subsystem is not available
+                - "suspended" - the GPRS subsystem is temporarily not
+                    available
+
-- 
1.6.0.4


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-GPRS-Atom.patch --]
[-- Type: text/x-patch, Size: 27945 bytes --]

From a5239566e9283657326177fd87fc11b127f73328 Mon Sep 17 00:00:00 2001
From: Ismo Puustinen <ismo.h.puustinen@nokia.com>
Date: Tue, 1 Sep 2009 12:05:21 +0300
Subject: [PATCH] GPRS Atom

---
 Makefile.am    |    5 +-
 include/gprs.h |  151 ++++++++++
 src/gprs.c     |  854 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/ofono.h    |    1 +
 4 files changed, 1009 insertions(+), 2 deletions(-)
 create mode 100644 include/gprs.h
 create mode 100644 src/gprs.c

diff --git a/Makefile.am b/Makefile.am
index 7ee6536..8b53e78 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,7 +9,8 @@ include_HEADERS = include/log.h include/plugin.h include/history.h \
 			include/call-meter.h include/call-settings.h \
 			include/phonebook.h include/ssn.h include/ussd.h \
 			include/sms.h include/sim.h include/message-waiting.h \
-			include/netreg.h include/voicecall.h include/devinfo.h
+			include/netreg.h include/voicecall.h include/devinfo.h \
+			include/gprs.h
 
 nodist_include_HEADERS = include/version.h
 
@@ -94,7 +95,7 @@ src_ofonod_SOURCES = $(gdbus_sources) $(builtin_sources) \
 			src/call-meter.c src/smsutil.h src/smsutil.c \
 			src/ssn.c src/call-barring.c src/sim.c \
 			src/phonebook.c src/history.c src/message-waiting.c \
-			src/simutil.h src/simutil.c
+			src/simutil.h src/simutil.c src/gprs.c
 
 src_ofonod_LDADD = $(builtin_libadd) \
 			@GLIB_LIBS@ @GTHREAD_LIBS@ @DBUS_LIBS@ -ldl
diff --git a/include/gprs.h b/include/gprs.h
new file mode 100644
index 0000000..aa87e38
--- /dev/null
+++ b/include/gprs.h
@@ -0,0 +1,151 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Ismo Puustinen <ismo.h.puustinen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OFONO_GPRS_H
+#define __OFONO_GPRS_H
+
+#include <ofono/types.h>
+
+#define GPRS_CONTEXT_ID_INVALID 0x100
+
+#define GPRS_TYPE_IPV4 "IPv4"
+#define GPRS_TYPE_IPV6 "IPv6"
+
+/* manager */
+
+#define GPRS_PROPERTY_STATE 				"State"
+
+#define GPRS_STATE_ATTACHED					"attached"
+#define GPRS_STATE_DETACHED					"detached"
+#define GPRS_STATE_SUSPENDED				"suspended"
+
+/* contexts */
+
+#define GPRS_CONTEXT_PROPERTY_STATE 		"State"
+#define GPRS_CONTEXT_PROPERTY_TYPE 			"Type"
+#define GPRS_CONTEXT_PROPERTY_ADDRESS 		"Address"
+#define GPRS_CONTEXT_PROPERTY_PDNS_ADDRESS 	"PrimaryDNSAddress"
+#define GPRS_CONTEXT_PROPERTY_SDNS_ADDRESS 	"SecondaryDNSAddress"
+#define GPRS_CONTEXT_PROPERTY_INTERFACE		"Interface"
+#define GPRS_CONTEXT_PROPERTY_TX_BYTES		"TransmittedBytes"
+#define GPRS_CONTEXT_PROPERTY_RX_BYTES		"ReceivedBytes"
+
+#define GPRS_CONTEXT_STATE_CONNECTING		"connecting"
+#define GPRS_CONTEXT_STATE_CONNECTED		"connected"
+#define GPRS_CONTEXT_STATE_DISCONNECTED		"disconnected"
+
+struct ofono_gprs;
+
+typedef unsigned int ofono_gprs_context_id_t;
+
+/* callbacks */
+
+typedef void (*ofono_gprs_generic_cb_t)(const struct ofono_error *error,
+		void *data);
+
+typedef void (*ofono_gprs_new_context_cb_t)(const struct ofono_error *error,
+		ofono_gprs_context_id_t token,
+		void *data);
+
+typedef void (*ofono_gprs_destroy_context_cb_t)(const struct ofono_error *error,
+		ofono_gprs_context_id_t token,
+		void *data);
+
+/* TODO: add a variant property list as a parameter to the new_context
+ * call -- it will contain the rarely used or modem spesific properties
+ * (QoS, fixed IP address, forced header compression, ...) */
+
+struct ofono_gprs_driver {
+	const char *name;
+	int (*probe)(struct ofono_gprs *manager);
+	int (*remove)(struct ofono_gprs *manager);
+	void (*new_context)(struct ofono_gprs *manager,
+			const char *apn,
+			const char *type,
+			const char *username,
+			const char *password,
+			ofono_gprs_new_context_cb_t cb,
+			void *data);
+	void (*destroy_context)(struct ofono_gprs *manager,
+			ofono_gprs_context_id_t token,
+			ofono_gprs_destroy_context_cb_t cb, void *data);
+	void (*attach)(struct ofono_gprs *manager,
+			ofono_gprs_generic_cb_t cb, void *data);
+	void (*detach)(struct ofono_gprs *manager,
+			ofono_gprs_generic_cb_t cb, void *data);
+};
+
+/* manager-level notification functions */
+
+void ofono_gprs_state_notify(
+		struct ofono_gprs *manager,
+		const char *state);
+
+
+/* context-specific notification functions */
+
+void ofono_gprs_context_state_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, const char *state);
+
+void ofono_gprs_context_type_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, const char *type);
+
+void ofono_gprs_context_address_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, const char *address);
+
+void ofono_gprs_context_pdns_address_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, const char *pdns_address);
+
+void ofono_gprs_context_sdns_address_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, const char *sdns_address);
+
+void ofono_gprs_context_interface_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, const char *interface);
+
+void ofono_gprs_context_tx_bytes_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, uint32_t tx_bytes);
+
+void ofono_gprs_context_rx_bytes_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, uint32_t rx_bytes);
+
+
+/* ofono boilerplate functions */
+
+
+int ofono_gprs_driver_register(const struct ofono_gprs_driver *d);
+void ofono_gprs_driver_unregister(const struct ofono_gprs_driver *d);
+
+struct ofono_gprs *ofono_gprs_create(struct ofono_modem *modem,
+		const char *driver,
+		void *data);
+
+void ofono_gprs_register(struct ofono_gprs *manager);
+void ofono_gprs_remove(struct ofono_gprs *manager);
+
+void ofono_gprs_set_data(struct ofono_gprs *manager, void *data);
+void *ofono_gprs_get_data(struct ofono_gprs *manager);
+
+/* vim: ts=4:noexpandtab:
+*/
+
+#endif
diff --git a/src/gprs.c b/src/gprs.c
new file mode 100644
index 0000000..62fd728
--- /dev/null
+++ b/src/gprs.c
@@ -0,0 +1,854 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Ismo Puustinen <ismo.h.puustinen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/*
+ * TODO:
+ *  - GPRS Manager properties
+ *  - Caching of the property values
+ *  - GetProperties method calls for both Manager and Contexts
+ *  - ConnectionStatistics signal
+ *  - Error handling for partially completed connections
+ *  - Support for querying already active contexts during ofono startup?
+ * */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "ofono.h"
+
+#include "util.h"
+
+#include "gprs.h"
+
+static GSList *g_drivers = NULL;
+
+struct ofono_gprs {
+	char *path;
+	GSList *contexts;
+	DBusMessage *pending;
+	const struct ofono_gprs_driver *driver;
+	void *driver_data;
+	struct ofono_atom *atom;
+};
+
+struct ofono_gprs_context {
+	struct ofono_gprs *manager; /* backpointer */
+	char *path;
+	int to_be_destroyed;
+	int to_be_connected;
+	ofono_gprs_context_id_t token;
+	DBusMessage *pending;
+};
+
+#define GPRS_CONTEXT_INTERFACE "org.ofono.GprsContext"
+
+static ofono_gprs_context_id_t token_from_path(struct ofono_gprs *manager,
+		const char *path)
+{
+	int len = strlen(path);
+	int digits = 0, i;
+
+	/* get the digits from the end of the context path */
+
+	for (i = len-1; i >= 0; i--) {
+		if (isdigit(path[i]))
+			digits++;
+		else
+			break;
+	}
+
+	return strtol(&path[len-digits], NULL, 10);
+}
+
+static char * path_from_token(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token)
+{
+	const char *modem_path = __ofono_atom_get_path(manager->atom);
+	static char path[256];
+
+	snprintf(path, sizeof(path), "%s/gprs%u", modem_path, token);
+
+	return path;
+}
+
+static struct ofono_gprs_context * gprs_find_context(
+		struct ofono_gprs *manager, const char *path)
+{
+	GSList *e = NULL;
+
+	if (!manager)
+		return NULL;
+
+	for (e = manager->contexts; e != NULL; e = g_slist_next(e)) {
+		struct ofono_gprs_context *context = e->data;
+		if (strcmp(path_from_token(manager, context->token), path) == 0) {
+			return context;
+		}
+	}
+
+	return NULL;
+}
+
+static DBusMessage * gprs_context_get_properties(DBusConnection *conn,
+		DBusMessage *msg, void *data)
+{
+	const char *path = dbus_message_get_path(msg);
+	struct ofono_gprs *manager = data;
+	struct ofono_gprs_context *context = gprs_find_context(manager, path);
+
+	/* TODO */
+
+	if (!context) {
+		return __ofono_error_not_found(msg);
+	}
+
+	if (context->pending || context->to_be_destroyed) {
+		return __ofono_error_busy(msg);
+	}
+
+	context->pending = dbus_message_ref(msg);
+	return NULL;
+}
+
+static GDBusMethodTable gprs_context_methods[] = {
+	{ "GetProperties",	"",			"a{sv}",	gprs_context_get_properties },
+	{ }
+};
+
+static GDBusSignalTable gprs_context_signals[] = {
+	{ "PropertyChanged",		"sv" },
+	{ "ConnectionStatistics",	"sv" },
+	{ }
+};
+
+
+static void gprs_context_destroy(gpointer data)
+{
+	ofono_debug("> gprs_context_destroy: %p", data);
+
+	return;
+}
+
+static struct ofono_gprs_context * new_context(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token)
+{
+	DBusConnection *conn = ofono_dbus_get_connection();
+	struct ofono_gprs_context *context = g_new0(struct ofono_gprs_context, 1);
+	char *path = path_from_token(manager, token);
+
+	context->token = token;
+	context->manager = manager;
+
+	if (!g_dbus_register_interface(conn, path,
+				GPRS_CONTEXT_INTERFACE,
+				gprs_context_methods,
+				gprs_context_signals,
+				NULL, context,
+				gprs_context_destroy)) {
+		ofono_error("Could not register GPRS Context interface");
+
+		gprs_context_destroy(context);
+		return NULL;
+	}
+
+	ofono_debug("GPRS Context interface for modem: %s created",
+			path);
+
+	return context;
+
+}
+/* GPRS Manager takes care of the GPRS Context objects */
+
+#define OFONO_GPRS_MANAGER_INTERFACE "org.ofono.GprsManager"
+
+static void gprs_error_disconnect(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token)
+{
+	/* something terrible has happened and we need to disconnect --
+	 * perhaps the connection could not be fully completed */
+
+	/* TODO */
+
+	return;
+}
+
+static DBusMessage * gprs_get_properties(DBusConnection *conn,
+		DBusMessage *msg, void *data)
+{
+	struct ofono_gprs *manager = data;
+
+	/* TODO */
+
+	if (manager->pending) {
+		DBusMessage *reply = __ofono_error_busy(msg);
+		g_dbus_send_message(conn, reply);
+		return NULL;
+	}
+	manager->pending = dbus_message_ref(msg);
+
+	return NULL;
+}
+
+static void gprs_error_handling_cb(const struct ofono_error *error,
+		void *data)
+{
+	struct ofono_gprs *manager = data;
+	DBusMessage *reply = NULL;
+
+	if (!manager || !manager->pending)
+		return;
+
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+		__ofono_dbus_pending_reply(&manager->pending,
+				__ofono_error_failed(manager->pending));
+		return;
+	}
+
+	/* reply to the pending call */
+	reply = dbus_message_new_method_return(manager->pending);
+
+	if (!reply) {
+		/* out of memory, can't even send a reply */
+		return;
+	}
+
+	__ofono_dbus_pending_reply(&manager->pending, reply);
+}
+
+static DBusMessage * gprs_attach(DBusConnection *conn,
+		DBusMessage *msg, void *data)
+{
+	struct ofono_gprs *manager = data;
+
+	ofono_debug("Attach called");
+
+	if (manager->pending) {
+		return __ofono_error_busy(msg);
+	}
+	manager->pending = dbus_message_ref(msg);
+
+	manager->driver->attach(manager, gprs_error_handling_cb, manager);
+
+	return NULL;
+}
+
+static DBusMessage * gprs_detach(DBusConnection *conn,
+		DBusMessage *msg, void *data)
+{
+	struct ofono_gprs *manager = data;
+
+	ofono_debug("Detach called");
+
+	if (manager->pending) {
+		return __ofono_error_busy(msg);
+	}
+	manager->pending = dbus_message_ref(msg);
+
+	manager->driver->detach(manager, gprs_error_handling_cb, manager);
+
+	return NULL;
+}
+
+#if 0
+static bool bogus_event(const struct gprs_property *property)
+{
+	/* TODO */
+
+	return false;
+}
+#endif
+
+static bool send_connection_statistics(DBusConnection *conn,
+		const char *path, struct ofono_gprs_context *context)
+{
+	/* TODO */
+
+	return true;
+}
+
+
+void ofono_gprs_context_state_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, const char *state)
+{
+	/* FIXME: check error and NULL values */
+
+	char *context_path = path_from_token(manager, token);
+	struct ofono_modem *modem = __ofono_atom_get_modem(manager->atom);
+	struct ofono_gprs_context *context = gprs_find_context(manager, context_path);
+	DBusConnection *conn = ofono_dbus_get_connection();
+
+	if (!context || !state) {
+		/* bogus event */
+		goto end;
+	}
+
+	ofono_dbus_signal_property_changed(conn, context_path,
+			GPRS_CONTEXT_INTERFACE,
+			GPRS_CONTEXT_PROPERTY_STATE,
+			DBUS_TYPE_STRING,
+			&state);
+
+	if (strcmp(state, GPRS_CONTEXT_STATE_CONNECTED) == 0) {
+
+		/* reply to the pending call */
+
+		DBusMessage *reply = dbus_message_new_method_return(manager->pending);
+
+		if (!reply) {
+			/* out of memory, can't even send a reply */
+			gprs_error_disconnect(manager, token);
+			if (g_slist_length(manager->contexts) == 1) {
+				ofono_modem_remove_interface(modem, GPRS_CONTEXT_INTERFACE);
+			}
+			goto end;
+		}
+
+		/* The connection is online and ready. Send the reply to the
+		 * D-Bus connection creation message. */
+
+		/* the context is now connected and ready */
+		context->to_be_connected = 0;
+
+		dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
+				&context_path,
+				DBUS_TYPE_INVALID);
+
+		__ofono_dbus_pending_reply(&manager->pending, reply);
+	}
+	else if (strcmp(state, GPRS_CONTEXT_STATE_DISCONNECTED) == 0) {
+
+		if (context->to_be_destroyed) {
+
+			/* User requested that this connection was to be
+			 * destroyed */
+
+			DBusMessage *reply = dbus_message_new_method_return(manager->pending);
+
+			if (!reply) {
+				/* out of memory, can't even send a reply */
+				return;
+			}
+
+			__ofono_dbus_pending_reply(&manager->pending, reply);
+		}
+		else if (context->to_be_connected) {
+
+			/* the context creation did not succeed, send a D-Bus
+			 * error the the user */
+
+			if (manager->pending) {
+				__ofono_dbus_pending_reply(&manager->pending,
+						__ofono_error_failed(manager->pending));
+			}
+		}
+		else {
+			/* network requested connection shutdown */
+		}
+
+		/* Send the ConnectionStatistics signal */
+
+		send_connection_statistics(conn, context_path, context);
+
+		/* Delete our representation of the context only when
+		 * everything is said and done and the ConnectionStatistics
+		 * signal has been sent */
+
+		manager->contexts = g_slist_remove(manager->contexts, context);
+		g_dbus_unregister_interface(conn, context_path, GPRS_CONTEXT_INTERFACE);
+	}
+
+end:
+
+	return;
+}
+
+void ofono_gprs_context_type_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, const char *type)
+{
+	char *context_path = path_from_token(manager, token);
+	DBusConnection *conn = ofono_dbus_get_connection();
+	struct ofono_gprs_context *context = gprs_find_context(manager, context_path);
+
+	if (!context || !type) {
+		/* bogus event */
+		return;
+	}
+
+	ofono_dbus_signal_property_changed(conn, context_path,
+			GPRS_CONTEXT_INTERFACE,
+			GPRS_CONTEXT_PROPERTY_TYPE,
+			DBUS_TYPE_STRING,
+			&type);
+
+	return;
+}
+
+void ofono_gprs_context_address_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, const char *address)
+{
+
+	char *context_path = path_from_token(manager, token);
+	DBusConnection *conn = ofono_dbus_get_connection();
+	struct ofono_gprs_context *context = gprs_find_context(manager, context_path);
+
+	if (!context || !address) {
+		/* bogus event */
+		return;
+	}
+
+	ofono_dbus_signal_property_changed(conn, context_path,
+			GPRS_CONTEXT_INTERFACE,
+			GPRS_CONTEXT_PROPERTY_ADDRESS,
+			DBUS_TYPE_STRING,
+			&address);
+
+	return;
+}
+
+void ofono_gprs_context_pdns_address_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, const char *pdns_address)
+{
+	char *context_path = path_from_token(manager, token);
+	DBusConnection *conn = ofono_dbus_get_connection();
+	struct ofono_gprs_context *context = gprs_find_context(manager, context_path);
+
+	if (!context || !pdns_address) {
+		/* bogus event */
+		return;
+	}
+
+	ofono_dbus_signal_property_changed(conn, context_path,
+			GPRS_CONTEXT_INTERFACE,
+			GPRS_CONTEXT_PROPERTY_PDNS_ADDRESS,
+			DBUS_TYPE_STRING,
+			&pdns_address);
+
+	return;
+}
+
+void ofono_gprs_context_sdns_address_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, const char *sdns_address)
+{
+	char *context_path = path_from_token(manager, token);
+	DBusConnection *conn = ofono_dbus_get_connection();
+	struct ofono_gprs_context *context = gprs_find_context(manager, context_path);
+
+	if (!context || !sdns_address) {
+		/* bogus event */
+		return;
+	}
+
+	ofono_dbus_signal_property_changed(conn, context_path,
+			GPRS_CONTEXT_INTERFACE,
+			GPRS_CONTEXT_PROPERTY_SDNS_ADDRESS,
+			DBUS_TYPE_STRING,
+			&sdns_address);
+
+	return;
+}
+
+void ofono_gprs_context_interface_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, const char *interface)
+{
+	char *context_path = path_from_token(manager, token);
+	DBusConnection *conn = ofono_dbus_get_connection();
+	struct ofono_gprs_context *context = gprs_find_context(manager, context_path);
+
+	if (!context || !interface) {
+		/* bogus event */
+		return;
+	}
+
+	ofono_dbus_signal_property_changed(conn, context_path,
+			GPRS_CONTEXT_INTERFACE,
+			GPRS_CONTEXT_PROPERTY_INTERFACE,
+			DBUS_TYPE_STRING,
+			&interface);
+
+	return;
+}
+
+void ofono_gprs_context_tx_bytes_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, uint32_t tx_bytes)
+{
+	char *context_path = path_from_token(manager, token);
+	DBusConnection *conn = ofono_dbus_get_connection();
+	struct ofono_gprs_context *context = gprs_find_context(manager, context_path);
+
+	if (!context) {
+		/* bogus event */
+		return;
+	}
+
+	ofono_dbus_signal_property_changed(conn, context_path,
+			GPRS_CONTEXT_INTERFACE,
+			GPRS_CONTEXT_PROPERTY_RX_BYTES,
+			DBUS_TYPE_UINT32,
+			&tx_bytes);
+
+	return;
+}
+
+void ofono_gprs_context_rx_bytes_notify(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token, uint32_t rx_bytes)
+{
+	char *context_path = path_from_token(manager, token);
+	DBusConnection *conn = ofono_dbus_get_connection();
+	struct ofono_gprs_context *context = gprs_find_context(manager, context_path);
+
+	if (!context) {
+		/* bogus event */
+		return;
+	}
+
+	ofono_dbus_signal_property_changed(conn, context_path,
+			GPRS_CONTEXT_INTERFACE,
+			GPRS_CONTEXT_PROPERTY_TX_BYTES,
+			DBUS_TYPE_UINT32,
+			&rx_bytes);
+
+	return;
+}
+
+static void gprs_connect_cb(const struct ofono_error *error,
+		ofono_gprs_context_id_t token,
+		void *data)
+{
+	struct ofono_gprs *manager = data;
+	struct ofono_modem *modem = __ofono_atom_get_modem(manager->atom);
+	struct ofono_gprs_context *context = NULL;
+	DBusMessage *reply = NULL;
+
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+		reply = __ofono_error_failed(manager->pending);
+		goto send_reply;
+	}
+
+	context = new_context(manager, token);
+
+	if (!context) {
+		gprs_error_disconnect(manager, token);
+		reply = __ofono_error_failed(manager->pending);
+		goto send_reply;
+	}
+
+	context->to_be_connected = 1;
+
+	if (g_slist_length(manager->contexts) == 0) {
+		ofono_modem_add_interface(modem, GPRS_CONTEXT_INTERFACE);
+	}
+
+	manager->contexts = g_slist_prepend(manager->contexts, context);
+
+	/* success case is handled when the connection gets to a connected
+	 * state, errors when they come */
+
+	return;
+
+send_reply:
+
+	__ofono_dbus_pending_reply(&manager->pending, reply);
+
+	return;
+}
+
+static DBusMessage * gprs_connect(DBusConnection *conn,
+		DBusMessage *msg, void *data)
+{
+	struct ofono_gprs *manager = data;
+	const char *apn, *type, *username, *password;
+	DBusMessageIter iter;
+
+	ofono_debug("Connect called");
+
+	if (manager->pending) {
+		DBusMessage *reply = __ofono_error_busy(msg);
+		g_dbus_send_message(conn, reply);
+		return NULL;
+	}
+
+	dbus_message_iter_init(msg, &iter);
+
+	/* get APN */
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
+		goto err;
+	}
+	dbus_message_iter_get_basic(&iter, &apn);
+	dbus_message_iter_next(&iter);
+
+	/* get type */
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
+		goto err;
+	}
+	dbus_message_iter_get_basic(&iter, &type);
+	dbus_message_iter_next(&iter);
+
+	/* get username */
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
+		goto err;
+	}
+	dbus_message_iter_get_basic(&iter, &username);
+	dbus_message_iter_next(&iter);
+
+	/* get password */
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
+		goto err;
+	}
+	dbus_message_iter_get_basic(&iter, &password);
+
+	/* skip the extra options dict for now */
+
+	manager->pending = dbus_message_ref(msg);
+
+	/* create the connection */
+
+	manager->driver->new_context(manager,
+			apn, type, username, password,
+			gprs_connect_cb,
+			manager);
+
+	return NULL;
+
+err:
+	return __ofono_error_invalid_args(msg);
+}
+
+static void gprs_destroy_cb(const struct ofono_error *error,
+		ofono_gprs_context_id_t token,
+		void *data)
+{
+	struct ofono_gprs *manager = data;
+	struct ofono_gprs_context *context = NULL;
+
+	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+		__ofono_dbus_pending_reply(&manager->pending,
+				__ofono_error_failed(manager->pending));
+		return;
+	}
+
+	/* Mark the interface as non-active, so that nothing can be done
+	 * with it until the ConnectionStatistics signal arrives and the
+	 * context is finally removed. */
+
+	context = gprs_find_context(manager, path_from_token(manager, token));
+
+	if (context) {
+		context->to_be_destroyed = 1;
+	}
+	else {
+		/* something fishy is going on */
+	}
+
+	return;
+}
+
+static DBusMessage * gprs_disconnect(DBusConnection *conn,
+		DBusMessage *msg, void *data)
+{
+	struct ofono_gprs *manager = data;
+	const char *path;
+	struct ofono_gprs_context *context = NULL;
+
+	ofono_debug("Disconnect called");
+
+	if (manager->pending) {
+		return __ofono_error_busy(msg);
+	}
+
+	if (!dbus_message_get_args(
+				msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) {
+		return __ofono_error_invalid_args(msg);
+	}
+
+	context = gprs_find_context(manager, path);
+
+	if (!context || context->to_be_destroyed) {
+		return __ofono_error_not_found(msg);
+	}
+
+	manager->pending = dbus_message_ref(msg);
+
+	manager->driver->destroy_context(manager, token_from_path(manager, path),
+			gprs_destroy_cb, manager);
+
+	return NULL;
+}
+
+static GDBusMethodTable gprs_manager_methods[] = {
+	{ "GetProperties",	"",			"a{sv}",	gprs_get_properties },
+	{ "Attach",			"",			"",			gprs_attach, G_DBUS_METHOD_FLAG_ASYNC  },
+	{ "Detach",			"",			"",			gprs_detach, G_DBUS_METHOD_FLAG_ASYNC  },
+	{ "Connect",		"ssssa{sv}","o",		gprs_connect, G_DBUS_METHOD_FLAG_ASYNC  },
+	{ "Disconnect",		"o",		"",			gprs_disconnect, G_DBUS_METHOD_FLAG_ASYNC  },
+	{ }
+};
+
+static GDBusSignalTable gprs_manager_signals[] = {
+	{ "PropertyChanged",	"sv" },
+	{ }
+};
+
+void ofono_gprs_state_notify(
+		struct ofono_gprs *manager,
+		const char *state)
+{
+	/* TODO */
+	return;
+}
+
+
+/* ofono boilerplate code begins */
+
+
+
+static void gprs_remove(struct ofono_atom *atom)
+{
+	struct ofono_gprs *manager = __ofono_atom_get_data(atom);
+
+	DBG("atom: %p", atom);
+
+	if (manager == NULL)
+		return;
+
+	if (manager->driver && manager->driver->remove)
+		manager->driver->remove(manager);
+
+	g_free(manager);
+}
+
+int ofono_gprs_driver_register(const struct ofono_gprs_driver *d)
+{
+	DBG("driver: %p, name: %s", d, d->name);
+
+	if (d->probe == NULL)
+		return -EINVAL;
+
+	g_drivers = g_slist_prepend(g_drivers, (void *)d);
+
+	return 0;
+}
+
+void ofono_gprs_driver_unregister(const struct ofono_gprs_driver *d)
+{
+	DBG("driver: %p, name: %s", d, d->name);
+
+	g_drivers = g_slist_remove(g_drivers, (void *)d);
+}
+
+struct ofono_gprs *ofono_gprs_create(struct ofono_modem *modem,
+		const char *driver, void *data)
+{
+	struct ofono_gprs *manager;
+	GSList *l;
+
+	if (driver == NULL)
+		return NULL;
+
+	manager = g_try_new0(struct ofono_gprs, 1);
+
+	if (manager == NULL)
+		return NULL;
+
+	manager->driver_data = data;
+	manager->pending = NULL;
+	manager->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_GPRS,
+			gprs_remove, manager);
+
+	DBG("Probing GPRS drivers");
+
+	for (l = g_drivers; l; l = l->next) {
+		const struct ofono_gprs_driver *drv = l->data;
+
+		if (g_strcmp0(drv->name, driver))
+			continue;
+
+		if (drv->probe(manager) < 0)
+			continue;
+
+		manager->driver = drv;
+		break;
+	}
+
+	return manager;
+}
+
+static void gprs_unregister(struct ofono_atom *atom)
+{
+	struct ofono_gprs *manager = __ofono_atom_get_data(atom);
+	const char *path = __ofono_atom_get_path(manager->atom);
+	DBusConnection *conn = ofono_dbus_get_connection();
+	struct ofono_modem *modem = __ofono_atom_get_modem(manager->atom);
+
+	ofono_modem_remove_interface(modem, OFONO_GPRS_MANAGER_INTERFACE);
+	g_dbus_unregister_interface(conn, path, OFONO_GPRS_MANAGER_INTERFACE);
+}
+
+void ofono_gprs_register(struct ofono_gprs *manager)
+{
+	DBusConnection *conn = ofono_dbus_get_connection();
+	const char *path = __ofono_atom_get_path(manager->atom);
+	struct ofono_modem *modem = __ofono_atom_get_modem(manager->atom);
+
+	DBG("Registering GPRS manager interface on path %s", path);
+
+	if (!g_dbus_register_interface(conn, path, OFONO_GPRS_MANAGER_INTERFACE,
+				gprs_manager_methods, gprs_manager_signals,
+				NULL, manager, NULL)) {
+		ofono_error("Could not create %s interface",
+				OFONO_GPRS_MANAGER_INTERFACE);
+
+		return;
+	}
+
+	ofono_modem_add_interface(modem, OFONO_GPRS_MANAGER_INTERFACE);
+
+	__ofono_atom_register(manager->atom, gprs_unregister);
+
+	return;
+}
+
+void ofono_gprs_set_data(struct ofono_gprs *gprs, void *data)
+{
+	gprs->driver_data = data;
+}
+
+void *ofono_gprs_get_data(struct ofono_gprs *gprs)
+{
+	return gprs->driver_data;
+}
+
+/* vim: ts=4:noexpandtab:
+*/
+
diff --git a/src/ofono.h b/src/ofono.h
index bf31531..5eda013 100644
--- a/src/ofono.h
+++ b/src/ofono.h
@@ -82,6 +82,7 @@ enum ofono_atom_type {
 	OFONO_ATOM_TYPE_HISTORY = 11,
 	OFONO_ATOM_TYPE_SSN = 12,
 	OFONO_ATOM_TYPE_MESSAGE_WAITING = 13,
+	OFONO_ATOM_TYPE_GPRS = 14,
 };
 
 enum ofono_atom_watch_condition {
-- 
1.6.0.4


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0003-GPRS-ISI-modem-driver.patch --]
[-- Type: text/x-patch, Size: 41966 bytes --]

From 38760be738440f047b28f0d274d15a0990e3c6e4 Mon Sep 17 00:00:00 2001
From: Ismo Puustinen <ismo.h.puustinen@nokia.com>
Date: Mon, 31 Aug 2009 13:49:07 +0300
Subject: [PATCH] GPRS ISI modem driver

---
 Makefile.am                 |    1 +
 drivers/isimodem/gprs.c     | 1759 +++++++++++++++++++++++++++++++++++++++++++
 drivers/isimodem/isi.h      |    4 +
 drivers/isimodem/isimodem.c |    4 +
 4 files changed, 1768 insertions(+), 0 deletions(-)
 create mode 100644 drivers/isimodem/gprs.c

diff --git a/Makefile.am b/Makefile.am
index 8b53e78..a5d8c32 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -52,6 +52,7 @@ builtin_sources += $(gisi_sources) drivers/isimodem/isi.h \
 				drivers/isimodem/sim.c \
 				drivers/isimodem/ssn.c \
 				drivers/isimodem/ussd.c \
+				drivers/isimodem/gprs.c \
 				drivers/isimodem/call-forwarding.c \
 				drivers/isimodem/call-settings.c \
 				drivers/isimodem/call-barring.c \
diff --git a/drivers/isimodem/gprs.c b/drivers/isimodem/gprs.c
new file mode 100644
index 0000000..599c298
--- /dev/null
+++ b/drivers/isimodem/gprs.c
@@ -0,0 +1,1759 @@
+/*
+ * This file is part of oFono - Open Source Telephony
+ *
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Contact: Ismo Puustinen <ismo.h.puustinen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/*
+ * TODO:
+ *  - Better error handling!
+ *  - Helper functions for creating the ISI messages in a cleaner way
+ *  - Helper functions for parsing the ISI messages
+ *  - Support for fetching the GPRS interface information
+ *  - GPRS authentication support
+ *  - Support for querying already active contexts during ofono startup?
+ * */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <net/if.h>
+
+#include <glib.h>
+#include <gisi/client.h>
+#include <gisi/pipe.h>
+#include <gisi/pep.h>
+#include <gisi/phonet.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/gprs.h>
+#include "util.h"
+#include "isi.h"
+
+#define PN_GPDS				0x31
+#define GPDS_TIMEOUT		60
+
+enum message_id {
+	GPDS_LL_CONFIGURE_REQ = 0x00,
+	GPDS_LL_CONFIGURE_RESP = 0x01,
+	GPDS_CONTEXT_ID_CREATE_REQ = 0x02,
+	GPDS_CONTEXT_ID_CREATE_RESP = 0x03,
+	GPDS_CONTEXT_ID_CREATE_IND = 0x04,
+	GPDS_CONTEXT_ID_DELETE_IND = 0x05,
+	GPDS_CONTEXT_CONFIGURE_REQ = 0x06,
+	GPDS_CONTEXT_CONFIGURE_RESP = 0x07,
+	GPDS_CONTEXT_ACTIVATE_REQ = 0x08,
+	GPDS_CONTEXT_ACTIVATE_RESP = 0x09,
+	GPDS_CONTEXT_ACTIVATE_IND = 0x0A,
+	GPDS_CONTEXT_DEACTIVATE_REQ = 0x0B,
+	GPDS_CONTEXT_DEACTIVATE_RESP = 0x0C,
+	GPDS_CONTEXT_DEACTIVATE_IND = 0x0D,
+	GPDS_ATTACH_REQ = 0x13,
+	GPDS_ATTACH_RESP = 0x14,
+	GPDS_ATTACH_IND = 0x15,
+	GPDS_DETACH_REQ = 0x16,
+	GPDS_DETACH_RESP = 0x17,
+	GPDS_DETACH_IND = 0x18,
+	GPDS_TRANSFER_STATUS_IND = 0x1E,
+	GPDS_CONTEXT_ACTIVATE_FAIL_IND = 0x1F,
+	GPDS_CONTEXT_STATUS_IND = 0x24,
+	GPDS_CONTEXT_ACTIVATING_IND = 0x25,
+	GPDS_CONTEXT_DEACTIVATING_IND = 0x2F,
+	GPDS_CONFIGURATION_INFO_IND = 0x32,
+	GPDS_CONTEXT_AUTH_REQ = 0x33,
+	GPDS_CONTEXT_AUTH_RESP = 0x34,
+	GPDS_RESOURCE_CONTROL_IND = 0x50,
+};
+
+enum gpds_status {
+	GPDS_ERROR = 0x00,
+	GPDS_OK = 0x01,
+	GPDS_FAIL = 0x02
+};
+
+enum gpds_pdp_type {
+	GPDS_PDP_TYPE_PPP = 0x01,
+	GPDS_PDP_TYPE_IPV4 = 0x21,
+	GPDS_PDP_TYPE_IPV6 = 0x57,
+	GPDS_PDP_TYPE_DEFAULT = 0xFF
+};
+
+enum gprs_context_state {
+	GPRS_CONTEXT_INITED,
+	GPRS_CONTEXT_ID_REQUESTED,
+	GPRS_CONTEXT_LOCAL_LINK_CONFIGURED,
+	GPRS_CONTEXT_CONFIGURED,
+	GPRS_CONTEXT_ACTIVATING,
+	GPRS_CONTEXT_ACTIVATED,
+	GPRS_CONTEXT_PIPE_CREATED,
+	GPRS_CONTEXT_PIPE_STARTED,
+	GPRS_CONTEXT_CONNECTED,
+	GPRS_CONTEXT_DEACTIVATING,
+	GPRS_CONTEXT_DEACTIVATED,
+	GPRS_CONTEXT_FINISHED
+};
+
+struct gprs_data {
+	GIsiClient *client;
+	GIsiModem *isi_modem;
+	struct isi_version version;
+	struct ofono_gprs *manager; /* manager for this modem */
+	GSList *contexts;
+};
+
+/* There are two possiblities: either we keep the driver data as an
+ * opaque structure on the user side, or we keep local track of all
+ * contexts. */
+
+struct context_data {
+
+	/* This is the callback data for the context creation request. */
+	struct isi_cb_data *cbd;
+
+	/* This is the callback data for the context disconnection request. */
+	struct isi_cb_data *destroy_cbd;
+
+	/* This is the callback data for the context property updates. */
+	struct isi_cb_data *property_cbd;
+
+	char *apn;
+	unsigned char type;
+	char *username;
+	char *password;
+
+	enum gprs_context_state prev_state;
+	enum gprs_context_state state;
+
+	ofono_gprs_context_id_t token;
+	GIsiPipe *pipe;
+	GIsiPEP *pep;
+	uint16_t gpds_object;
+
+	union {
+		struct in_addr ipv4_addr;
+		struct in6_addr ipv6_addr;
+	} pdp_addr;
+	char pdp_addr_s[INET6_ADDRSTRLEN];
+
+	union {
+		struct in_addr ipv4_addr;
+		struct in6_addr ipv6_addr;
+	} pdns_addr;
+	char pdns_addr_s[INET6_ADDRSTRLEN];
+
+	union {
+		struct in_addr ipv4_addr;
+		struct in6_addr ipv6_addr;
+	} sdns_addr;
+	char sdns_addr_s[INET6_ADDRSTRLEN];
+};
+
+static struct context_data * gprs_find_context_by_pep(
+		struct gprs_data *data,
+		GIsiPEP *pep)
+{
+	GSList *e = NULL;
+
+	for (e = data->contexts; e != NULL; e = g_slist_next(e)) {
+		struct context_data *context = e->data;
+		if (pep == context->pep) {
+			return context;
+		}
+	}
+
+	return NULL;
+}
+
+static struct context_data * gprs_find_context(
+		struct gprs_data *data, ofono_gprs_context_id_t token)
+{
+	GSList *e = NULL;
+
+	for (e = data->contexts; e != NULL; e = g_slist_next(e)) {
+		struct context_data *context = e->data;
+		if (token == context->token) {
+			return context;
+		}
+	}
+
+	return NULL;
+}
+
+static void connection_sm(struct gprs_data *data,
+		struct context_data *c_data,
+		enum gprs_context_state new_state);
+
+
+static void delete_cdata(struct context_data *c_data)
+{
+	DBG("Freeing context data structure %p", c_data);
+
+	g_free(c_data);
+
+	return;
+}
+
+static void handle_gprs_context_error(struct gprs_data *data,
+		struct context_data *c_data,
+		struct ofono_error *err)
+{
+
+	/* This function is very much TODO */
+
+	/* if the connection creation is not successful, try to remove
+	 * already initialized parts of the connection */
+
+	ofono_gprs_new_context_cb_t cb;
+
+	DBG("GPRS error handler called...");
+
+	if (!c_data)
+		return;
+
+	DBG("... state %d", c_data->state);
+
+	if (c_data->cbd) {
+
+		cb = c_data->cbd->cb;
+
+		cb(err, c_data->token, c_data->cbd->data);
+
+		switch (c_data->state) {
+			case GPRS_CONTEXT_INITED:
+				/* No need to send property update, since the context
+				 * was never created */
+				goto end;
+			case GPRS_CONTEXT_ID_REQUESTED:
+				break;
+			case GPRS_CONTEXT_LOCAL_LINK_CONFIGURED:
+				break;
+			case GPRS_CONTEXT_CONFIGURED:
+				break;
+			case GPRS_CONTEXT_ACTIVATING:
+				break;
+			case GPRS_CONTEXT_ACTIVATED:
+				break;
+			case GPRS_CONTEXT_PIPE_CREATED:
+				break;
+			case GPRS_CONTEXT_PIPE_STARTED:
+				break;
+			case GPRS_CONTEXT_CONNECTED:
+				break;
+			case GPRS_CONTEXT_DEACTIVATING:
+				break;
+			case GPRS_CONTEXT_DEACTIVATED:
+				break;
+			case GPRS_CONTEXT_FINISHED:
+				break;
+		}
+
+	}
+
+	ofono_gprs_context_state_notify(data->manager, c_data->token,
+			GPRS_CONTEXT_STATE_DISCONNECTED);
+
+end:
+
+	delete_cdata(c_data);
+	return;
+}
+
+static bool parse_msg(int header_len, unsigned char **subs, int n_subs,
+		unsigned char *msg, int msg_len)
+{
+	int i;
+	unsigned char *msg_p;
+
+	if (n_subs < 1 || msg_len <= header_len) {
+		/* no subs to find */
+		DBG("No sub blocks to parse");
+		return false;
+	}
+
+	msg_p = &msg[header_len]; /* beginning of the first sub block */
+
+	for (i = 0; i < n_subs; i++) {
+		unsigned char sub_len = *(msg_p + 1);
+		subs[i] = msg_p;
+		msg_p = msg_p + sub_len;
+	}
+
+	if (msg_p - msg > msg_len) {
+		DBG("Message parsing failed");
+		return false;
+	}
+
+	return true;
+}
+
+static bool start_interface(struct gprs_data *data, struct context_data *c_data)
+{
+	return true;
+}
+
+static bool context_activate_resp_cb(GIsiClient *client, const void *restrict data,
+		size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct gprs_data *gprs_data = opaque;
+	struct context_data *c_data = NULL;
+	/* char *subs[6]; */
+	int n_subs;
+
+	DBG("> context_activate_resp_cb");
+
+	/* sanity checks */
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	dump_msg(msg, len);
+
+	if (len < 7) {
+		DBG("Wrong message length");
+		goto error;
+	}
+
+	if (msg[0] != GPDS_CONTEXT_ACTIVATE_RESP) {
+		DBG("Unexpected message ID: 0x%02x", msg[0]);
+		goto error;
+	}
+
+	c_data = gprs_find_context(gprs_data, msg[1]);
+	if (!c_data) {
+		DBG("Unknown PDP context: %d", msg[1]);
+		goto error;
+	}
+
+	if (msg[2] != GPDS_OK) {
+		DBG("Context activation error");
+		goto error;
+	}
+
+	n_subs = msg[6];
+
+	if (n_subs > 6) {
+		DBG("Too many sub blocks");
+		goto error;
+	}
+
+	return true;
+
+error:
+
+	DBG("Error activating the context");
+
+	{
+		DECLARE_FAILURE(error);
+		handle_gprs_context_error(gprs_data, c_data, &error);
+	}
+	return false;
+}
+
+
+static bool context_activate_req(struct gprs_data *data, struct context_data *c_data)
+{
+	const unsigned char msg_header[] = {
+		GPDS_CONTEXT_ACTIVATE_REQ,
+		c_data->token, /* CID */
+		0x01,  /* number of sub blocks */
+	};
+	unsigned char *msg;
+	GIsiRequest *req = NULL;
+	int addr_len, pdp_block_len, filler, msg_len;
+
+	/* we can have either IPv4 or IPv6 addresses */
+
+	DBG("> context_activate_req");
+
+	if (c_data->type == GPDS_PDP_TYPE_IPV6) {
+		addr_len = sizeof(struct in6_addr);
+	}
+	else {
+		/* default case */
+		addr_len = sizeof(struct in_addr);
+	}
+
+	filler = (4 + addr_len) % 4; /* ( PDP block header + PDP address length ) modulo 4 */
+	pdp_block_len = 4 + addr_len + filler;
+	msg_len = 3 + pdp_block_len;
+	msg = malloc(msg_len);
+
+	if (!msg)
+		goto error;
+
+	/* zero (for the address and the end filler bytes) */
+	memset(msg, 0, msg_len);
+
+	memcpy(msg, msg_header, sizeof(msg_header));
+
+	msg[3] = 0x04; /* GPDS_PDP_ADDRESS_INFO */
+	msg[4] = pdp_block_len;
+	msg[5] = 0x00; /* filler */
+	msg[6] = addr_len; /* filler */
+
+	/* the address is just zeroes */
+
+	DBG("The activation request:");
+	dump_msg(msg, msg_len);
+
+	req = g_isi_request_make(data->client, msg, msg_len, GPDS_TIMEOUT,
+			context_activate_resp_cb, data);
+
+	free(msg);
+
+	if (req) {
+		return true;
+	}
+
+error:
+
+	return false;
+}
+
+static bool context_configure_resp_cb(GIsiClient *client, const void *restrict data,
+		size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct context_data *c_data = NULL;
+	struct gprs_data *gprs_data = opaque;
+
+	DBG("> context_configure_resp_cb");
+
+	/* sanity checks */
+
+	if (!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	dump_msg(msg, len);
+
+	if (len != 3) {
+		DBG("Wrong message length");
+		goto error;
+	}
+
+	c_data = gprs_find_context(gprs_data, msg[1]);
+	if (!c_data) {
+		DBG("Unknown PDP context: %d", msg[1]);
+		goto error;
+	}
+
+	if (msg[0] != GPDS_CONTEXT_CONFIGURE_RESP) {
+		DBG("Unexpected message ID: 0x%02x", msg[0]);
+		goto error;
+	}
+
+	if (msg[1] != c_data->token || msg[2] != GPDS_OK) {
+		DBG("Context configuration error");
+		goto error;
+	}
+
+	/* Next phase: configure the context */
+
+	connection_sm(gprs_data, c_data, GPRS_CONTEXT_CONFIGURED);
+
+	return true;
+
+error:
+
+	{
+		DECLARE_FAILURE(error);
+		handle_gprs_context_error(gprs_data, c_data, &error);
+	}
+	return false;
+}
+
+static bool context_configure_req(struct gprs_data *data, struct context_data *c_data)
+{
+	const unsigned char msg_header[] = {
+		GPDS_CONTEXT_CONFIGURE_REQ,
+		c_data->token, /* CID */
+		c_data->type, /* IPv4 or IPv6 */
+		0x00, /* GPDS_CONT_TYPE_NORMAL */
+		c_data->token, /* primary CID */
+		0x00, /* filler */
+		0x02  /* number of sub blocks */
+	};
+	unsigned char *msg;
+	GIsiRequest *req = NULL;
+	int apn_len, apn_block_len, msg_len, filler;
+
+	DBG("> context_configure_req (apn: '%s')", c_data->apn);
+
+	/* sanity checks */
+
+	apn_len = strlen(c_data->apn);
+	if (apn_len > 100)
+		goto error;
+
+	filler = (3 + apn_len) % 4; /* ( APN block header + APN length ) modulo 4 */
+	apn_block_len = 3 + apn_len + filler;
+
+	DBG("apn_len: %d, apn_block_len: %d, filler: %d", apn_len, apn_block_len, filler);
+
+	/* header length + APN block length + DNS block length */
+	msg_len = 7 + apn_block_len + 4;
+
+	msg = malloc(msg_len);
+
+	if (!msg)
+		goto error;
+
+	/* zero (for the end filler bytes) */
+	memset(msg, 0, msg_len);
+
+	/* APN sub block */
+
+	memcpy(msg, msg_header, 7);
+	msg[7] = 0x05; /* GPDS_APN_INFO */
+	msg[8] = apn_block_len;
+	msg[9] = apn_len;
+	memcpy(&msg[10], c_data->apn, apn_len);
+
+	/* DNS sub block */
+
+	msg[7+apn_block_len] = 0x90; /* GPDS_DNS_ADDRESS_INFO */
+	msg[7+apn_block_len+1] = 0x04; /* sub block length */
+	/* the two last bytes are filler */
+
+	DBG("The configuration request:");
+	dump_msg(msg, msg_len);
+
+	req = g_isi_request_make(data->client, msg, msg_len, GPDS_TIMEOUT,
+			context_configure_resp_cb, data);
+
+	free(msg);
+
+	if (req) {
+		return true;
+	}
+
+error:
+
+	return false;
+}
+
+static bool context_configure_ll_resp_cb(GIsiClient *client, const void *restrict data,
+		size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct context_data *c_data = NULL;
+	struct gprs_data *gprs_data = opaque;
+
+	DBG("> context_configure_ll_resp_cb");
+
+	/* sanity checks */
+
+	if(!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	dump_msg(msg, len);
+
+	if (len != 3) {
+		DBG("Wrong message length");
+		goto error;
+	}
+
+	c_data = gprs_find_context(gprs_data, msg[1]);
+	if (!c_data) {
+		DBG("Unknown PDP context: %d", msg[1]);
+		goto error;
+	}
+
+	if (msg[0] != GPDS_LL_CONFIGURE_RESP) {
+		DBG("Unexpected message ID: 0x%02x", msg[0]);
+		goto error;
+	}
+
+	if (msg[1] != c_data->token || msg[2] != GPDS_OK) {
+		DBG("Context  local link configuration error");
+		goto error;
+	}
+
+	connection_sm(gprs_data, c_data, GPRS_CONTEXT_LOCAL_LINK_CONFIGURED);
+
+	return true;
+
+error:
+
+	{
+		DECLARE_FAILURE(error);
+		handle_gprs_context_error(gprs_data, c_data, &error);
+	}
+	return false;
+}
+
+static bool context_configure_ll_req(struct gprs_data *data, struct context_data *c_data)
+{
+	GIsiPipe *pipe = c_data->pipe;
+	const unsigned char msg[] = {
+		GPDS_LL_CONFIGURE_REQ,
+		c_data->token, /* context identifier */
+		g_isi_pipe_get_handle(pipe), /* Phonet pipe handle */
+		0x02 /* GPDS_LL_PLAIN */
+	};
+	GIsiRequest *req = NULL;
+
+	DBG("> context_configure_ll_req");
+
+	DBG("The local link configuration request:");
+	dump_msg(msg, sizeof(msg));
+
+	req = g_isi_request_make(data->client, msg, sizeof(msg), GPDS_TIMEOUT,
+			context_configure_ll_resp_cb, data);
+
+	if (req) {
+		return true;
+	}
+
+	return false;
+}
+static bool context_id_create_resp_cb(GIsiClient *client, const void *restrict data,
+		size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct context_data *c_data = NULL;
+	struct gprs_data *gprs_data = opaque;
+
+	DBG("> context_id_create_resp_cb");
+
+	/* sanity checks */
+
+	if(!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	dump_msg(msg, len);
+
+	if (len != 3) {
+		DBG("Wrong message length");
+		goto error;
+	}
+
+	if (msg[0] != GPDS_CONTEXT_ID_CREATE_RESP) {
+		DBG("Unexpected message ID: 0x%02x", msg[0]);
+		goto error;
+	}
+
+	c_data = gprs_find_context(gprs_data, GPRS_CONTEXT_ID_INVALID);
+	if (!c_data) {
+		DBG("The just-created context was not found!");
+		goto error;
+	}
+
+	c_data->token = msg[1];
+
+	if (msg[2] != GPDS_OK) {
+		DBG("Context creation error");
+		goto error;
+	}
+
+	c_data->token = msg[1];
+	c_data->gpds_object = object;
+
+	/* Next phase: configure the context */
+
+	connection_sm(gprs_data, c_data, GPRS_CONTEXT_ID_REQUESTED);
+
+	return true;
+
+error:
+
+	{
+		DECLARE_FAILURE(error);
+		handle_gprs_context_error(gprs_data, c_data, &error);
+	}
+	return false;
+}
+
+static bool context_id_create_req(struct gprs_data *data, struct context_data *c_data)
+{
+	const unsigned char msg[] = {
+		GPDS_CONTEXT_ID_CREATE_REQ
+	};
+	GIsiRequest *req = NULL;
+
+	DBG("> context_id_create_req");
+
+	req = g_isi_request_make(data->client, msg, sizeof(msg), GPDS_TIMEOUT,
+			context_id_create_resp_cb, data);
+
+	if (req) {
+		return true;
+	}
+
+	return false;
+}
+
+static bool context_start_pipe(struct gprs_data *data, struct context_data *c_data)
+{
+	int ret = g_isi_pipe_start(c_data->pipe);
+
+	DBG("> context_start_pipe");
+
+	if (ret != 0) {
+		DBG("Pipe activation failed: %d", ret);
+		return false;
+	}
+
+	c_data->state = GPRS_CONTEXT_PIPE_STARTED;
+	return true;
+}
+
+struct pipe_data {
+	struct gprs_data *gprs_data;
+	ofono_gprs_context_id_t token;
+};
+
+static void context_create_pipe_error_cb(GIsiPipe *pipe)
+{
+	struct context_data *c_data = NULL;
+	struct pipe_data *pipe_data = g_isi_pipe_get_userdata(pipe);
+
+	DBG("Pipe creation error callback called, pipe: %p", pipe);
+
+	c_data = gprs_find_context(pipe_data->gprs_data, pipe_data->token);
+
+	if (c_data) {
+		DECLARE_FAILURE(error);
+		handle_gprs_context_error(pipe_data->gprs_data, c_data, &error);
+	}
+
+	return;
+}
+
+static void context_create_pipe_cb(GIsiPipe *pipe)
+{
+	struct context_data *c_data = NULL;
+	struct pipe_data *pipe_data = g_isi_pipe_get_userdata(pipe);
+
+	DBG("Pipe creation callback called, pipe: %p", pipe);
+
+	c_data = gprs_find_context(pipe_data->gprs_data, pipe_data->token);
+
+	if (!c_data)
+		return;
+
+	c_data->pipe = pipe; /* redundant? */
+
+	if (!c_data->pipe)
+		goto error;
+
+	c_data->pipe = pipe;
+
+	connection_sm(pipe_data->gprs_data, c_data, GPRS_CONTEXT_PIPE_CREATED);
+
+	return;
+
+error:
+	{
+		DECLARE_FAILURE(error);
+		handle_gprs_context_error(pipe_data->gprs_data, c_data, &error);
+	}
+	return;
+}
+
+static void context_create_pep_cb(GIsiPEP *pep, void *opaque)
+{
+	struct gprs_data *data = opaque;
+	struct context_data *c_data = NULL;
+	char buf[IF_NAMESIZE];
+
+	/* the pipe endpoint is now ready, let's get the interface name */
+
+	DBG("Pipe endpoint creation callback called, PEP: %p", pep);
+
+	c_data = gprs_find_context_by_pep(data, pep);
+
+	if (!c_data)
+		return;
+
+	ofono_gprs_context_interface_notify(data->manager, c_data->token,
+			g_isi_pep_get_ifname(pep, buf));
+
+	return;
+}
+
+#define PN_PEP_TYPE_GPRS 0x04
+
+static bool context_create_pipe(struct gprs_data *data, struct context_data *c_data)
+{
+	uint16_t local_object;
+	struct pipe_data *pipe_data;
+
+	c_data->pep = g_isi_pep_create(data->isi_modem, context_create_pep_cb, data);
+
+	DBG("Creating the pipe: endpoint %p", c_data->pep);
+
+	if (!c_data->pep)
+		goto error;
+
+	local_object = g_isi_pep_get_object(c_data->pep);
+
+	DBG("Creating the pipe: local object 0x%04X, remote object 0x%04X",
+			local_object, c_data->gpds_object);
+
+	c_data->pipe = g_isi_pipe_create(data->isi_modem,
+			context_create_pipe_cb,
+			local_object, c_data->gpds_object,
+			PN_PEP_TYPE_GPRS, PN_PEP_TYPE_GPRS);
+
+	if (!c_data->pipe)
+		goto error;
+
+	pipe_data = g_new0(struct pipe_data, 1);
+	pipe_data->token = c_data->token;
+	pipe_data->gprs_data = data;
+
+	g_isi_pipe_set_userdata(c_data->pipe, pipe_data);
+	g_isi_pipe_set_error_handler(c_data->pipe, context_create_pipe_error_cb);
+
+	DBG("Waiting for pipe to be ready.");
+
+	return true;
+
+error:
+
+	if (c_data->pep) {
+		g_isi_pep_destroy(c_data->pep);
+	}
+
+	return false;
+}
+
+#undef PN_PEP_TYPE_GPRS
+
+static bool get_ipv4_address(int addr_len, unsigned char *msg_addr,
+		struct in_addr *addr, char *char_addr)
+{
+	if (sizeof(struct in_addr) != addr_len) {
+		DBG("Unexpected IPv4 address length");
+		return false;
+	}
+
+	memcpy(addr, msg_addr, addr_len);
+	inet_ntop(AF_INET, addr, char_addr, INET_ADDRSTRLEN);
+
+	return true;
+}
+
+static bool get_ipv6_address(int addr_len, unsigned char *msg_addr,
+		struct in6_addr *addr, char *char_addr)
+{
+	if (sizeof(struct in6_addr) != addr_len) {
+		DBG("Unexpected IPv6 address length");
+		return false;
+	}
+
+	memcpy(addr, msg_addr, addr_len);
+	inet_ntop(AF_INET6, addr, char_addr, INET6_ADDRSTRLEN);
+
+	return true;
+}
+
+static void context_id_delete_ind (GIsiClient *client,
+		const void *restrict data, size_t len,
+		uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct context_data *c_data = NULL;
+	struct gprs_data *gprs_data = opaque;
+
+	DBG("GPDS_CONTEXT_ID_DELETE_IND:");
+	dump_msg(msg, len);
+
+	c_data = gprs_find_context(gprs_data, msg[1]);
+	if (!c_data) {
+		DBG("Unknown PDP context: %d", msg[1]);
+		goto error;
+	}
+
+	connection_sm(gprs_data, c_data, GPRS_CONTEXT_FINISHED);
+
+	return;
+
+error:
+
+	return;
+}
+
+static void deactivating_ind (GIsiClient *client,
+		const void *restrict data, size_t len,
+		uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct context_data *c_data = NULL;
+	struct gprs_data *gprs_data = opaque;
+
+	DBG("GPDS_CONTEXT_DEACTIVATING_IND:");
+	dump_msg(msg, len);
+
+	if (len != 2) {
+		DBG("Wrong message length");
+		goto error;
+	}
+
+	c_data = gprs_find_context(gprs_data, msg[1]);
+	if (!c_data) {
+		DBG("Unknown PDP context: %d", msg[1]);
+		goto error;
+	}
+
+	connection_sm(gprs_data, c_data, GPRS_CONTEXT_DEACTIVATING);
+
+	return;
+
+error:
+
+	return;
+}
+
+static void status_ind (GIsiClient *client,
+		const void *restrict data, size_t len,
+		uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct context_data *c_data = NULL;
+	struct gprs_data *gprs_data = opaque;
+	unsigned int rx = 0, tx = 0;
+
+	DBG("GPDS_CONTEXT_STATUS_IND:");
+	dump_msg(msg, len);
+
+	if (len != 11) {
+		DBG("Wrong message length");
+		goto error;
+	}
+
+	c_data = gprs_find_context(gprs_data, msg[2]);
+	if (!c_data) {
+		DBG("Unknown PDP context: %d", msg[1]);
+		goto error;
+	}
+
+	memcpy(&tx, &msg[3], sizeof(int));
+	memcpy(&rx, &msg[7], sizeof(int));
+
+	tx = ntohl(tx);
+	rx = ntohl(rx);
+
+#if 0
+	tx = ntohl((int) msg[3]);
+	rx = ntohl((int) msg[7]);
+#endif
+
+	DBG("TX bytes: %i, RX bytes: %i", tx, rx);
+
+	ofono_gprs_context_tx_bytes_notify(gprs_data->manager, c_data->token, tx);
+	ofono_gprs_context_rx_bytes_notify(gprs_data->manager, c_data->token, rx);
+
+	return;
+
+error:
+
+	return;
+}
+
+static void deactivate_ind (GIsiClient *client,
+		const void *restrict data, size_t len,
+		uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct context_data *c_data = NULL;
+	struct gprs_data *gprs_data = opaque;
+
+	DBG("GPDS_CONTEXT_DEACTIVATE_IND:");
+	dump_msg(msg, len);
+
+	if (len < 3) {
+		DBG("Wrong message length");
+		goto error;
+	}
+
+	c_data = gprs_find_context(gprs_data, msg[1]);
+	if (!c_data) {
+		DBG("Unknown PDP context: %d", msg[1]);
+		goto error;
+	}
+
+	connection_sm(gprs_data, c_data, GPRS_CONTEXT_DEACTIVATED);
+
+	return;
+
+error:
+
+	return;
+}
+
+static void activating_ind (GIsiClient *client,
+		const void *restrict data, size_t len,
+		uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct context_data *c_data = NULL;
+	struct gprs_data *gprs_data = opaque;
+
+	DBG("GPDS_CONTEXT_ACTIVATING_IND:");
+	dump_msg(msg, len);
+
+	if (len < 3) {
+		DBG("Wrong message length");
+		goto error;
+	}
+
+	c_data = gprs_find_context(gprs_data, msg[1]);
+	if (!c_data) {
+		DBG("Unknown PDP context: %d", msg[1]);
+		goto error;
+	}
+
+	connection_sm(gprs_data, c_data, GPRS_CONTEXT_ACTIVATING);
+
+	return;
+
+error:
+
+	return;
+}
+
+static void activate_fail_ind (GIsiClient *client,
+		const void *restrict data, size_t len,
+		uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+#if 0
+	struct context_data *c_data = NULL;
+	struct gprs_data *gprs_data = opaque;
+#endif
+
+	DBG("GPDS_CONTEXT_ACTIVATE_FAIL_IND:");
+	dump_msg(msg, len);
+
+	/* the error is handled from activate_resp_cb, so let's not do it
+	 * here */
+
+#if 0
+	c_data = gprs_find_context(gprs_data, msg[1]);
+	if (!c_data) {
+		DBG("Unknown PDP context: %d", msg[1]);
+		goto error;
+	}
+
+	connection_sm(gprs_data, c_data, GPRS_CONTEXT_DEACTIVATED);
+
+	return;
+
+error:
+#endif
+
+	return;
+}
+
+static void activate_ind (GIsiClient *client,
+		const void *restrict data, size_t len,
+		uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct context_data *c_data = NULL;
+	struct gprs_data *gprs_data = opaque;
+	unsigned char *subs[13];
+	int n_subs;
+
+	DBG("GPDS_CONTEXT_ACTIVATE_IND:");
+
+	dump_msg(msg, len);
+
+	if (len < 3) {
+		DBG("Wrong message length");
+		goto error;
+	}
+
+	c_data = gprs_find_context(gprs_data, msg[1]);
+	if (!c_data) {
+		DBG("Unknown PDP context: %d", msg[1]);
+		goto error;
+	}
+
+	/* parse the indication */
+
+	n_subs = msg[2];
+
+	if (parse_msg(3, subs, n_subs, (unsigned char *) msg, len)) {
+		int i;
+
+		for (i = 0; i < n_subs; i++) {
+			switch (*subs[i]) {
+				case 0x04: /* GPDS_PDP_ADDRESS_INFO */
+					{
+						int addr_len = *(subs[i]+3);
+
+						if (c_data->type == GPDS_PDP_TYPE_IPV6) {
+							get_ipv6_address(addr_len, subs[i]+4,
+									&c_data->pdp_addr.ipv6_addr, c_data->pdp_addr_s);
+						}
+						else {
+							get_ipv4_address(addr_len, subs[i]+4,
+									&c_data->pdp_addr.ipv4_addr, c_data->pdp_addr_s);
+						}
+						DBG("PDP address: %s", c_data->pdp_addr_s);
+
+						ofono_gprs_context_address_notify(gprs_data->manager,
+								c_data->token, c_data->pdp_addr_s);
+
+						break;
+					}
+				case 0x0D: /* GPDS_PDNS_ADDRESS_INFO */
+					{
+						int addr_len = *(subs[i]+3);
+
+						if (c_data->type == GPDS_PDP_TYPE_IPV6) {
+							get_ipv6_address(addr_len, subs[i]+4,
+									&c_data->pdns_addr.ipv6_addr, c_data->pdns_addr_s);
+						}
+						else {
+							get_ipv4_address(addr_len, subs[i]+4,
+									&c_data->pdns_addr.ipv4_addr, c_data->pdns_addr_s);
+						}
+
+						DBG("PDNS address: %s", c_data->pdns_addr_s);
+
+						ofono_gprs_context_pdns_address_notify(gprs_data->manager,
+								c_data->token, c_data->pdns_addr_s);
+
+						break;
+					}
+				case 0x0E: /* GPDS_SDNS_ADDRESS_INFO */
+					{
+						int addr_len = *(subs[i]+3);
+
+						if (c_data->type == GPDS_PDP_TYPE_IPV6) {
+							get_ipv6_address(addr_len, subs[i]+4, &c_data->sdns_addr.ipv6_addr, c_data->sdns_addr_s);
+						}
+						else {
+							get_ipv4_address(addr_len, subs[i]+4, &c_data->sdns_addr.ipv4_addr, c_data->sdns_addr_s);
+						}
+						DBG("SDNS address: %s", c_data->sdns_addr_s);
+
+						ofono_gprs_context_sdns_address_notify(gprs_data->manager,
+								c_data->token, c_data->sdns_addr_s);
+
+						break;
+					}
+				default:
+					break;
+
+			}
+		}
+	}
+
+	connection_sm(gprs_data, c_data, GPRS_CONTEXT_ACTIVATED);
+
+	return;
+
+error:
+
+	return;
+}
+
+
+static void connection_sm(struct gprs_data *data,
+		struct context_data *c_data,
+		enum gprs_context_state new_state)
+{
+	bool ret = true;
+	bool again = false;
+	enum gprs_context_state tmp_state;
+
+	/*
+	 * 1. Create a new (primary) PDP context.
+	 * 2. Create the data pipe (deactivated)
+	 * 3. Configure the context.
+	 * 4. Configure the local link.
+	 * 5. Activate the context.
+	 * 6. Activate the data pipe.
+	 *
+	 * ... data transfer ...
+	 *
+	 * 7. Deactivate the context.
+	 */
+
+	c_data->prev_state = c_data->state;
+	c_data->state = new_state;
+
+	DBG("Entering connection state machine -- current state %d", c_data->state);
+
+	switch (c_data->state) {
+		case GPRS_CONTEXT_INITED:
+			ret = context_id_create_req(data, c_data);
+			break;
+		case GPRS_CONTEXT_ID_REQUESTED:
+			{
+				struct isi_cb_data *cbd = c_data->cbd;
+				ofono_gprs_new_context_cb_t cb = cbd->cb;
+				struct ofono_error err;
+
+				/* tell the upper level that the call actually succeeded
+				 * so far */
+
+				err.type = OFONO_ERROR_TYPE_NO_ERROR;
+				err.error = 0;
+
+				cb(&err, c_data->token, cbd->data);
+				g_free(cbd);
+				c_data->cbd = NULL;
+
+				/* Now the upper level knows we have a context running.
+				 * Set it to be in "Connecting" state. */
+
+				ofono_gprs_context_state_notify(data->manager, c_data->token,
+						GPRS_CONTEXT_STATE_CONNECTING);
+
+				ret = context_create_pipe(data, c_data);
+			}
+			break;
+		case GPRS_CONTEXT_PIPE_CREATED:
+			ret = context_configure_req(data, c_data);
+			break;
+		case GPRS_CONTEXT_CONFIGURED:
+			ret = context_configure_ll_req(data, c_data);
+			break;
+		case GPRS_CONTEXT_LOCAL_LINK_CONFIGURED:
+
+			/* subscribe to the activation indications */
+			g_isi_subscribe(data->client,
+					GPDS_CONTEXT_ACTIVATING_IND, activating_ind, data);
+
+			ret = context_activate_req(data, c_data);
+			break;
+		case GPRS_CONTEXT_PIPE_STARTED:
+			ret = start_interface(data, c_data);
+			tmp_state = GPRS_CONTEXT_CONNECTED;
+			again = true;
+			break;
+		case GPRS_CONTEXT_ACTIVATING:
+			g_isi_subscribe(data->client,
+					GPDS_CONTEXT_DEACTIVATING_IND, deactivating_ind, data);
+			g_isi_subscribe(data->client,
+					GPDS_CONTEXT_ACTIVATE_IND, activate_ind, data);
+			g_isi_subscribe(data->client,
+					GPDS_CONTEXT_ACTIVATE_FAIL_IND, activate_fail_ind, data);
+			break;
+		case GPRS_CONTEXT_ACTIVATED:
+
+			/* subscribe to the deactivation indications */
+			g_isi_subscribe(data->client,
+					GPDS_CONTEXT_DEACTIVATE_IND, deactivate_ind, data);
+
+			/* request status when the connection goes away */
+			g_isi_subscribe(data->client,
+					GPDS_CONTEXT_STATUS_IND, status_ind, data);
+
+			/* unsubscribe from the activation indications */
+			g_isi_unsubscribe(data->client, GPDS_CONTEXT_ACTIVATE_FAIL_IND);
+			g_isi_unsubscribe(data->client, GPDS_CONTEXT_ACTIVATE_IND);
+			g_isi_unsubscribe(data->client, GPDS_CONTEXT_ACTIVATING_IND);
+
+			ret = context_start_pipe(data, c_data);
+			tmp_state = GPRS_CONTEXT_PIPE_STARTED;
+			again = true;
+			break;
+		case GPRS_CONTEXT_CONNECTED:
+			ofono_gprs_context_state_notify(data->manager, c_data->token,
+					GPRS_CONTEXT_STATE_CONNECTED);
+			break;
+		case GPRS_CONTEXT_DEACTIVATING:
+
+			/* unsubscribe from the deactivating indication */
+			g_isi_unsubscribe(data->client, GPDS_CONTEXT_DEACTIVATING_IND);
+			break;
+
+		case GPRS_CONTEXT_DEACTIVATED:
+
+			/* subscribe to the context deletion indications */
+			g_isi_subscribe(data->client,
+					GPDS_CONTEXT_ID_DELETE_IND, context_id_delete_ind, data);
+
+			/* unsubscribe from the deactivation indications */
+			g_isi_unsubscribe(data->client, GPDS_CONTEXT_DEACTIVATE_IND);
+
+			if (c_data->pipe) {
+				struct pipe_data *pipe_data = g_isi_pipe_get_userdata(c_data->pipe);
+				DBG("Destroying ISI pipe %p", c_data->pipe);
+				free(pipe_data);
+				g_isi_pipe_destroy(c_data->pipe);
+			}
+
+			if (c_data->pep) {
+				DBG("Destroying ISI pipe endpoint %p", c_data->pep);
+				g_isi_pep_destroy(c_data->pep);
+			}
+
+			break;
+		case GPRS_CONTEXT_FINISHED:
+			/* unsubscribe from the context deletion indications and
+			 * status indications */
+			g_isi_unsubscribe(data->client, GPDS_CONTEXT_ID_DELETE_IND);
+			g_isi_unsubscribe(data->client, GPDS_CONTEXT_STATUS_IND);
+
+			data->contexts = g_slist_remove(data->contexts, c_data);
+
+			ofono_gprs_context_state_notify(data->manager, c_data->token,
+					GPRS_CONTEXT_STATE_DISCONNECTED);
+
+			delete_cdata(c_data);
+			c_data = NULL;
+
+			break;
+	}
+
+	if (!ret) {
+		DECLARE_FAILURE(error);
+		handle_gprs_context_error(data, c_data, &error);
+	}
+	else if (again) {
+		/* synchronous call -- continue SM processing */
+		connection_sm(data, c_data, tmp_state);
+	}
+	return;
+}
+
+static unsigned char map_pdp_type(const char *type)
+{
+	if (strcmp(type, GPRS_TYPE_IPV4) == 0) {
+		return GPDS_PDP_TYPE_IPV4;
+	}
+	else if (strcmp(type, GPRS_TYPE_IPV6) == 0) {
+		return GPDS_PDP_TYPE_IPV6;
+	}
+
+	/* error case */
+	return GPDS_PDP_TYPE_DEFAULT;
+}
+
+static void isi_gprs_new_context(struct ofono_gprs *manager,
+		const char *apn,
+		const char *type,
+		const char *username,
+		const char *password,
+		ofono_gprs_new_context_cb_t cb,
+		void *user_data)
+{
+
+	/* The PDP context creation and connection has several phases, which
+	 * are detailed in connection_sm function.
+	 */
+
+	struct gprs_data *data = ofono_gprs_get_data(manager);
+	struct context_data *c_data = g_new0(struct context_data, 1);
+
+	if (!c_data)
+		goto error;
+
+	c_data->apn = g_strdup(apn);
+	c_data->type = map_pdp_type(type);
+	c_data->username = g_strdup(username);
+	c_data->password = g_strdup(password);
+	c_data->cbd = isi_cb_data_new(NULL, cb, user_data);
+#if 0
+	c_data->property_cbd = isi_cb_data_new(NULL, property_cb, user_data);
+#endif
+	c_data->token = GPRS_CONTEXT_ID_INVALID;
+
+	if (!c_data->apn || !c_data->username || !c_data->password || !c_data->cbd)
+		goto error;
+
+	/* add the context to our internal list of active contexts */
+	data->contexts = g_slist_prepend(data->contexts, c_data);
+
+	/* start the state machine */
+	connection_sm(data, c_data, GPRS_CONTEXT_INITED);
+
+	return;
+
+error:
+	{
+		DECLARE_FAILURE(e);
+		handle_gprs_context_error(data, c_data, &e);
+	}
+	return;
+}
+
+static bool context_deactivate_resp_cb(GIsiClient *client, const void *restrict data,
+		size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct gprs_data *gprs_data = opaque;
+	ofono_gprs_destroy_context_cb_t cb = NULL;
+	struct ofono_error err;
+	struct context_data *c_data = NULL;
+
+	/* sanity checks */
+
+	if(!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	dump_msg(msg, len);
+
+	if (len != 3) {
+		DBG("Wrong message length");
+		goto error;
+	}
+
+	if (msg[0] != GPDS_CONTEXT_DEACTIVATE_RESP) {
+		DBG("Unexpected message ID: 0x%02x", msg[0]);
+		goto error;
+	}
+
+	c_data = gprs_find_context(gprs_data, msg[1]);
+	if (!c_data) {
+		DBG("Unknown PDP context: %d", msg[1]);
+		goto error;
+	}
+
+	cb = c_data->destroy_cbd->cb;
+
+	if (msg[2] != GPDS_OK) {
+		DBG("Disconnect failed");
+		goto error;
+	}
+
+	err.type = OFONO_ERROR_TYPE_NO_ERROR;
+	err.error = 0;
+
+	cb(&err, c_data->token, c_data->destroy_cbd->data);
+
+	g_free(c_data->destroy_cbd);
+
+	return true;
+
+error:
+	/* what to do if disconnect fails? */
+	{
+		DECLARE_FAILURE(e);
+		if (c_data) {
+			cb(&e, c_data->token, c_data->destroy_cbd->data);
+			g_free(c_data->destroy_cbd);
+		}
+	}
+	return false;
+}
+
+static void isi_gprs_destroy_context(struct ofono_gprs *manager,
+		ofono_gprs_context_id_t token,
+		ofono_gprs_destroy_context_cb_t cb, void *user_data)
+{
+	struct gprs_data *data = ofono_gprs_get_data(manager);
+	struct context_data *c_data = NULL;
+	struct isi_cb_data *cbd = isi_cb_data_new(NULL, cb, user_data);
+	const unsigned char msg[] = {
+		GPDS_CONTEXT_DEACTIVATE_REQ,
+		token
+	};
+	GIsiRequest *req = NULL;
+
+	DBG("Destroying context %d", token);
+
+	c_data = gprs_find_context(data, msg[1]);
+	if (!c_data) {
+		DBG("Unknown PDP context: %d", msg[1]);
+		goto error;
+	}
+
+	c_data->destroy_cbd = cbd;
+
+	req = g_isi_request_make(data->client, msg, sizeof(msg), GPDS_TIMEOUT,
+			context_deactivate_resp_cb, data);
+
+	if (req) {
+		return;
+	}
+
+error:
+
+	if (cbd)
+		g_free(cbd);
+
+	{
+		DECLARE_FAILURE(error);
+		cb(&error, token, user_data);
+	}
+	return;
+}
+
+static bool attach_resp_cb(GIsiClient *client, const void *restrict data,
+		size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_gprs_generic_cb_t cb = cbd->cb;
+	struct ofono_error err;
+
+	/* sanity checks */
+
+	if(!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	dump_msg(msg, len);
+
+	if (len != 4) {
+		DBG("Wrong message length");
+		goto error;
+	}
+
+	if (msg[0] != GPDS_ATTACH_RESP) {
+		DBG("Unexpected message ID: 0x%02x", msg[0]);
+		goto error;
+	}
+
+	if (msg[1] != GPDS_OK) {
+		DBG("Attach failed");
+		goto error;
+	}
+
+	err.type = OFONO_ERROR_TYPE_NO_ERROR;
+	err.error = 0;
+
+	cb(&err, cbd->data);
+
+	g_free(cbd);
+
+	return true;
+
+error:
+	{
+		DECLARE_FAILURE(e);
+		cb(&e, cbd->data);
+	}
+	return false;
+}
+
+static void isi_gprs_attach(struct ofono_gprs *manager,
+		ofono_gprs_generic_cb_t cb, void *user_data)
+{
+	struct gprs_data *data = ofono_gprs_get_data(manager);
+	struct isi_cb_data *cbd = isi_cb_data_new(NULL, cb, user_data);
+	const unsigned char msg[] = {
+		GPDS_ATTACH_REQ,
+		0x00  /* GPDS_FOLLOW_OFF */
+	};
+	GIsiRequest *req = NULL;
+
+	if (!cbd)
+		goto error;
+
+	req = g_isi_request_make(data->client, msg, sizeof(msg), GPDS_TIMEOUT,
+			attach_resp_cb, cbd);
+
+	if (req) {
+		return;
+	}
+
+error:
+	if (cbd)
+		g_free(cbd);
+
+	{
+		DECLARE_FAILURE(error);
+		cb(&error, data);
+	}
+	return;
+}
+
+static bool detach_resp_cb(GIsiClient *client, const void *restrict data,
+		size_t len, uint16_t object, void *opaque)
+{
+	const unsigned char *msg = data;
+	struct isi_cb_data *cbd = opaque;
+	ofono_gprs_generic_cb_t cb = cbd->cb;
+	struct ofono_error err;
+
+	/* sanity checks */
+
+	if(!msg) {
+		DBG("ISI client error: %d", g_isi_client_error(client));
+		goto error;
+	}
+
+	dump_msg(msg, len);
+
+	if (len != 3) {
+		DBG("Wrong message length");
+		goto error;
+	}
+
+	if (msg[0] != GPDS_DETACH_RESP) {
+		DBG("Unexpected message ID: 0x%02x", msg[0]);
+		goto error;
+	}
+
+	if (msg[1] != GPDS_OK) {
+		DBG("Attach failed");
+		goto error;
+	}
+
+	err.type = OFONO_ERROR_TYPE_NO_ERROR;
+	err.error = 0;
+
+	cb(&err, cbd->data);
+
+	g_free(cbd);
+
+	return true;
+
+error:
+	{
+		DECLARE_FAILURE(e);
+		cb(&e, cbd->data);
+	}
+	return false;
+}
+
+static void isi_gprs_detach(struct ofono_gprs *manager,
+		ofono_gprs_generic_cb_t cb, void *user_data)
+{
+	struct gprs_data *data = ofono_gprs_get_data(manager);
+	struct isi_cb_data *cbd = isi_cb_data_new(NULL, cb, user_data);
+	const unsigned char msg[] = {
+		GPDS_DETACH_REQ,
+		0x00, /* filler */
+		0x00  /* number of sub blocks */
+	};
+	GIsiRequest *req = NULL;
+
+	if (!cbd)
+		goto error;
+
+	req = g_isi_request_make(data->client, msg, sizeof(msg), GPDS_TIMEOUT,
+			detach_resp_cb, cbd);
+
+	if (req) {
+		return;
+	}
+
+error:
+	if (cbd)
+		g_free(cbd);
+
+	{
+		DECLARE_FAILURE(error);
+		cb(&error, data);
+	}
+
+	return;
+}
+
+static gboolean isi_gprs_register(gpointer user)
+{
+	struct ofono_gprs *gprs = user;
+
+	DBG("> isi_gprs_register");
+
+	ofono_gprs_register(gprs);
+
+	/* run only once */
+
+	return FALSE;
+}
+
+static int isi_gprs_probe(struct ofono_gprs *gprs)
+{
+	GIsiModem *idx = ofono_gprs_get_data(gprs);
+	struct gprs_data *data = g_try_new0(struct gprs_data, 1);
+
+	DBG("> isi_gprs_probe");
+
+	if (!data) {
+		DBG("Failed to allocate GPRS data");
+		return -ENOMEM;
+	}
+
+	data->isi_modem = idx;
+	data->client = g_isi_client_create(idx, PN_GPDS);
+	if (!data->client) {
+		DBG("Failed to crate ISI client for GPRS");
+		return -ENOMEM;
+	}
+
+	/* the manager and struct gprs_data are two sides of a coin */
+	data->manager = gprs;
+
+	ofono_gprs_set_data(gprs, data);
+
+	g_idle_add(isi_gprs_register, gprs);
+
+	return 0;
+}
+
+static int isi_gprs_remove(struct ofono_gprs *gprs)
+{
+	struct gprs_data *data = ofono_gprs_get_data(gprs);
+
+	if (data) {
+		g_isi_client_destroy(data->client);
+		g_free(data);
+	}
+
+	return 0;
+}
+
+static struct ofono_gprs_driver driver = {
+	.name			        = "isi",
+	.probe			        = isi_gprs_probe,
+	.remove			        = isi_gprs_remove,
+	.new_context		    = isi_gprs_new_context,
+	.destroy_context	    = isi_gprs_destroy_context,
+	.attach				    = isi_gprs_attach,
+	.detach				    = isi_gprs_detach,
+};
+
+void isi_gprs_init()
+{
+	ofono_gprs_driver_register(&driver);
+}
+
+void isi_gprs_exit()
+{
+	ofono_gprs_driver_unregister(&driver);
+}
+
+/* vim: ts=4:noexpandtab:
+*/
+
diff --git a/drivers/isimodem/isi.h b/drivers/isimodem/isi.h
index 89ed534..bb73f12 100644
--- a/drivers/isimodem/isi.h
+++ b/drivers/isimodem/isi.h
@@ -105,3 +105,7 @@ extern void isi_call_barring_exit();
 
 extern void isi_call_meter_init();
 extern void isi_call_meter_exit();
+
+extern void isi_gprs_init();
+extern void isi_gprs_exit();
+
diff --git a/drivers/isimodem/isimodem.c b/drivers/isimodem/isimodem.c
index 3f3d179..8d032be 100644
--- a/drivers/isimodem/isimodem.c
+++ b/drivers/isimodem/isimodem.c
@@ -49,6 +49,7 @@
 #include <ofono/call-settings.h>
 #include <ofono/call-barring.h>
 #include <ofono/call-meter.h>
+#include <ofono/gprs.h>
 
 #include "isi.h"
 
@@ -161,6 +162,7 @@ static int isi_modem_populate(struct ofono_modem *modem)
 	ofono_call_settings_create(isi->modem, "isi", isi->idx);
 	ofono_call_barring_create(isi->modem, "isi", isi->idx);
 	ofono_call_meter_create(isi->modem, "isi", isi->idx);
+	ofono_gprs_create(isi->modem, "isi", isi->idx);
 
 	return 0;
 }
@@ -190,6 +192,7 @@ static int isimodem_init(void)
 	isi_call_settings_init();
 	isi_call_barring_init();
 	isi_call_meter_init();
+	isi_gprs_init();
 
 	ofono_modem_driver_register(&driver);
 
@@ -229,6 +232,7 @@ static void isimodem_exit(void)
 	isi_call_settings_exit();
 	isi_call_barring_exit();
 	isi_call_meter_exit();
+	isi_gprs_exit();
 }
 
 OFONO_PLUGIN_DEFINE(isimodem, "PhoNet / ISI modem driver", VERSION,
-- 
1.6.0.4


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #5: 0004-Basic-tests-for-GPRS-D-Bus-API.patch --]
[-- Type: text/x-patch, Size: 1363 bytes --]

From fedc35d4e10d063351ce23025c72742d5f095a55 Mon Sep 17 00:00:00 2001
From: Ismo Puustinen <ismo.h.puustinen@nokia.com>
Date: Mon, 31 Aug 2009 14:35:07 +0300
Subject: [PATCH] Basic tests for GPRS D-Bus API

---
 test/test-gprs |   39 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 39 insertions(+), 0 deletions(-)
 create mode 100755 test/test-gprs

diff --git a/test/test-gprs b/test/test-gprs
new file mode 100755
index 0000000..0e48f3c
--- /dev/null
+++ b/test/test-gprs
@@ -0,0 +1,39 @@
+#!/usr/bin/python
+
+import gobject
+
+import dbus
+
+if __name__ == "__main__":
+
+	bus = dbus.SystemBus()
+
+	manager = dbus.Interface(bus.get_object('org.ofono', '/'),
+							'org.ofono.Manager')
+
+	try:
+		modems = manager.GetProperties()['Modems']
+	except dbus.DBusException, e:
+		print "Unable to get the Modems property %s" % e
+
+	manager = dbus.Interface(bus.get_object('org.ofono', modems[0]),
+				'org.ofono.GprsManager')
+
+	# TODO: get manager properties
+
+	manager.Attach()
+
+	variants = dbus.Dictionary(signature='sv')
+
+	path = manager.Connect('internet', 'IPv4', '', '', variants, timeout=100)
+
+	print "New GPRS context created, path " + path
+	context = dbus.Interface(bus.get_object('org.ofono', path), 'org.ofono.GprsContext')
+
+	# TODO: get context properties
+
+	manager.Disconnect(path)
+
+	manager.Detach()
+
+
-- 
1.6.0.4


^ permalink raw reply related	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2009-09-02 21:18 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-09-01 11:09 GPRS support for Ofono Ismo Puustinen
2009-09-01 19:02 ` Jean-Christian de Rivaz
2009-09-01 19:25   ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
2009-09-01 20:17     ` Jean-Christian de Rivaz
2009-09-01 20:26       ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
2009-09-01 20:30       ` Christensen, Mikkel
2009-09-01 19:27   ` Christensen, Mikkel
2009-09-01 21:36 ` Denis Kenzior
2009-09-01 22:42   ` Marcel Holtmann
2009-09-01 22:50     ` Denis Kenzior
2009-09-02  6:39     ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
2009-09-02  9:16       ` Marcel Holtmann
2009-09-02  9:22         ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
2009-09-02 10:43           ` Aki Niemi
2009-09-02 11:03             ` Marcel Holtmann
2009-09-02 11:19               ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
2009-09-02 11:30   ` Ismo Puustinen
2009-09-02 12:02     ` Marcel Holtmann
2009-09-02 12:34       ` Aki Niemi
2009-09-02 12:46         ` Marcel Holtmann
2009-09-02 12:51           ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
2009-09-02 15:28         ` Denis Kenzior
2009-09-02 15:42           ` Aki Niemi
2009-09-02 20:37             ` Marcel Holtmann
2009-09-02 20:36               ` Denis Kenzior
2009-09-02 21:09                 ` Marcel Holtmann
2009-09-02 12:46       ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
2009-09-02 13:01         ` Marcel Holtmann
2009-09-02 17:51           ` Bastian, Waldo
2009-09-02 20:40             ` Marcel Holtmann
2009-09-02 15:00     ` Denis Kenzior
2009-09-02 15:32       ` Aki Niemi
2009-09-02 15:36         ` Denis Kenzior
2009-09-02 15:38       ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
2009-09-02 16:26         ` Denis Kenzior
2009-09-02 17:39           ` Bastian, Waldo
2009-09-02 17:46             ` Denis Kenzior
2009-09-02 18:41               ` Bastian, Waldo
2009-09-02 21:01                 ` Marcel Holtmann
2009-09-02 21:10                   ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
2009-09-02 21:18                     ` Marcel Holtmann
2009-09-02 20:53         ` Marcel Holtmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.