All of lore.kernel.org
 help / color / mirror / Atom feed
* RFC: IPv6 support
@ 2011-01-26 16:22 Mika Liljeberg
  2011-01-26 16:22 ` [RFC 1/5] gprs: Update documentation for IPv6 Mika Liljeberg
                   ` (4 more replies)
  0 siblings, 5 replies; 14+ messages in thread
From: Mika Liljeberg @ 2011-01-26 16:22 UTC (permalink / raw)
  To: ofono

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

Hi,

Here's an initial set of IPv6 patches for review. Please don't apply
anything yet, as these are not final. I've left in some shim code which
allows compilation with existing modem drivers. Also, I have not yet
tried to exterminate coding style issues.

I'd like feedback on the following issues:

1) connman API: A combined ipv4v6 context type has been added as well
as properties for IPv6 network configuration. The combined ipv4v6 context
falls back on separate IPv4 and IPv6 bearers under the hood, in case the
modem or the network does not support 3GPP rel 8.

IPv6 address configuration is minimal. Basically, only network interface name,
IPv6 link-local address and DNS server addresses are exposed. IPv6 stateless
address autoconfiguration method should be used for interface configuration.
I'd like some feedback on modems that provide a virtual ethernet interface.
Will the above suffice?

2) driver API: The activate_primary_new() method will replace the
activate_primary() method in the final patches. The callback no longer
passes every address configuration setting as argument. Instead, I've
defined a set of ofono_gprs_context_set_xyz() methods to convey context
settings to the core. The reason is that most of the settings are
optional. E.g., with a combined IPv4v6 context we might actually end up
with IPv4 or IPv6 only, instead of both, so both sets of configuration
parameters are optional. Things like IP netmask and gateway for static
network configuration, P-CSCF address, DNS servers, QoS parameters,
are also optional, depending on driver and context type. This way, any
changes are less likely to break the driver interface.

3) implementation in general: Unfortunately, the core patch is fairly big
even though I tried to not change things unnecessarily. The combined ipv4v6
context type made it necessary to rearrange quite a few things. The
pri_context structure now owns one or more context drivers (aka bearers),
each of which has it's own set of IPv4 and IPv6 settings when active.

Currently, the isimodem driver has been updated to work with IPv6, so N900
over USB can be used for testing. Other modem drivers should work ok with
IPv4.

Br,

	MikaL

[RFC 1/5] gprs: Update documentation for IPv6
[RFC 2/5] gprs: driver interface changes for IPv6
[RFC 3/5] gprs: core support for IPv6
[RFC 4/5] test: modify test scripts for IPv6
[RFC 5/5] isimodem: IPv6 support

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

* [RFC 1/5] gprs: Update documentation for IPv6
  2011-01-26 16:22 RFC: IPv6 support Mika Liljeberg
@ 2011-01-26 16:22 ` Mika Liljeberg
  2011-01-28 12:49   ` Sjur =?unknown-8bit?q?Br=C3=A6ndeland?=
  2011-01-26 16:22 ` [RFC 2/5] gprs: driver interface changes " Mika Liljeberg
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Mika Liljeberg @ 2011-01-26 16:22 UTC (permalink / raw)
  To: ofono

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

---
 doc/connman-api.txt |   48 +++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/doc/connman-api.txt b/doc/connman-api.txt
index 22c59dc..b885725 100644
--- a/doc/connman-api.txt
+++ b/doc/connman-api.txt
@@ -152,6 +152,15 @@ Properties	boolean Active [readwrite]
 			Holds whether the context is activated.  This value
 			can be set to activate / deactivate the context.
 
+			When the "Protocol" property is set to "ipv4v6",
+			oFono will first try to activate a combined "ipv4v6"
+			context (3GPP rel 8). Based on the result, oFono may
+			fall back to an IPv4 only or an IPv6 only context, or
+			activate separate IPv4 and IPv6 contexts under the
+			hood. The Protocol attribute is updated accordingly.
+			The "Settings" and "IPv6Settings" attributes will only
+			appear if the contained network settings are valid.
+
 		string AccessPointName [readwrite]
 
 			Holds the name of the access point.  This is
@@ -182,7 +191,7 @@ Properties	boolean Active [readwrite]
 		string Protocol [readwrite]
 
 			Holds the protocol for this context.  Valid values
-			are: "ip" and "ipv6".
+			are: "ip", "ipv6" and "ipv4v6".
 
 		string Name [readwrite]
 
@@ -196,8 +205,13 @@ Properties	boolean Active [readwrite]
 
 			string Interface [readonly, optional]
 
-				Holds the interface of the network interface
-				used by this context (e.g. "ppp0" "usb0")
+				Holds the name of the IPv4 network interface
+				used by this context (e.g. "ppp0" "usb0").
+
+				For combined IPv4v6 context (3GPP rel 8) the
+				same network interface may be used for both
+				IPv4 and IPv6. IPv4 and IPv6 may also be
+				offered via separate network interfaces.
 
 			string Method [readonly, optional]
 
@@ -215,8 +229,8 @@ Properties	boolean Active [readwrite]
 
 			array{string} DomainNameServers [readonly, optional]
 
-				Holds the list of domain name servers for this
-				context.
+				Holds the list of domain name servers accessible
+				via this network interface.
 
 			string Gateway [readonly, optional]
 
@@ -242,6 +256,30 @@ Properties	boolean Active [readwrite]
 				via this proxy.  All other values are left
 				out in this case.
 
+		dict IPv6Settings [readonly, optional]
+
+			Holds all the IPv6 network settings.
+
+			string Interface [readonly, optional]
+
+				Holds the name of the IPv6 network interface
+				used by this context (e.g. "ppp0" "usb0").
+
+				For combined IPv4v6 context (3GPP rel 8) the
+				same network interface may be used for both
+				IPv4 and IPv6. IPv4 and IPv6 may also be
+				offered via separate network interfaces.
+
+			string LinkLocal [readonly, optional]
+
+				Holds the IPv6 link local address for this
+				context.
+
+			array{string} DomainNameServers [readonly, optional]
+
+				Holds the list of domain name servers accessible
+				via this network interface.
+
 		string MessageProxy [readwrite, MMS only]
 
 			Holds the MMS Proxy setting.
-- 
1.7.1


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

* [RFC 2/5] gprs: driver interface changes for IPv6
  2011-01-26 16:22 RFC: IPv6 support Mika Liljeberg
  2011-01-26 16:22 ` [RFC 1/5] gprs: Update documentation for IPv6 Mika Liljeberg
@ 2011-01-26 16:22 ` Mika Liljeberg
  2011-01-26 16:22 ` [RFC 3/5] gprs: core support " Mika Liljeberg
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 14+ messages in thread
From: Mika Liljeberg @ 2011-01-26 16:22 UTC (permalink / raw)
  To: ofono

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

---
 include/gprs-context.h |   41 +++++++++++++++++++++++++++++++++++++++++
 src/gprs.c             |    2 ++
 2 files changed, 43 insertions(+), 0 deletions(-)

diff --git a/include/gprs-context.h b/include/gprs-context.h
index c29c0dc..eee8e18 100644
--- a/include/gprs-context.h
+++ b/include/gprs-context.h
@@ -37,6 +37,7 @@ struct ofono_gprs_context;
 enum ofono_gprs_proto {
 	OFONO_GPRS_PROTO_IP = 0,
 	OFONO_GPRS_PROTO_IPV6,
+	OFONO_GPRS_PROTO_IPV4V6,
 };
 
 enum ofono_gprs_context_type {
@@ -47,6 +48,14 @@ enum ofono_gprs_context_type {
 	OFONO_GPRS_CONTEXT_TYPE_IMS,
 };
 
+enum ofono_gprs_addrconf_method {
+	OFONO_GPRS_ADDRCONF_NONE,
+	OFONO_GPRS_ADDRCONF_STATIC,
+	OFONO_GPRS_ADDRCONF_DHCP,
+	OFONO_GPRS_ADDRCONF_STATELESS,
+	OFONO_GPRS_ADDRCONF_DHCPV6,
+};
+
 struct ofono_gprs_primary_context {
 	unsigned int cid;
 	int direction;
@@ -56,6 +65,26 @@ struct ofono_gprs_primary_context {
 	enum ofono_gprs_proto proto;
 };
 
+void ofono_gprs_context_set_ip_interface(struct ofono_gprs_context *gc,
+					const char *interface);
+void ofono_gprs_context_set_ip_addrconf(struct ofono_gprs_context *gc,
+					enum ofono_gprs_addrconf_method method);
+void ofono_gprs_context_set_ip_address(struct ofono_gprs_context *gc,
+					const char *address);
+void ofono_gprs_context_set_ip_netmask(struct ofono_gprs_context *gc,
+					const char *netmask);
+void ofono_gprs_context_set_ip_gateway(struct ofono_gprs_context *gc,
+					const char *netmask);
+void ofono_gprs_context_set_ip_dns_servers(struct ofono_gprs_context *gc,
+						const char **dns);
+
+void ofono_gprs_context_set_ipv6_interface(struct ofono_gprs_context *gc,
+					const char *interface);
+void ofono_gprs_context_set_ipv6_address(struct ofono_gprs_context *gc,
+						const char *address);
+void ofono_gprs_context_set_ipv6_dns_servers(struct ofono_gprs_context *gc,
+						const char **dns);
+
 typedef void (*ofono_gprs_context_cb_t)(const struct ofono_error *error,
 					void *data);
 typedef void (*ofono_gprs_context_up_cb_t)(const struct ofono_error *error,
@@ -63,6 +92,10 @@ typedef void (*ofono_gprs_context_up_cb_t)(const struct ofono_error *error,
 				const char *address, const char *netmask,
 				const char *gw, const char **dns, void *data);
 
+typedef void (*ofono_gprs_context_activate_cb_t)(const struct ofono_error *error,
+					ofono_bool_t single_bearers,
+					void *data);
+
 struct ofono_gprs_context_driver {
 	const char *name;
 	int (*probe)(struct ofono_gprs_context *gc, unsigned int vendor,
@@ -71,6 +104,14 @@ struct ofono_gprs_context_driver {
 	void (*activate_primary)(struct ofono_gprs_context *gc,
 				const struct ofono_gprs_primary_context *ctx,
 				ofono_gprs_context_up_cb_t cb, void *data);
+	void (*activate_primary_new)(struct ofono_gprs_context *gc,
+					unsigned int id,
+					const char *apn,
+					enum ofono_gprs_proto proto,
+					const char *username,
+					const char *password,
+					ofono_gprs_context_activate_cb_t cb,
+					void *data);
 	void (*deactivate_primary)(struct ofono_gprs_context *gc,
 					unsigned int id,
 					ofono_gprs_context_cb_t cb, void *data);
diff --git a/src/gprs.c b/src/gprs.c
index 92d0b1a..37e7aee 100644
--- a/src/gprs.c
+++ b/src/gprs.c
@@ -224,6 +224,8 @@ static const char *gprs_proto_to_string(enum ofono_gprs_proto proto)
 		return "ip";
 	case OFONO_GPRS_PROTO_IPV6:
 		return "ipv6";
+	case OFONO_GPRS_PROTO_IPV4V6:
+		return "ipv4v6";
 	};
 
 	return NULL;
-- 
1.7.1


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

* [RFC 3/5] gprs: core support for IPv6
  2011-01-26 16:22 RFC: IPv6 support Mika Liljeberg
  2011-01-26 16:22 ` [RFC 1/5] gprs: Update documentation for IPv6 Mika Liljeberg
  2011-01-26 16:22 ` [RFC 2/5] gprs: driver interface changes " Mika Liljeberg
@ 2011-01-26 16:22 ` Mika Liljeberg
  2011-01-26 16:22 ` [RFC 4/5] test: modify test scripts " Mika Liljeberg
  2011-01-26 16:22 ` [RFC 5/5] isimodem: IPv6 support Mika Liljeberg
  4 siblings, 0 replies; 14+ messages in thread
From: Mika Liljeberg @ 2011-01-26 16:22 UTC (permalink / raw)
  To: ofono

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

---
 src/gprs.c |  916 ++++++++++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 679 insertions(+), 237 deletions(-)

diff --git a/src/gprs.c b/src/gprs.c
index 37e7aee..6edeef6 100644
--- a/src/gprs.c
+++ b/src/gprs.c
@@ -54,6 +54,7 @@
 #define MAX_MESSAGE_CENTER_LENGTH 255
 #define MAX_CONTEXTS 256
 #define SUSPEND_TIMEOUT 8
+#define ACTIVATE_FAIL_DELAY 2
 
 static GSList *g_drivers = NULL;
 static GSList *g_context_drivers = NULL;
@@ -97,19 +98,11 @@ struct ofono_gprs {
 	struct ofono_atom *atom;
 };
 
-struct ofono_gprs_context {
-	struct ofono_gprs *gprs;
-	enum ofono_gprs_context_type type;
-	ofono_bool_t inuse;
-	const struct ofono_gprs_context_driver *driver;
-	void *driver_data;
-	struct ofono_atom *atom;
-};
+struct pri_context;
 
-struct context_settings {
-	enum ofono_gprs_context_type type;
+struct context_settings_ip {
 	char *interface;
-	gboolean static_ip;
+	enum ofono_gprs_addrconf_method method;
 	char *ip;
 	char *netmask;
 	char *gateway;
@@ -117,21 +110,43 @@ struct context_settings {
 	char *proxy;
 };
 
+struct context_settings_ipv6 {
+	char *interface;
+	char *address;
+	char **dns;
+};
+
+struct ofono_gprs_context {
+	struct ofono_gprs *gprs;
+	struct pri_context *pri;
+	enum ofono_gprs_context_type type;
+	enum ofono_gprs_proto proto;
+	struct context_settings_ip *settings_ip;
+	struct context_settings_ipv6 *settings_ipv6;
+	guint timer;
+	unsigned int cid;
+	const struct ofono_gprs_context_driver *driver;
+	void *driver_data;
+	struct ofono_atom *atom;
+};
+
 struct pri_context {
 	ofono_bool_t active;
 	enum ofono_gprs_context_type type;
 	char name[MAX_CONTEXT_NAME_LENGTH + 1];
 	char message_proxy[MAX_MESSAGE_PROXY_LENGTH + 1];
 	char message_center[MAX_MESSAGE_CENTER_LENGTH + 1];
+	char apn[OFONO_GPRS_MAX_APN_LENGTH + 1];
+	char username[OFONO_GPRS_MAX_USERNAME_LENGTH + 1];
+	char password[OFONO_GPRS_MAX_PASSWORD_LENGTH + 1];
+	enum ofono_gprs_proto proto;
 	unsigned int id;
 	char *path;
 	char *key;
-	struct context_settings *settings;
 	char *proxy_host;
 	uint16_t proxy_port;
 	DBusMessage *pending;
-	struct ofono_gprs_primary_context context;
-	struct ofono_gprs_context *context_driver;
+	GSList *bearers;
 	struct ofono_gprs *gprs;
 };
 
@@ -240,11 +255,26 @@ static gboolean gprs_proto_from_string(const char *str,
 	} else if (g_str_equal(str, "ipv6")) {
 		*proto = OFONO_GPRS_PROTO_IPV6;
 		return TRUE;
+	} else if (g_str_equal(str, "ipv4v6")) {
+		*proto = OFONO_GPRS_PROTO_IPV4V6;
+		return TRUE;
 	}
 
 	return FALSE;
 }
 
+static const char *gprs_addrconf_to_string(enum ofono_gprs_proto method)
+{
+	switch (method) {
+	case OFONO_GPRS_ADDRCONF_STATIC:
+		return "static";
+	case OFONO_GPRS_ADDRCONF_DHCP:
+		return "dhcp";
+	}
+
+	return NULL;
+}
+
 static unsigned int gprs_cid_alloc(struct ofono_gprs *gprs)
 {
 	return idmap_alloc(gprs->cid_map);
@@ -270,21 +300,37 @@ static struct pri_context *gprs_context_by_path(struct ofono_gprs *gprs,
 	return NULL;
 }
 
-static void context_settings_free(struct context_settings *settings)
+static void context_settings_free(struct ofono_gprs_context *gc)
+{
+	if (gc->settings_ip == NULL)
+		return;
+
+	g_free(gc->settings_ip->interface);
+	g_free(gc->settings_ip->ip);
+	g_free(gc->settings_ip->netmask);
+	g_free(gc->settings_ip->gateway);
+	g_strfreev(gc->settings_ip->dns);
+	g_free(gc->settings_ip->proxy);
+	g_free(gc->settings_ip);
+	gc->settings_ip = NULL;
+}
+
+static void context_ipv6settings_free(struct ofono_gprs_context *gc)
 {
-	g_free(settings->interface);
-	g_free(settings->ip);
-	g_free(settings->netmask);
-	g_free(settings->gateway);
-	g_strfreev(settings->dns);
-	g_free(settings->proxy);
+	if (gc->settings_ipv6 == NULL)
+		return;
 
-	g_free(settings);
+	g_free(gc->settings_ipv6->interface);
+	g_free(gc->settings_ipv6->address);
+	g_strfreev(gc->settings_ipv6->dns);
+	g_free(gc->settings_ipv6);
+	gc->settings_ipv6 = NULL;
 }
 
-static void context_settings_append_variant(struct context_settings *settings,
+static void context_settings_append_variant(struct ofono_gprs_context *gc,
 						DBusMessageIter *iter)
 {
+	struct context_settings_ip *settings = gc->settings_ip;
 	DBusMessageIter variant;
 	DBusMessageIter array;
 	char typesig[5];
@@ -306,22 +352,21 @@ static void context_settings_append_variant(struct context_settings *settings,
 	if (settings == NULL)
 		goto done;
 
-	ofono_dbus_dict_append(&array, "Interface",
-				DBUS_TYPE_STRING, &settings->interface);
+	if (settings->interface != NULL)
+		ofono_dbus_dict_append(&array, "Interface",
+					DBUS_TYPE_STRING, &settings->interface);
 
-	if (settings->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
+	if (gc->pri->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
 		if (settings->proxy)
 			ofono_dbus_dict_append(&array, "Proxy",
 					DBUS_TYPE_STRING, &settings->proxy);
 		goto done;
 	}
 
-	if (settings->static_ip == TRUE)
-		method = "static";
-	else
-		method = "dhcp";
-
-	ofono_dbus_dict_append(&array, "Method", DBUS_TYPE_STRING, &method);
+	method = gprs_addrconf_to_string(settings->method);
+	if (method != NULL)
+		ofono_dbus_dict_append(&array, "Method", DBUS_TYPE_STRING,
+					&method);
 
 	if (settings->ip)
 		ofono_dbus_dict_append(&array, "Address", DBUS_TYPE_STRING,
@@ -346,7 +391,7 @@ done:
 	dbus_message_iter_close_container(iter, &variant);
 }
 
-static void context_settings_append_dict(struct context_settings *settings,
+static void context_settings_append_dict(struct ofono_gprs_context *gc,
 						DBusMessageIter *dict)
 {
 	DBusMessageIter entry;
@@ -357,14 +402,15 @@ static void context_settings_append_dict(struct context_settings *settings,
 
 	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
 
-	context_settings_append_variant(settings, &entry);
+	context_settings_append_variant(gc, &entry);
 
 	dbus_message_iter_close_container(dict, &entry);
 }
 
-static void pri_context_signal_settings(struct pri_context *ctx)
+static void context_signal_settings(struct ofono_gprs_context *gc)
 {
 	DBusConnection *conn = ofono_dbus_get_connection();
+	struct pri_context *ctx = gc->pri;
 	const char *path = ctx->path;
 	DBusMessage *signal;
 	DBusMessageIter iter;
@@ -374,6 +420,98 @@ static void pri_context_signal_settings(struct pri_context *ctx)
 					OFONO_CONNECTION_CONTEXT_INTERFACE,
 					"PropertyChanged");
 
+	DBG("signal = %p", signal);
+
+	if (signal == NULL)
+		return;
+
+	dbus_message_iter_init_append(signal, &iter);
+
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &prop);
+
+	context_settings_append_variant(gc, &iter);
+
+	g_dbus_send_message(conn, signal);
+}
+
+static void context_ipv6settings_append_variant(struct ofono_gprs_context *gc,
+						DBusMessageIter *iter)
+{
+	struct context_settings_ipv6 *settings = gc->settings_ipv6;
+	DBusMessageIter variant;
+	DBusMessageIter array;
+	char typesig[5];
+	char arraysig[6];
+
+	arraysig[0] = DBUS_TYPE_ARRAY;
+	arraysig[1] = typesig[0] = DBUS_DICT_ENTRY_BEGIN_CHAR;
+	arraysig[2] = typesig[1] = DBUS_TYPE_STRING;
+	arraysig[3] = typesig[2] = DBUS_TYPE_VARIANT;
+	arraysig[4] = typesig[3] = DBUS_DICT_ENTRY_END_CHAR;
+	arraysig[5] = typesig[4] = '\0';
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+						arraysig, &variant);
+	dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
+						typesig, &array);
+
+	if (settings == NULL)
+		goto done;
+
+	if (settings->interface != NULL)
+		ofono_dbus_dict_append(&array, "Interface",
+					DBUS_TYPE_STRING, &settings->interface);
+
+	if (settings->address != NULL) {
+	  uint8_t addr[16];
+	  char *strll = alloca(INET6_ADDRSTRLEN);
+
+	  inet_pton(AF_INET6, settings->address, addr);
+	  memset(addr, 0, 8);
+	  addr[0] = 0xf0;
+	  addr[1] = 0x80;
+	  inet_ntop(AF_INET6, addr, strll, INET6_ADDRSTRLEN);
+	  ofono_dbus_dict_append(&array, "LinkLocal", DBUS_TYPE_STRING, &strll);
+	}
+
+	if (settings->dns != NULL)
+		ofono_dbus_dict_append_array(&array, "DomainNameServers",
+					DBUS_TYPE_STRING, &settings->dns);
+done:
+	dbus_message_iter_close_container(&variant, &array);
+
+	dbus_message_iter_close_container(iter, &variant);
+}
+
+static void context_ipv6settings_append_dict(struct ofono_gprs_context *gc,
+						DBusMessageIter *dict)
+{
+	DBusMessageIter entry;
+	const char *key = "IPv6Settings";
+
+	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+						NULL, &entry);
+
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+	context_ipv6settings_append_variant(gc, &entry);
+
+	dbus_message_iter_close_container(dict, &entry);
+}
+
+static void context_signal_ipv6settings(struct ofono_gprs_context *gc)
+{
+	DBusConnection *conn = ofono_dbus_get_connection();
+	struct pri_context *ctx = gc->pri;
+	const char *path = ctx->path;
+	DBusMessage *signal;
+	DBusMessageIter iter;
+	const char *prop = "IPv6Settings";
+
+	signal = dbus_message_new_signal(path,
+					OFONO_CONNECTION_CONTEXT_INTERFACE,
+					"PropertyChanged");
+
 	if (signal == NULL)
 		return;
 
@@ -381,11 +519,28 @@ static void pri_context_signal_settings(struct pri_context *ctx)
 
 	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &prop);
 
-	context_settings_append_variant(ctx->settings, &iter);
+	context_ipv6settings_append_variant(gc, &iter);
 
 	g_dbus_send_message(conn, signal);
 }
 
+static void pri_context_settings_append_dict(struct pri_context *ctx,
+						DBusMessageIter *dict)
+{
+	struct ofono_gprs_context *ip = NULL, *ipv6 = NULL;
+	GSList *l;
+
+	for (l = ctx->bearers; l; l = l->next) {
+		struct ofono_gprs_context *gc = l->data;
+
+		if (gc->settings_ip)
+			context_settings_append_dict(gc, dict);
+
+		if (gc->settings_ipv6)
+			context_ipv6settings_append_dict(gc, dict);
+	}
+}
+
 static void pri_parse_proxy(struct pri_context *ctx, const char *proxy)
 {
 	char *scheme, *host, *port, *path;
@@ -552,78 +707,62 @@ static void pri_setproxy(const char *interface, const char *proxy)
 
 static void pri_reset_context_settings(struct pri_context *ctx)
 {
-	char *interface;
-
-	if (ctx->settings == NULL)
-		return;
-
-	interface = ctx->settings->interface;
-	ctx->settings->interface = NULL;
-
-	context_settings_free(ctx->settings);
-	ctx->settings = NULL;
-
-	pri_context_signal_settings(ctx);
-
 	if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
-		pri_setaddr(interface, NULL);
-
 		g_free(ctx->proxy_host);
 		ctx->proxy_host = NULL;
 		ctx->proxy_port = 0;
 	}
-
-	pri_ifupdown(interface, FALSE);
-
-	g_free(interface);
 }
 
-static void pri_update_context_settings(struct pri_context *ctx,
-					const char *interface,
-					ofono_bool_t static_ip,
-					const char *ip, const char *netmask,
-					const char *gateway, const char **dns)
+static void pri_update_context_settings(struct pri_context *ctx)
 {
-	if (ctx->settings)
-		context_settings_free(ctx->settings);
+	struct ofono_gprs_context *ip = NULL, *ipv6 = NULL;
+	GSList *l;
 
-	ctx->settings = g_try_new0(struct context_settings, 1);
-	if (ctx->settings == NULL)
-		return;
+	for (l = ctx->bearers; l; l = l->next) {
+		struct ofono_gprs_context *gc = l->data;
 
-	ctx->settings->type = ctx->type;
+		if (gc->settings_ip != NULL)
+			ip = gc;
 
-	ctx->settings->interface = g_strdup(interface);
-	ctx->settings->static_ip = static_ip;
-	ctx->settings->ip = g_strdup(ip);
-	ctx->settings->netmask = g_strdup(netmask);
-	ctx->settings->gateway = g_strdup(gateway);
-	ctx->settings->dns = g_strdupv((char **)dns);
+		if (gc->settings_ipv6 != NULL)
+			ipv6 = gc;
+	}
 
-	if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS && ctx->message_proxy)
-		ctx->settings->proxy = g_strdup(ctx->message_proxy);
+	if (ip != NULL) {
+		pri_ifupdown(ip->settings_ip->interface, TRUE);
 
-	pri_ifupdown(interface, TRUE);
+		if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS &&
+				ctx->message_proxy != NULL) {
+			ip->settings_ip->proxy = g_strdup(ctx->message_proxy);
+			pri_parse_proxy(ctx, ctx->message_proxy);
 
-	if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS) {
-		pri_parse_proxy(ctx, ctx->message_proxy);
+			DBG("proxy %s port %u", ctx->proxy_host,
+				ctx->proxy_port);
+
+			pri_setaddr(ip->settings_ip->interface,
+					ip->settings_ip->ip);
 
-		DBG("proxy %s port %u", ctx->proxy_host, ctx->proxy_port);
+			if (ctx->proxy_host)
+				pri_setproxy(ip->settings_ip->interface,
+						ctx->proxy_host);
 
-		pri_setaddr(interface, ip);
+		}
 
-		if (ctx->proxy_host)
-			pri_setproxy(interface, ctx->proxy_host);
+		context_signal_settings(ip);
 	}
 
-	pri_context_signal_settings(ctx);
+	if (ipv6 != NULL) {
+		pri_ifupdown(ipv6->settings_ipv6->interface, TRUE);
+		context_signal_ipv6settings(ipv6);
+	}
 }
 
 static void append_context_properties(struct pri_context *ctx,
 					DBusMessageIter *dict)
 {
 	const char *type = gprs_context_type_to_string(ctx->type);
-	const char *proto = gprs_proto_to_string(ctx->context.proto);
+	const char *proto = gprs_proto_to_string(ctx->proto);
 	const char *name = ctx->name;
 	dbus_bool_t value;
 	const char *strvalue;
@@ -637,15 +776,15 @@ static void append_context_properties(struct pri_context *ctx,
 
 	ofono_dbus_dict_append(dict, "Protocol", DBUS_TYPE_STRING, &proto);
 
-	strvalue = ctx->context.apn;
+	strvalue = ctx->apn;
 	ofono_dbus_dict_append(dict, "AccessPointName", DBUS_TYPE_STRING,
 				&strvalue);
 
-	strvalue = ctx->context.username;
+	strvalue = ctx->username;
 	ofono_dbus_dict_append(dict, "Username", DBUS_TYPE_STRING,
 				&strvalue);
 
-	strvalue = ctx->context.password;
+	strvalue = ctx->password;
 	ofono_dbus_dict_append(dict, "Password", DBUS_TYPE_STRING,
 				&strvalue);
 
@@ -659,7 +798,7 @@ static void append_context_properties(struct pri_context *ctx,
 					DBUS_TYPE_STRING, &strvalue);
 	}
 
-	context_settings_append_dict(ctx->settings, dict);
+	pri_context_settings_append_dict(ctx, dict);
 }
 
 static DBusMessage *pri_get_properties(DBusConnection *conn,
@@ -685,44 +824,243 @@ static DBusMessage *pri_get_properties(DBusConnection *conn,
 	return reply;
 }
 
-static void pri_activate_callback(const struct ofono_error *error,
-					const char *interface,
-					ofono_bool_t static_ip,
-					const char *ip, const char *netmask,
-					const char *gateway, const char **dns,
-					void *data)
+static void pri_context_activated(struct pri_context *ctx)
 {
-	struct pri_context *ctx = data;
 	DBusConnection *conn = ofono_dbus_get_connection();
 	dbus_bool_t value;
 
-	DBG("%p %s", ctx, interface);
+	ctx->active = TRUE;
+	__ofono_dbus_pending_reply(&ctx->pending,
+				dbus_message_new_method_return(ctx->pending));
+
+	pri_update_context_settings(ctx);
+
+	value = ctx->active;
+	ofono_dbus_signal_property_changed(conn, ctx->path,
+					OFONO_CONNECTION_CONTEXT_INTERFACE,
+					"Active", DBUS_TYPE_BOOLEAN, &value);
+}
+
+static struct ofono_gprs_context *assign_packet_bearer(struct pri_context *ctx)
+{
+	struct ofono_gprs *gprs = ctx->gprs;
+	struct idmap *cidmap = gprs->cid_map;
+	unsigned int cid_min, cid;
+	GSList *l;
+
+	if (cidmap == NULL)
+		return NULL;
+
+	cid_min = idmap_get_min(cidmap);
+
+	cid = gprs_cid_alloc(gprs);
+	if (cid == 0)
+		return NULL;
+
+	for (l = gprs->context_drivers; l; l = l->next) {
+		struct ofono_gprs_context *gc = l->data;
+
+		if (gc->pri != NULL)
+			continue;
+
+		if (gc->type == OFONO_GPRS_CONTEXT_TYPE_ANY ||
+				gc->type == ctx->type) {
+			gc->cid = cid;
+			gc->pri = ctx;
+			ctx->bearers = g_slist_prepend(ctx->bearers, gc);
+			return gc;
+		}
+	}
+
+	return NULL;
+}
+
+static void release_packet_bearer(struct ofono_gprs_context *gc)
+{
+	struct pri_context *ctx;
+	ofono_bool_t ip, ipv6;
+
+	if (gc == NULL)
+		return;
+
+	ctx = gc->pri;
+
+	if (gc->settings_ip != NULL) {
+		if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS)
+			pri_setaddr(gc->settings_ip->interface, NULL);
+
+		pri_ifupdown(gc->settings_ip->interface, FALSE);
+		context_settings_free(gc);
+
+		if (ctx->active == TRUE)
+			context_signal_settings(gc);
+	}
+
+	if (gc->settings_ipv6 != NULL) {
+		pri_ifupdown(gc->settings_ipv6->interface, FALSE);
+		context_ipv6settings_free(gc);
+
+		if (ctx->active == TRUE)
+			context_signal_ipv6settings(gc);
+	}
+
+	if (gc->timer) {
+		g_source_remove(gc->timer);
+		gc->timer = 0;
+	}
+
+	gprs_cid_release(ctx->gprs, gc->cid);
+	gc->cid = 0;
+	ctx->bearers = g_slist_remove(ctx->bearers, gc);
+	gc->pri = NULL;
+}
+
+static void pri_activate_error(struct pri_context *ctx)
+{
+	__ofono_dbus_pending_reply(&ctx->pending,
+				__ofono_error_failed(ctx->pending));
+
+	while (ctx->bearers != NULL)
+		release_packet_bearer(ctx->bearers->data);
+}
+
+static gboolean pri_activate_next(gpointer data);
+
+static void pri_activate_context_callback(const struct ofono_error *error,
+					ofono_bool_t single_bearers,
+					void *data)
+{
+	struct ofono_gprs_context *gc = data;
+	struct pri_context *ctx = gc->pri;
+	enum ofono_gprs_proto proto = gc->proto;
+	int bearers = g_slist_length(ctx->bearers);
+
+	if (ctx == NULL)
+		return;
 
 	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
-		DBG("Activating context failed with error: %s",
+
+		if (bearers > 1) {
+			DBG("Activating second bearer failed with error: %s",
 				telephony_error_to_str(error));
-		__ofono_dbus_pending_reply(&ctx->pending,
-					__ofono_error_failed(ctx->pending));
+			release_packet_bearer(gc);
+			pri_context_activated(ctx);
+			return;
+		}
 
-		gprs_cid_release(ctx->gprs, ctx->context.cid);
-		ctx->context.cid = 0;
-		ctx->context_driver->inuse = FALSE;
-		ctx->context_driver = NULL;
+		DBG("Activating bearer failed with error: %s",
+				telephony_error_to_str(error));
+
+		if (ctx->proto != OFONO_GPRS_PROTO_IPV4V6 ||
+				proto == OFONO_GPRS_PROTO_IPV6) {
+			pri_activate_error(ctx);
+			return;
+		}
+
+		/* Retry first bearer with different protocol */
+		if (proto == OFONO_GPRS_PROTO_IPV4V6)
+			gc->proto = OFONO_GPRS_PROTO_IP;
+		else
+			gc->proto = OFONO_GPRS_PROTO_IPV6;
 
+		gc->timer = g_timeout_add_seconds(ACTIVATE_FAIL_DELAY,
+							pri_activate_next, gc);
 		return;
 	}
 
-	ctx->active = TRUE;
+	if (ctx->proto != OFONO_GPRS_PROTO_IPV4V6 || single_bearers == FALSE ||
+			bearers > 1 || gc->proto == OFONO_GPRS_PROTO_IPV6) {
+		pri_context_activated(ctx);
+		return;
+	}
+
+	/* Activate second bearer */
+	if (gc->settings_ip == NULL)
+		proto = OFONO_GPRS_PROTO_IP;
+	else
+		proto = OFONO_GPRS_PROTO_IPV6;
+
+	gc = assign_packet_bearer(ctx);
+	if (gc == NULL) {
+		/* No suitable driver. Go with a single bearer. */
+		pri_context_activated(ctx);
+		return;
+	}
+
+	gc->proto = proto;
+	gc->timer = g_timeout_add_seconds(0, pri_activate_next, gc);
+}
+
+static gboolean pri_activate_next(gpointer data)
+{
+	struct ofono_gprs_context *gc = data;
+	struct pri_context *ctx = gc->pri;
+
+	gc->timer = 0;
+	gc->driver->activate_primary_new(gc, gc->cid, ctx->apn,	gc->proto,
+						ctx->username, ctx->password,
+						pri_activate_context_callback,
+						gc);
+	return FALSE;
+}
+
+/* Backward compatibility hack (to be removed) ==> */
+
+static void pri_activate_callback_shim(const struct ofono_error *error,
+				const char *interface, ofono_bool_t static_ip,
+				const char *address, const char *netmask,
+				const char *gw, const char **dns, void *data)
+{
+	struct ofono_gprs_context *gc = data;
+
+	if (error->type == OFONO_ERROR_TYPE_NO_ERROR) {
+		ofono_gprs_context_set_ip_interface(gc, interface);
+		ofono_gprs_context_set_ip_addrconf(gc, static_ip ?
+						OFONO_GPRS_ADDRCONF_STATIC :
+						OFONO_GPRS_ADDRCONF_DHCP);
+		ofono_gprs_context_set_ip_address(gc, address);
+		ofono_gprs_context_set_ip_netmask(gc, netmask);
+		ofono_gprs_context_set_ip_gateway(gc, gw);
+		ofono_gprs_context_set_ip_dns_servers(gc, dns);
+	}
+
+	pri_activate_context_callback(error, FALSE, data);
+}
+
+static void activate_primary_shim(struct ofono_gprs_context *gc,
+					unsigned int id,
+					const char *apn,
+					enum ofono_gprs_proto proto,
+					const char *username,
+					const char *password,
+					void *data)
+{
+	struct ofono_gprs_primary_context context;
+
+	memset(&context, 0, sizeof(context));
+	context.cid = gc->cid;
+	strncpy(context.apn, apn, OFONO_GPRS_MAX_APN_LENGTH);
+	strncpy(context.username, username, OFONO_GPRS_MAX_USERNAME_LENGTH);
+	strncpy(context.password, password, OFONO_GPRS_MAX_PASSWORD_LENGTH);
+	context.proto = proto;
+
+	gc->driver->activate_primary(gc, &context, pri_activate_callback_shim,
+					data);
+}
+
+/* <== end of backward compatiblity hack */
+
+static void pri_context_deactivated(struct pri_context *ctx)
+{
+	DBusConnection *conn = ofono_dbus_get_connection();
+	dbus_bool_t value;
+
+	ctx->active = FALSE;
+
 	__ofono_dbus_pending_reply(&ctx->pending,
 				dbus_message_new_method_return(ctx->pending));
 
-	/*
-	 * If we don't have the interface, don't bother emitting any settings,
-	 * as nobody can make use of them
-	 */
-	if (interface != NULL)
-		pri_update_context_settings(ctx, interface, static_ip,
-						ip, netmask, gateway, dns);
+	pri_reset_context_settings(ctx);
 
 	value = ctx->active;
 	ofono_dbus_signal_property_changed(conn, ctx->path,
@@ -730,11 +1068,11 @@ static void pri_activate_callback(const struct ofono_error *error,
 					"Active", DBUS_TYPE_BOOLEAN, &value);
 }
 
-static void pri_deactivate_callback(const struct ofono_error *error, void *data)
+static void pri_deactivate_callback(const struct ofono_error *error,
+						void *data)
 {
-	struct pri_context *ctx = data;
-	DBusConnection *conn = ofono_dbus_get_connection();
-	dbus_bool_t value;
+	struct ofono_gprs_context *gc = data;
+	struct pri_context *ctx = gc->pri;
 
 	if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
 		DBG("Deactivating context failed with error: %s",
@@ -744,21 +1082,16 @@ static void pri_deactivate_callback(const struct ofono_error *error, void *data)
 		return;
 	}
 
-	gprs_cid_release(ctx->gprs, ctx->context.cid);
-	ctx->context.cid = 0;
-	ctx->active = FALSE;
-	ctx->context_driver->inuse = FALSE;
-	ctx->context_driver = NULL;
-
-	__ofono_dbus_pending_reply(&ctx->pending,
-				dbus_message_new_method_return(ctx->pending));
+	release_packet_bearer(gc);
 
-	pri_reset_context_settings(ctx);
+	if (ctx->bearers != NULL) {
+		gc = ctx->bearers->data;
+		gc->driver->deactivate_primary(gc, gc->cid,
+					pri_deactivate_callback, gc);
+		return;
+	}
 
-	value = ctx->active;
-	ofono_dbus_signal_property_changed(conn, ctx->path,
-					OFONO_CONNECTION_CONTEXT_INTERFACE,
-					"Active", DBUS_TYPE_BOOLEAN, &value);
+	pri_context_deactivated(ctx);
 }
 
 static DBusMessage *pri_set_apn(struct pri_context *ctx, DBusConnection *conn,
@@ -769,13 +1102,13 @@ static DBusMessage *pri_set_apn(struct pri_context *ctx, DBusConnection *conn,
 	if (strlen(apn) > OFONO_GPRS_MAX_APN_LENGTH)
 		return __ofono_error_invalid_format(msg);
 
-	if (g_str_equal(apn, ctx->context.apn))
+	if (g_str_equal(apn, ctx->apn))
 		return dbus_message_new_method_return(msg);
 
 	if (is_valid_apn(apn) == FALSE)
 		return __ofono_error_invalid_format(msg);
 
-	strcpy(ctx->context.apn, apn);
+	strcpy(ctx->apn, apn);
 
 	if (settings) {
 		g_key_file_set_string(settings, ctx->key,
@@ -802,10 +1135,10 @@ static DBusMessage *pri_set_username(struct pri_context *ctx,
 	if (strlen(username) > OFONO_GPRS_MAX_USERNAME_LENGTH)
 		return __ofono_error_invalid_format(msg);
 
-	if (g_str_equal(username, ctx->context.username))
+	if (g_str_equal(username, ctx->username))
 		return dbus_message_new_method_return(msg);
 
-	strcpy(ctx->context.username, username);
+	strcpy(ctx->username, username);
 
 	if (settings) {
 		g_key_file_set_string(settings, ctx->key,
@@ -832,10 +1165,10 @@ static DBusMessage *pri_set_password(struct pri_context *ctx,
 	if (strlen(password) > OFONO_GPRS_MAX_PASSWORD_LENGTH)
 		return __ofono_error_invalid_format(msg);
 
-	if (g_str_equal(password, ctx->context.password))
+	if (g_str_equal(password, ctx->password))
 		return dbus_message_new_method_return(msg);
 
-	strcpy(ctx->context.password, password);
+	strcpy(ctx->password, password);
 
 	if (settings) {
 		g_key_file_set_string(settings, ctx->key,
@@ -891,10 +1224,10 @@ static DBusMessage *pri_set_proto(struct pri_context *ctx,
 	if (gprs_proto_from_string(str, &proto) == FALSE)
 		return __ofono_error_invalid_format(msg);
 
-	if (ctx->context.proto == proto)
+	if (ctx->proto == proto)
 		return dbus_message_new_method_return(msg);
 
-	ctx->context.proto = proto;
+	ctx->proto = proto;
 
 	if (settings) {
 		g_key_file_set_string(settings, ctx->key, "Protocol", str);
@@ -995,42 +1328,11 @@ static DBusMessage *pri_set_message_center(struct pri_context *ctx,
 	return NULL;
 }
 
-static gboolean assign_context(struct pri_context *ctx)
-{
-	struct idmap *cidmap = ctx->gprs->cid_map;
-	unsigned int cid_min;
-	GSList *l;
-
-	if (cidmap == NULL)
-		return FALSE;
-
-	cid_min = idmap_get_min(cidmap);
-
-	ctx->context.cid = gprs_cid_alloc(ctx->gprs);
-	if (ctx->context.cid == 0)
-		return FALSE;
-
-	for (l = ctx->gprs->context_drivers; l; l = l->next) {
-		struct ofono_gprs_context *gc = l->data;
-
-		if (gc->inuse == TRUE)
-			continue;
-
-		if (gc->type == OFONO_GPRS_CONTEXT_TYPE_ANY ||
-						gc->type == ctx->type) {
-			ctx->context_driver = gc;
-			ctx->context_driver->inuse = TRUE;
-			return TRUE;
-		}
-	}
-
-	return FALSE;
-}
-
 static DBusMessage *pri_set_property(DBusConnection *conn,
 					DBusMessage *msg, void *data)
 {
 	struct pri_context *ctx = data;
+	struct ofono_gprs *gprs = ctx->gprs;
 	DBusMessageIter iter;
 	DBusMessageIter var;
 	const char *property;
@@ -1052,9 +1354,9 @@ static DBusMessage *pri_set_property(DBusConnection *conn,
 	dbus_message_iter_recurse(&iter, &var);
 
 	if (g_str_equal(property, "Active")) {
-		struct ofono_gprs_context *gc;
+		struct ofono_gprs_context *gc = NULL;
 
-		if (ctx->gprs->pending)
+		if (gprs->pending)
 			return __ofono_error_busy(msg);
 
 		if (ctx->pending)
@@ -1068,31 +1370,49 @@ static DBusMessage *pri_set_property(DBusConnection *conn,
 		if (ctx->active == (ofono_bool_t) value)
 			return dbus_message_new_method_return(msg);
 
-		if (value && !ctx->gprs->attached)
+		if (value && !gprs->attached)
 			return __ofono_error_not_attached(msg);
 
-		if (ctx->gprs->flags & GPRS_FLAG_ATTACHING)
+		if (gprs->flags & GPRS_FLAG_ATTACHING)
 			return __ofono_error_attach_in_progress(msg);
 
-		if (value) {
-			if (assign_context(ctx) == FALSE)
-				return __ofono_error_not_implemented(msg);
-		}
+		if (value)
+			gc = assign_packet_bearer(ctx);
+		else if (ctx->bearers != NULL)
+			gc = ctx->bearers->data;
 
-		gc = ctx->context_driver;
 		if (gc == NULL || gc->driver == NULL ||
-				gc->driver->activate_primary == NULL ||
+				(gc->driver->activate_primary == NULL &&
+				gc->driver->activate_primary_new == NULL) ||
 				gc->driver->deactivate_primary == NULL)
 			return __ofono_error_not_implemented(msg);
 
 		ctx->pending = dbus_message_ref(msg);
 
-		if (value)
-			gc->driver->activate_primary(gc, &ctx->context,
-						pri_activate_callback, ctx);
-		else
-			gc->driver->deactivate_primary(gc, ctx->context.cid,
-						pri_deactivate_callback, ctx);
+		if (value) {
+			gc->proto = ctx->proto;
+			/* Backward compatiblity hack (to be removed) ==> */
+			if (gc->driver->activate_primary_new == NULL)
+				activate_primary_shim(gc,
+						gc->cid,
+						ctx->apn,
+						gc->proto,
+						ctx->username,
+						ctx->password,
+						gc);
+			else
+			/* <== end of backward compatiblity hack */
+				gc->driver->activate_primary_new(gc,
+						gc->cid,
+						ctx->apn,
+						gc->proto,
+						ctx->username,
+						ctx->password,
+						pri_activate_context_callback,
+						gc);
+		} else
+			gc->driver->deactivate_primary(gc, gc->cid,
+						pri_deactivate_callback, gc);
 
 		return NULL;
 	}
@@ -1207,10 +1527,7 @@ static void pri_context_destroy(gpointer userdata)
 {
 	struct pri_context *ctx = userdata;
 
-	if (ctx->settings) {
-		context_settings_free(ctx->settings);
-		ctx->settings = NULL;
-	}
+	pri_reset_context_settings(ctx);
 
 	g_free(ctx->proxy_host);
 
@@ -1344,13 +1661,10 @@ static void gprs_attached_update(struct ofono_gprs *gprs)
 			if (ctx->active == FALSE)
 				continue;
 
-			gprs_cid_release(gprs, ctx->context.cid);
-			ctx->context.cid = 0;
 			ctx->active = FALSE;
-			ctx->context_driver->inuse = FALSE;
-			ctx->context_driver = NULL;
 
-			pri_reset_context_settings(ctx);
+			while (ctx->bearers != NULL)
+				release_packet_bearer(ctx->bearers->data);
 
 			value = FALSE;
 			ofono_dbus_signal_property_changed(conn, ctx->path,
@@ -1597,15 +1911,15 @@ static void write_context_settings(struct ofono_gprs *gprs,
 	g_key_file_set_string(gprs->settings, context->key,
 				"Name", context->name);
 	g_key_file_set_string(gprs->settings, context->key,
-				"AccessPointName", context->context.apn);
+				"AccessPointName", context->apn);
 	g_key_file_set_string(gprs->settings, context->key,
-				"Username", context->context.username);
+				"Username", context->username);
 	g_key_file_set_string(gprs->settings, context->key,
-				"Password", context->context.password);
+				"Password", context->password);
 	g_key_file_set_string(gprs->settings, context->key, "Type",
 				gprs_context_type_to_string(context->type));
 	g_key_file_set_string(gprs->settings, context->key, "Protocol",
-				gprs_proto_to_string(context->context.proto));
+				gprs_proto_to_string(context->proto));
 }
 
 static struct pri_context *add_context(struct ofono_gprs *gprs,
@@ -1711,7 +2025,8 @@ static DBusMessage *gprs_add_context(DBusConnection *conn,
 static void gprs_deactivate_for_remove(const struct ofono_error *error,
 						void *data)
 {
-	struct pri_context *ctx = data;
+	struct ofono_gprs_context *gc = data;
+	struct pri_context *ctx = gc->pri;
 	struct ofono_gprs *gprs = ctx->gprs;
 	DBusConnection *conn;
 	char *path;
@@ -1726,10 +2041,14 @@ static void gprs_deactivate_for_remove(const struct ofono_error *error,
 		return;
 	}
 
-	gprs_cid_release(gprs, ctx->context.cid);
-	ctx->context.cid = 0;
-	ctx->context_driver->inuse = FALSE;
-	ctx->context_driver = NULL;
+	release_packet_bearer(gc);
+
+	if (ctx->bearers != NULL) {
+		gc = ctx->bearers->data;
+		gc->driver->deactivate_primary(gc, gc->cid,
+					gprs_deactivate_for_remove, gc);
+		return;
+	}
 
 	if (gprs->settings) {
 		g_key_file_remove_group(gprs->settings, ctx->key, NULL);
@@ -1776,15 +2095,16 @@ static DBusMessage *gprs_remove_context(DBusConnection *conn,
 		return __ofono_error_not_found(msg);
 
 	if (ctx->active) {
-		struct ofono_gprs_context *gc = ctx->context_driver;
+		struct ofono_gprs_context *gc;
 
 		/* This context is already being messed with */
 		if (ctx->pending)
 			return __ofono_error_busy(msg);
 
 		gprs->pending = dbus_message_ref(msg);
-		gc->driver->deactivate_primary(gc, ctx->context.cid,
-					gprs_deactivate_for_remove, ctx);
+		gc = ctx->bearers->data;
+		gc->driver->deactivate_primary(gc, gc->cid,
+					gprs_deactivate_for_remove, gc);
 		return NULL;
 	}
 
@@ -1810,7 +2130,8 @@ static DBusMessage *gprs_remove_context(DBusConnection *conn,
 static void gprs_deactivate_for_all(const struct ofono_error *error,
 					void *data)
 {
-	struct pri_context *ctx = data;
+	struct ofono_gprs_context *gc = data;
+	struct pri_context *ctx = gc->pri;
 	struct ofono_gprs *gprs = ctx->gprs;
 	DBusConnection *conn;
 	dbus_bool_t value;
@@ -1821,12 +2142,16 @@ static void gprs_deactivate_for_all(const struct ofono_error *error,
 		return;
 	}
 
-	gprs_cid_release(gprs, ctx->context.cid);
-	ctx->active = FALSE;
-	ctx->context.cid = 0;
-	ctx->context_driver->inuse = FALSE;
-	ctx->context_driver = NULL;
+	release_packet_bearer(gc);
+
+	if (ctx->bearers != NULL) {
+		gc = ctx->bearers->data;
+		gc->driver->deactivate_primary(gc, gc->cid,
+						gprs_deactivate_for_all, gc);
+		return;
+	}
 
+	ctx->active = FALSE;
 	pri_reset_context_settings(ctx);
 
 	value = ctx->active;
@@ -1850,9 +2175,9 @@ static void gprs_deactivate_next(struct ofono_gprs *gprs)
 		if (ctx->active == FALSE)
 			continue;
 
-		gc = ctx->context_driver;
-		gc->driver->deactivate_primary(gc, ctx->context.cid,
-					gprs_deactivate_for_all, ctx);
+		gc = ctx->bearers->data;
+		gc->driver->deactivate_primary(gc, gc->cid,
+						gprs_deactivate_for_all, gc);
 
 		return;
 	}
@@ -2062,34 +2387,23 @@ void ofono_gprs_context_deactivated(struct ofono_gprs_context *gc,
 {
 	DBusConnection *conn = ofono_dbus_get_connection();
 	GSList *l;
-	struct pri_context *ctx;
+	struct pri_context *ctx = gc->pri;
 	dbus_bool_t value;
 
-	if (gc->gprs == NULL)
+	if (gc->gprs == NULL || ctx == NULL || ctx->active == FALSE)
 		return;
 
-	for (l = gc->gprs->contexts; l; l = l->next) {
-		ctx = l->data;
-
-		if (ctx->context.cid != cid)
-			continue;
-
-		if (ctx->active == FALSE)
-			break;
-
-		gprs_cid_release(ctx->gprs, ctx->context.cid);
-		ctx->context.cid = 0;
-		ctx->active = FALSE;
-		ctx->context_driver->inuse = FALSE;
-		ctx->context_driver = NULL;
+	release_packet_bearer(gc);
 
-		pri_reset_context_settings(ctx);
+	if (ctx->bearers != NULL)
+		return;
 
-		value = FALSE;
-		ofono_dbus_signal_property_changed(conn, ctx->path,
+	ctx->active = FALSE;
+	pri_reset_context_settings(ctx);
+	value = FALSE;
+	ofono_dbus_signal_property_changed(conn, ctx->path,
 					OFONO_CONNECTION_CONTEXT_INTERFACE,
 					"Active", DBUS_TYPE_BOOLEAN, &value);
-	}
 }
 
 int ofono_gprs_context_driver_register(const struct ofono_gprs_context_driver *d)
@@ -2120,6 +2434,9 @@ static void gprs_context_remove(struct ofono_atom *atom)
 	if (gc == NULL)
 		return;
 
+	if (gc->pri != NULL)
+		release_packet_bearer(gc);
+
 	if (gc->driver && gc->driver->remove)
 		gc->driver->remove(gc);
 
@@ -2192,6 +2509,131 @@ void ofono_gprs_context_set_type(struct ofono_gprs_context *gc,
 	gc->type = type;
 }
 
+static struct context_settings_ip *get_ip_settings(struct ofono_gprs_context *gc)
+{
+	if (gc == NULL)
+		return NULL;
+
+	if (gc->settings_ip == NULL)
+		gc->settings_ip = g_try_new0(struct context_settings_ip, 1);
+
+	return gc->settings_ip;
+}
+
+void ofono_gprs_context_set_ip_interface(struct ofono_gprs_context *gc,
+					const char *interface)
+{
+	struct context_settings_ip *settings = get_ip_settings(gc);
+
+	if (settings == NULL || settings->interface != NULL)
+		return;
+
+	settings->interface = g_strdup(interface);
+}
+
+void ofono_gprs_context_set_ip_addrconf(struct ofono_gprs_context *gc,
+					enum ofono_gprs_addrconf_method method)
+{
+	struct context_settings_ip *settings = get_ip_settings(gc);
+
+	if (settings == NULL || settings->method != OFONO_GPRS_ADDRCONF_NONE)
+		return;
+
+	settings->method = method;
+}
+
+void ofono_gprs_context_set_ip_address(struct ofono_gprs_context *gc,
+					const char *address)
+{
+	struct context_settings_ip *settings = get_ip_settings(gc);
+
+	if (settings == NULL || settings->ip != NULL)
+		return;
+
+	settings->ip = g_strdup(address);
+}
+
+void ofono_gprs_context_set_ip_netmask(struct ofono_gprs_context *gc,
+					const char *netmask)
+{
+	struct context_settings_ip *settings = get_ip_settings(gc);
+
+	if (settings == NULL || settings->netmask != NULL)
+		return;
+
+	settings->netmask = g_strdup(netmask);
+}
+
+void ofono_gprs_context_set_ip_gateway(struct ofono_gprs_context *gc,
+					const char *gateway)
+{
+	struct context_settings_ip *settings = get_ip_settings(gc);
+
+	if (settings == NULL || settings->gateway != NULL)
+		return;
+
+	settings->gateway = g_strdup(gateway);
+}
+
+void ofono_gprs_context_set_ip_dns_servers(struct ofono_gprs_context *gc,
+						const char **dns)
+{
+	struct context_settings_ip *settings = get_ip_settings(gc);
+
+	if (settings == NULL || settings->dns != NULL)
+		return;
+
+	settings->dns = g_strdupv((char **)dns);
+}
+
+static struct context_settings_ipv6 *get_ipv6_settings(struct ofono_gprs_context *gc)
+{
+	if (gc == NULL)
+		return NULL;
+
+	if (gc->settings_ipv6 == NULL) {
+		gc->settings_ipv6 = g_try_new0(struct context_settings_ipv6, 1);
+
+		if (gc->settings_ipv6 == NULL)
+			return NULL;
+	}
+
+	return gc->settings_ipv6;
+}
+
+void ofono_gprs_context_set_ipv6_interface(struct ofono_gprs_context *gc,
+					const char *interface)
+{
+	struct context_settings_ipv6 *settings = get_ipv6_settings(gc);
+
+	if (settings == NULL || settings->interface != NULL)
+		return;
+
+	settings->interface = g_strdup(interface);
+}
+
+void ofono_gprs_context_set_ipv6_address(struct ofono_gprs_context *gc,
+						const char *address)
+{
+	struct context_settings_ipv6 *settings = get_ipv6_settings(gc);
+
+	if (settings == NULL || settings->address != NULL)
+		return;
+
+	settings->address = g_strdup(address);
+}
+
+void ofono_gprs_context_set_ipv6_dns_servers(struct ofono_gprs_context *gc,
+						const char **dns)
+{
+	struct context_settings_ipv6 *settings = get_ipv6_settings(gc);
+
+	if (settings == NULL || settings->dns != NULL)
+		return;
+
+	settings->dns = g_strdupv((char **)dns);
+}
+
 int ofono_gprs_driver_register(const struct ofono_gprs_driver *d)
 {
 	DBG("driver: %p, name: %s", d, d->name);
@@ -2431,10 +2873,10 @@ static gboolean load_context(struct ofono_gprs *gprs, const char *group)
 
 	idmap_take(gprs->pid_map, id);
 	context->id = id;
-	strcpy(context->context.username, username);
-	strcpy(context->context.password, password);
-	strcpy(context->context.apn, apn);
-	context->context.proto = proto;
+	strcpy(context->username, username);
+	strcpy(context->password, password);
+	strcpy(context->apn, apn);
+	context->proto = proto;
 
 	if (msgproxy != NULL)
 		strcpy(context->message_proxy, msgproxy);
-- 
1.7.1


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

* [RFC 4/5] test: modify test scripts for IPv6
  2011-01-26 16:22 RFC: IPv6 support Mika Liljeberg
                   ` (2 preceding siblings ...)
  2011-01-26 16:22 ` [RFC 3/5] gprs: core support " Mika Liljeberg
@ 2011-01-26 16:22 ` Mika Liljeberg
  2011-01-26 16:22 ` [RFC 5/5] isimodem: IPv6 support Mika Liljeberg
  4 siblings, 0 replies; 14+ messages in thread
From: Mika Liljeberg @ 2011-01-26 16:22 UTC (permalink / raw)
  To: ofono

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

---
 Makefile.am        |    3 ++-
 test/list-contexts |    6 +++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 71365d7..6c53215 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -470,7 +470,8 @@ test_scripts = test/backtrace \
 		test/cdma-list-call \
 		test/cdma-dial-number \
 		test/cdma-hangup \
-		test/disable-call-forwarding
+		test/disable-call-forwarding \
+		test/set-context-property
 
 if TEST
 testdir = $(pkglibdir)/test
diff --git a/test/list-contexts b/test/list-contexts
index 68dae6a..9519ade 100755
--- a/test/list-contexts
+++ b/test/list-contexts
@@ -24,15 +24,15 @@ for path, properties in modems:
 		print "    [ %s ]" % (path)
 
 		for key in properties.keys():
-			if key in ["Settings"]:
+			if key in ["Settings"] or key in ["IPv6Settings"]:
 				val = "{"
 				for i in properties[key].keys():
 					val += " " + i + "="
 					if i in ["DomainNameServers"]:
 						for n in properties[key][i]:
-							val += n + ","
+							val += str(n) + ","
 					else:
-						val += properties[key][i]
+						val += str(properties[key][i])
 				val += " }"
 			else:
 				val = str(properties[key])
-- 
1.7.1


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

* [RFC 5/5] isimodem: IPv6 support
  2011-01-26 16:22 RFC: IPv6 support Mika Liljeberg
                   ` (3 preceding siblings ...)
  2011-01-26 16:22 ` [RFC 4/5] test: modify test scripts " Mika Liljeberg
@ 2011-01-26 16:22 ` Mika Liljeberg
  4 siblings, 0 replies; 14+ messages in thread
From: Mika Liljeberg @ 2011-01-26 16:22 UTC (permalink / raw)
  To: ofono

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

---
 drivers/isimodem/gprs-context.c |  137 ++++++++++++++++++++++++--------------
 1 files changed, 86 insertions(+), 51 deletions(-)

diff --git a/drivers/isimodem/gprs-context.c b/drivers/isimodem/gprs-context.c
index 6d579d8..4665198 100644
--- a/drivers/isimodem/gprs-context.c
+++ b/drivers/isimodem/gprs-context.c
@@ -63,7 +63,7 @@ struct context_data {
 	unsigned cid;	/* oFono core context ID */
 	struct ofono_gprs_context *context;
 	union {
-		ofono_gprs_context_up_cb_t up_cb;
+		ofono_gprs_context_activate_cb_t up_cb;
 		ofono_gprs_context_cb_t down_cb;
 	};
 	void *data;
@@ -112,15 +112,14 @@ typedef void (*ContextFailFunc)(struct context_data *cd);
 
 static void gprs_up_fail(struct context_data *cd)
 {
-	CALLBACK_WITH_FAILURE(cd->up_cb, NULL, 0, NULL, NULL, NULL, NULL,
-				cd->data);
 	reset_context(cd);
+	CALLBACK_WITH_FAILURE(cd->up_cb, FALSE, cd->data);
 }
 
 static void gprs_down_fail(struct context_data *cd)
 {
-	CALLBACK_WITH_FAILURE(cd->down_cb, cd->data);
 	reset_context(cd);
+	CALLBACK_WITH_FAILURE(cd->down_cb, cd->data);
 }
 
 static gboolean check_resp(const GIsiMessage *msg, uint8_t id, size_t minlen,
@@ -208,9 +207,12 @@ static void activate_ind_cb(const GIsiMessage *msg, void *opaque)
 	GIsiSubBlockIter iter;
 
 	char ifname[IF_NAMESIZE];
-	char *ip = NULL;
-	char *pdns = NULL;
-	char *sdns = NULL;
+	char *ip_addr = NULL;
+	char *ip_pdns = NULL;
+	char *ip_sdns = NULL;
+	char *ipv6_addr = NULL;
+	char *ipv6_pdns = NULL;
+	char *ipv6_sdns = NULL;
 	const char *dns[3];
 
 	if (!check_ind(msg, 2, cd))
@@ -225,8 +227,6 @@ static void activate_ind_cb(const GIsiMessage *msg, void *opaque)
 
 		switch (g_isi_sb_iter_get_id(&iter)) {
 
-		/* TODO: IPv6 address support */
-
 		case GPDS_PDP_ADDRESS_INFO:
 
 			if (!g_isi_sb_iter_get_byte(&iter, &addr_len, 3))
@@ -236,9 +236,16 @@ static void activate_ind_cb(const GIsiMessage *msg, void *opaque)
 							4))
 				goto error;
 
-			ip = alloca(INET_ADDRSTRLEN);
-			inet_ntop(AF_INET, (const void *)addr_value, ip,
-					INET_ADDRSTRLEN);
+			if (addr_len == 4) {
+				ip_addr = alloca(INET_ADDRSTRLEN);
+				inet_ntop(AF_INET, (const void *)addr_value,
+						ip_addr, INET_ADDRSTRLEN);
+			} else if (addr_len == 16) {
+				ipv6_addr = alloca(INET6_ADDRSTRLEN);
+				inet_ntop(AF_INET6, (const void *)addr_value,
+						ipv6_addr, INET6_ADDRSTRLEN);
+				DBG("IPv6 addr = <%s>", ipv6_addr);
+			}
 			break;
 
 		case GPDS_PDNS_ADDRESS_INFO:
@@ -250,9 +257,15 @@ static void activate_ind_cb(const GIsiMessage *msg, void *opaque)
 							4))
 				break;
 
-			pdns = alloca(INET_ADDRSTRLEN);
-			inet_ntop(AF_INET, (const void *)addr_value, pdns,
-					INET_ADDRSTRLEN);
+			if (addr_len == 4) {
+				ip_pdns = alloca(INET_ADDRSTRLEN);
+				inet_ntop(AF_INET, (const void *)addr_value,
+						ip_pdns, INET_ADDRSTRLEN);
+			} else if (addr_len == 16) {
+				ipv6_pdns = alloca(INET6_ADDRSTRLEN);
+				inet_ntop(AF_INET6, (const void *)addr_value,
+						ipv6_pdns, INET6_ADDRSTRLEN);
+			}
 			break;
 
 		case GPDS_SDNS_ADDRESS_INFO:
@@ -264,9 +277,15 @@ static void activate_ind_cb(const GIsiMessage *msg, void *opaque)
 							4))
 				break;
 
-			sdns = alloca(INET_ADDRSTRLEN);
-			inet_ntop(AF_INET, (const void *)addr_value, sdns,
-					INET_ADDRSTRLEN);
+			if (addr_len == 4) {
+				ip_sdns = alloca(INET_ADDRSTRLEN);
+				inet_ntop(AF_INET, (const void *)addr_value,
+						ip_sdns, INET_ADDRSTRLEN);
+			} else if (addr_len == 16) {
+				ipv6_sdns = alloca(INET6_ADDRSTRLEN);
+				inet_ntop(AF_INET6, (const void *)addr_value,
+						ipv6_sdns, INET6_ADDRSTRLEN);
+			}
 			break;
 
 		default:
@@ -279,29 +298,29 @@ static void activate_ind_cb(const GIsiMessage *msg, void *opaque)
 	if (!g_isi_pep_get_ifname(cd->pep, ifname))
 		goto error;
 
-	dns[0] = pdns;
-	dns[1] = sdns;
-	dns[2] = 0;
+	if (ip_addr != NULL) {
+		const char *dns[3] = { ip_pdns, ip_sdns, 0 };
+		ofono_gprs_context_set_ip_interface(cd->context, ifname);
+		ofono_gprs_context_set_ip_address(cd->context, ip_addr);
+		ofono_gprs_context_set_ip_addrconf(cd->context,
+						OFONO_GPRS_ADDRCONF_STATIC);
+		ofono_gprs_context_set_ip_dns_servers(cd->context, dns);
+	}
+
+	if (ipv6_addr != NULL) {
+		const char *dns[3] = { ipv6_pdns, ipv6_sdns, 0 };
+		ofono_gprs_context_set_ipv6_interface(cd->context, ifname);
+		ofono_gprs_context_set_ipv6_address(cd->context, ipv6_addr);
+		ofono_gprs_context_set_ipv6_dns_servers(cd->context, dns);
+	}
 
-	CALLBACK_WITH_SUCCESS(cd->up_cb, ifname, TRUE, (const char *)ip,
-					STATIC_IP_NETMASK, NULL,
-					dns, cd->data);
+	CALLBACK_WITH_SUCCESS(cd->up_cb, TRUE, cd->data);
 	return;
 
 error:
 	gprs_up_fail(cd);
 }
 
-static void activate_fail_ind_cb(const GIsiMessage *msg, void *opaque)
-{
-	struct context_data *cd = opaque;
-
-	if (!check_ind(msg, 2, cd))
-		return;
-
-	gprs_up_fail(cd);
-}
-
 static void context_activate_cb(const GIsiMessage *msg, void *cd)
 {
 	check_resp(msg, GPDS_CONTEXT_ACTIVATE_RESP, 6, cd, gprs_up_fail);
@@ -319,8 +338,6 @@ static void send_context_activate(GIsiClient *client, void *opaque)
 
 	g_isi_client_ind_subscribe(client, GPDS_CONTEXT_ACTIVATE_IND,
 				activate_ind_cb, cd);
-	g_isi_client_ind_subscribe(client, GPDS_CONTEXT_ACTIVATE_FAIL_IND,
-				activate_fail_ind_cb, cd);
 	g_isi_client_ind_subscribe(client, GPDS_CONTEXT_DEACTIVATE_IND,
 				deactivate_ind_cb, cd);
 
@@ -458,18 +475,22 @@ static void create_pipe_cb(GIsiPipe *pipe)
 		gprs_up_fail(cd);
 }
 
-static void isi_gprs_activate_primary(struct ofono_gprs_context *gc,
-				const struct ofono_gprs_primary_context *ctx,
-				ofono_gprs_context_up_cb_t cb, void *data)
+static void isi_gprs_activate_primary_new(struct ofono_gprs_context *gc,
+					unsigned int id,
+					const char *apn,
+					enum ofono_gprs_proto proto,
+					const char *username,
+					const char *password,
+					ofono_gprs_context_activate_cb_t cb,
+					void *data)
 {
 	struct context_data *cd = ofono_gprs_context_get_data(gc);
 
-	DBG("activate: gpds = 0x%04x", cd->gpds);
+	DBG("activate: gpds = 0x%04x apn=%s proto=%d", cd->gpds, apn, proto);
 
 	if (cd == NULL || !cd->gpds) {
 		/* GPDS is not reachable */
-		CALLBACK_WITH_FAILURE(cb, NULL, 0, NULL, NULL, NULL,
-					NULL, data);
+		CALLBACK_WITH_FAILURE(cb, FALSE, data);
 		return;
 	}
 
@@ -479,26 +500,40 @@ static void isi_gprs_activate_primary(struct ofono_gprs_context *gc,
 		cd->reset = 0;
 	}
 
-	cd->cid = ctx->cid;
+	cd->cid = id;
 	cd->up_cb = cb;
 	cd->data = data;
 	cd->pep = NULL;
 	cd->pipe = NULL;
 	cd->handle = INVALID_ID;
-	cd->type = GPDS_PDP_TYPE_IPV4;
 
-	if (strlen(ctx->apn) >= GPDS_MAX_APN_STRING_LENGTH
-			|| strlen(ctx->username) >= GPDS_MAX_USERNAME_LENGTH
-			|| strlen(ctx->password) >= GPDS_MAX_PASSWORD_LENGTH)
+	switch (proto) {
+	case OFONO_GPRS_PROTO_IP:
+		cd->type = GPDS_PDP_TYPE_IPV4;
+		break;
+
+	case OFONO_GPRS_PROTO_IPV6:
+		cd->type = GPDS_PDP_TYPE_IPV6;
+		break;
+
+	case OFONO_GPRS_PROTO_IPV4V6:
+		/* Not supported by modem */
+		CALLBACK_WITH_FAILURE(cb, TRUE, data);
+		return;
+	}
+
+	if (strlen(apn) >= GPDS_MAX_APN_STRING_LENGTH
+			|| strlen(username) >= GPDS_MAX_USERNAME_LENGTH
+			|| strlen(password) >= GPDS_MAX_PASSWORD_LENGTH)
 		goto error;
 
-	strncpy(cd->apn, ctx->apn, GPDS_MAX_APN_STRING_LENGTH);
+	strncpy(cd->apn, apn, GPDS_MAX_APN_STRING_LENGTH);
 	cd->apn[GPDS_MAX_APN_STRING_LENGTH] = '\0';
 
-	strncpy(cd->username, ctx->username, GPDS_MAX_USERNAME_LENGTH);
+	strncpy(cd->username, username, GPDS_MAX_USERNAME_LENGTH);
 	cd->username[GPDS_MAX_USERNAME_LENGTH] = '\0';
 
-	strncpy(cd->password, ctx->password, GPDS_MAX_PASSWORD_LENGTH);
+	strncpy(cd->password, password, GPDS_MAX_PASSWORD_LENGTH);
 	cd->username[GPDS_MAX_PASSWORD_LENGTH] = '\0';
 
 	cd->pep = g_isi_pep_create(cd->idx, NULL, NULL);
@@ -618,7 +653,7 @@ static struct ofono_gprs_context_driver driver = {
 	.name			= "isimodem",
 	.probe			= isi_gprs_context_probe,
 	.remove			= isi_gprs_context_remove,
-	.activate_primary	= isi_gprs_activate_primary,
+	.activate_primary_new	= isi_gprs_activate_primary_new,
 	.deactivate_primary	= isi_gprs_deactivate_primary,
 };
 
-- 
1.7.1


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

* Re: [RFC 1/5] gprs: Update documentation for IPv6
  2011-01-26 16:22 ` [RFC 1/5] gprs: Update documentation for IPv6 Mika Liljeberg
@ 2011-01-28 12:49   ` Sjur =?unknown-8bit?q?Br=C3=A6ndeland?=
  2011-01-28 14:00     ` Mika.Liljeberg
  2011-01-28 14:41     ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
  0 siblings, 2 replies; 14+ messages in thread
From: Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= @ 2011-01-28 12:49 UTC (permalink / raw)
  To: ofono

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

Hi,
> +               dict IPv6Settings [readonly, optional]
> +
> +                       Holds all the IPv6 network settings.
> +
> +                       string Interface [readonly, optional]
> +
> +                               Holds the name of the IPv6 network interface
> +                               used by this context (e.g. "ppp0" "usb0").
> +
> +                               For combined IPv4v6 context (3GPP rel 8) the
> +                               same network interface may be used for both
> +                               IPv4 and IPv6. IPv4 and IPv6 may also be
> +                               offered via separate network interfaces.
> +

I think it would be nice if we could keep only one interface here.
It's a bit messy that the difference between R7 and R8
networks will be visible to the users like this.

So when in a R7 network the uplink traffic should be filtered into the
right ipv4 and ipv6 pdp-connection automagically.
I know STE will support this in the modem firmware.

If firmware doesn't support this perhaps this could also be handled
in the kernel drivers. This should be doable for phonet (and Caif),
maybe a little more tricky with ppp/pppd?

Regards,
Sjur

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

* RE: [RFC 1/5] gprs: Update documentation for IPv6
  2011-01-28 12:49   ` Sjur =?unknown-8bit?q?Br=C3=A6ndeland?=
@ 2011-01-28 14:00     ` Mika.Liljeberg
  2011-01-28 14:17       ` Marcel Holtmann
  2011-01-28 14:41     ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
  1 sibling, 1 reply; 14+ messages in thread
From: Mika.Liljeberg @ 2011-01-28 14:00 UTC (permalink / raw)
  To: ofono

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

Hi Sjur,

> > +   For combined IPv4v6 context (3GPP rel 8) the
> > +   same network interface may be used for both
> > +   IPv4 and IPv6. IPv4 and IPv6 may also be
> > +   offered via separate network interfaces.
> > +
> 
> I think it would be nice if we could keep only one interface here.
> It's a bit messy that the difference between R7 and R8
> networks will be visible to the users like this.

By users I assume you mean connman?

> So when in a R7 network the uplink traffic should be filtered into the
> right ipv4 and ipv6 pdp-connection automagically.
> I know STE will support this in the modem firmware.

It's cool that STE firmware can do that. However, for modems that don't (most of them), I frankly don't see any particular reason to try to bond the bearers within the kernel. That would just bring more complexity to the kernel drivers without providing any real benefit. The Linux networking stack will handle separate interfaces just fine. The IPv4 default route can point to one interface and IPv6 routes can point to another and everything will just work.

Naturally connman will need to understand about the separate interfaces in order to configure them properly but that is a minor pain compared to doing bonding separately in each modem interface driver within the kernel.

Br,

	MikaL

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

* RE: [RFC 1/5] gprs: Update documentation for IPv6
  2011-01-28 14:00     ` Mika.Liljeberg
@ 2011-01-28 14:17       ` Marcel Holtmann
  2011-01-28 14:43         ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
  2011-01-28 14:55         ` Mika.Liljeberg
  0 siblings, 2 replies; 14+ messages in thread
From: Marcel Holtmann @ 2011-01-28 14:17 UTC (permalink / raw)
  To: ofono

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

Hi Mika,

> > > +   For combined IPv4v6 context (3GPP rel 8) the
> > > +   same network interface may be used for both
> > > +   IPv4 and IPv6. IPv4 and IPv6 may also be
> > > +   offered via separate network interfaces.
> > > +
> > 
> > I think it would be nice if we could keep only one interface here.
> > It's a bit messy that the difference between R7 and R8
> > networks will be visible to the users like this.
> 
> By users I assume you mean connman?
> 
> > So when in a R7 network the uplink traffic should be filtered into the
> > right ipv4 and ipv6 pdp-connection automagically.
> > I know STE will support this in the modem firmware.
> 
> It's cool that STE firmware can do that. However, for modems that don't (most of them), I frankly don't see any particular reason to try to bond the bearers within the kernel. That would just bring more complexity to the kernel drivers without providing any real benefit. The Linux networking stack will handle separate interfaces just fine. The IPv4 default route can point to one interface and IPv6 routes can point to another and everything will just work.
> 
> Naturally connman will need to understand about the separate interfaces in order to configure them properly but that is a minor pain compared to doing bonding separately in each modem interface driver within the kernel.

I am not sure it is a good idea to make ConnMan do that. For IFX, I was
actually considering just piping the two RawIP streams into one network
interface. That seems easy enough.

And to be honest for PPP, just doing IPv4 seems acceptable since PPP is
bad idea in the first place. It is a limitation I am willing to accept.

My concern is also on how we handle the Tethering cases properly. I have
not yet spent enough time to think about it, but I have concerns here.

So right now I would prefer to sit ipv6 out until we have proper ipv4v6
context support in the network and the modems.

Regards

Marcel



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

* Re: [RFC 1/5] gprs: Update documentation for IPv6
  2011-01-28 12:49   ` Sjur =?unknown-8bit?q?Br=C3=A6ndeland?=
  2011-01-28 14:00     ` Mika.Liljeberg
@ 2011-01-28 14:41     ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
  1 sibling, 0 replies; 14+ messages in thread
From: =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont @ 2011-01-28 14:41 UTC (permalink / raw)
  To: ofono

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

On Friday 28 January 2011 14:49:16 ext Sjur Brændeland, you wrote:
> I think it would be nice if we could keep only one interface here.
> It's a bit messy that the difference between R7 and R8
> networks will be visible to the users like this.
> 
> So when in a R7 network the uplink traffic should be filtered into the
> right ipv4 and ipv6 pdp-connection automagically.
> I know STE will support this in the modem firmware.
> 
> If firmware doesn't support this perhaps this could also be handled
> in the kernel drivers. This should be doable for phonet (and Caif),

Not really no. The API to create a Phonet gprs interface is tightly coupled 
with the underlying pipe. There are no easy ways to patch the driver to use 
two pipes, nor the corresponding userspace code.

It would actually be much easier to write a bonding driver to rule both IPv4 
and IPv6 instances of the existing driver. It would also be more generic, not 
Phonet/CAIF/PPP-specific, although it would probably not work for fake Ethernet 
devices.

However it is questionable why we would optimize this when the only customer 
is ConnMan, and the only use case is 3GPP Rel7. Applications don't need to 
care whether IPv4 and IPv6 are through a single or two separate interfaces. 
They just use the socket API.

-- 
Rémi Denis-Courmont
Nokia Devices R&D, Maemo Software, Helsinki

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

* Re: [RFC 1/5] gprs: Update documentation for IPv6
  2011-01-28 14:17       ` Marcel Holtmann
@ 2011-01-28 14:43         ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
  2011-01-28 14:55         ` Mika.Liljeberg
  1 sibling, 0 replies; 14+ messages in thread
From: =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont @ 2011-01-28 14:43 UTC (permalink / raw)
  To: ofono

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

On Friday 28 January 2011 16:17:04 ext Marcel Holtmann, you wrote:
> I am not sure it is a good idea to make ConnMan do that. For IFX, I was
> actually considering just piping the two RawIP streams into one network
> interface. That seems easy enough.
> 
> And to be honest for PPP, just doing IPv4 seems acceptable since PPP is
> bad idea in the first place. It is a limitation I am willing to accept.
> 
> My concern is also on how we handle the Tethering cases properly. I have
> not yet spent enough time to think about it, but I have concerns here.
> 
> So right now I would prefer to sit ipv6 out until we have proper ipv4v6
> context support in the network and the modems.

I would want to do that too. But my current guesstimate is that we will have 
to support dual-stack before we can assume dual-stack support in both the 
networks and the modems.

This limitation might be acceptable for tethering though, which is the main 
customer for PPP.

-- 
Rémi Denis-Courmont
Nokia Devices R&D, Maemo Software, Helsinki

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

* RE: [RFC 1/5] gprs: Update documentation for IPv6
  2011-01-28 14:17       ` Marcel Holtmann
  2011-01-28 14:43         ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
@ 2011-01-28 14:55         ` Mika.Liljeberg
  2011-01-28 15:04           ` Marcel Holtmann
  1 sibling, 1 reply; 14+ messages in thread
From: Mika.Liljeberg @ 2011-01-28 14:55 UTC (permalink / raw)
  To: ofono

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

Hi Marcel, 

> I am not sure it is a good idea to make ConnMan do that.

Why is that?

> And to be honest for PPP, just doing IPv4 seems acceptable 
> since PPP is
> bad idea in the first place. It is a limitation I am willing 
> to accept.

Yeah, PPP is not really a requirement for us, although it would be convenient to have it for testing. As a matter of fact, I would already have trialed atmodem support for IPv6 but that was blocked because of the lack of IPV6CP support in oFono PPP implementation. Too bad.

> My concern is also on how we handle the Tethering cases 
> properly. I have
> not yet spent enough time to think about it, but I have concerns here.

Ok. Can you outline your concerns so we can talk about them?

> So right now I would prefer to sit ipv6 out until we have 
> proper ipv4v6
> context support in the network and the modems.

I'd like to progress with this. We also have people who are keen to help out on the connman side. Just sitting and waiting for better times is not really an approach I'd prefer to take.

Currently, we only discussing whether the "Interface" setting is needed separately in IPv4 and IPv6 settings or not. That's a minor detail as far as I am concerned. For now, allowing separate network interfaces for IPv4 and IPv6 is convenient for testing the IPv6 support on current modems. If it turns out to be hugely difficult to manage separate interface on connman side, we can always restrict the approach and drop support for older modems when rel8 modems are available. 

Br,

	MikaL

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

* RE: [RFC 1/5] gprs: Update documentation for IPv6
  2011-01-28 14:55         ` Mika.Liljeberg
@ 2011-01-28 15:04           ` Marcel Holtmann
  2011-01-28 15:37             ` Mika.Liljeberg
  0 siblings, 1 reply; 14+ messages in thread
From: Marcel Holtmann @ 2011-01-28 15:04 UTC (permalink / raw)
  To: ofono

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

Hi Mika,

> > I am not sure it is a good idea to make ConnMan do that.
> 
> Why is that?

we need to chat with Samuel about this. I foresee a bunch of issues
trying to handle two context properly. This needs a bit more deeper
thinking on how things are done.

> > And to be honest for PPP, just doing IPv4 seems acceptable 
> > since PPP is
> > bad idea in the first place. It is a limitation I am willing 
> > to accept.
> 
> Yeah, PPP is not really a requirement for us, although it would be convenient to have it for testing. As a matter of fact, I would already have trialed atmodem support for IPv6 but that was blocked because of the lack of IPV6CP support in oFono PPP implementation. Too bad.

We have a TODO item open for that. So far nobody really bothered,
because either the hardware did not support it or the network did not.

But hey, patches are welcome ;)

> > My concern is also on how we handle the Tethering cases 
> > properly. I have
> > not yet spent enough time to think about it, but I have concerns here.
> 
> Ok. Can you outline your concerns so we can talk about them?

We are currently Tethering to one specific service with the assumption
that it maps to one interface of the kernel. If that assumption is not
true anymore, then we have to re-think this. Not sure if we should be
bothered.

But then again, on the other hand for IPv6 Tethering, don't wanna use
NAT anyway. So that might be not an issue after all. This really needs
some more thinking. I have no clear answers at the moment.

> > So right now I would prefer to sit ipv6 out until we have 
> > proper ipv4v6
> > context support in the network and the modems.
> 
> I'd like to progress with this. We also have people who are keen to help out on the connman side. Just sitting and waiting for better times is not really an approach I'd prefer to take.
> 
> Currently, we only discussing whether the "Interface" setting is needed separately in IPv4 and IPv6 settings or not. That's a minor detail as far as I am concerned. For now, allowing separate network interfaces for IPv4 and IPv6 is convenient for testing the IPv6 support on current modems. If it turns out to be hugely difficult to manage separate interface on connman side, we can always restrict the approach and drop support for older modems when rel8 modems are available. 

So I like the ST-Ericsson approach where this details is abstracted in
the modem firmware.

Regards

Marcel



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

* RE: [RFC 1/5] gprs: Update documentation for IPv6
  2011-01-28 15:04           ` Marcel Holtmann
@ 2011-01-28 15:37             ` Mika.Liljeberg
  0 siblings, 0 replies; 14+ messages in thread
From: Mika.Liljeberg @ 2011-01-28 15:37 UTC (permalink / raw)
  To: ofono

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

Hi Marcel, 

> Hi Mika,
> 
> > > I am not sure it is a good idea to make ConnMan do that.
> > 
> > Why is that?
> 
> we need to chat with Samuel about this. I foresee a bunch of issues
> trying to handle two context properly. This needs a bit more deeper
> thinking on how things are done.

Ok. But again, can't really comment unless you guys come out with the actual issues.

> > fact, I would already have trialed atmodem support for IPv6 
> > but that was blocked because of the lack of IPV6CP support in 
> > oFono PPP implementation. Too bad.
> 
> We have a TODO item open for that. So far nobody really bothered,
> because either the hardware did not support it or the network did not.
> 
> But hey, patches are welcome ;)

I'm more interested in the core support at the moment. 

> > > My concern is also on how we handle the Tethering cases 
> > > properly. I have
> > > not yet spent enough time to think about it, but I have 
> concerns here.
> > 
> > Ok. Can you outline your concerns so we can talk about them?
> 
> We are currently Tethering to one specific service with the assumption
> that it maps to one interface of the kernel. If that assumption is not
> true anymore, then we have to re-think this. Not sure if we should be
> bothered.

IPv4 and IPv6 are completely orthogonal, so I don't really see the problem you're alluding to here.

> I have no clear answers at the moment.

I believe the main question really is "How to do tethering with IPv6?". Clearly it needs to be thought out but I don't see why that work should block implementation of basic IPv6 access. You can start with IPv4 only tethering and just ignore IPv6 in the beginning.

> > > So right now I would prefer to sit ipv6 out until we have 
> > > proper ipv4v6
> > > context support in the network and the modems.
> > 
> > I'd like to progress with this. We also have people who are 
> keen to help out on the connman side. Just sitting and 
> waiting for better times is not really an approach I'd prefer to take.
> > 
> > Currently, we only discussing whether the "Interface" 
> setting is needed separately in IPv4 and IPv6 settings or 
> not. That's a minor detail as far as I am concerned. For now, 
> allowing separate network interfaces for IPv4 and IPv6 is 
> convenient for testing the IPv6 support on current modems. If 
> it turns out to be hugely difficult to manage separate 
> interface on connman side, we can always restrict the 
> approach and drop support for older modems when rel8 modems 
> are available. 
> 
> So I like the ST-Ericsson approach where this details is abstracted in
> the modem firmware.

That's not an answer though, unless we only plan to support STE hardware in oFono.

Br,

	MikaL

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

end of thread, other threads:[~2011-01-28 15:37 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-26 16:22 RFC: IPv6 support Mika Liljeberg
2011-01-26 16:22 ` [RFC 1/5] gprs: Update documentation for IPv6 Mika Liljeberg
2011-01-28 12:49   ` Sjur =?unknown-8bit?q?Br=C3=A6ndeland?=
2011-01-28 14:00     ` Mika.Liljeberg
2011-01-28 14:17       ` Marcel Holtmann
2011-01-28 14:43         ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
2011-01-28 14:55         ` Mika.Liljeberg
2011-01-28 15:04           ` Marcel Holtmann
2011-01-28 15:37             ` Mika.Liljeberg
2011-01-28 14:41     ` =?unknown-8bit?q?R=C3=A9mi?= Denis-Courmont
2011-01-26 16:22 ` [RFC 2/5] gprs: driver interface changes " Mika Liljeberg
2011-01-26 16:22 ` [RFC 3/5] gprs: core support " Mika Liljeberg
2011-01-26 16:22 ` [RFC 4/5] test: modify test scripts " Mika Liljeberg
2011-01-26 16:22 ` [RFC 5/5] isimodem: IPv6 support Mika Liljeberg

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.