* [RFC PATCH 00/20] *** LTE support with CSFB voice solution ***
@ 2011-04-11 10:19 Vijay Nayani
2011-04-11 10:19 ` [RFC PATCH 01/20] include: add generalised packet headers Vijay Nayani
` (19 more replies)
0 siblings, 20 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:19 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 4022 bytes --]
***
Subject: This patch enables LTE support to oFono with CSFB as voice solution.
Design considerations
1. Single packet atom to deal with multiple packet domains.
2. Can be considered as combination of gprs and eps functionality with just needed segregation depending on the access technology camped.
Aware of debate flared up in community on merits and demerits of individual atoms or combined approach for dealing with EPS & GPRS.
After couple of turn arounds and prototype implementations, single packet atom made better sense compared against segregated eps and gprs atoms. Reasons below briefly on advantages of single atom approach:
1. Better architecture , in terms of living with a single packet domain atom catering for all the available bearer(s).
2. Enables us to have a single packet interfaces.Exact bearer is more of context property.
3. Would bring no change in DBus interfaces.
3. Architecture fits the accommodating the IP continuity during CSFB.
We have tested the patch against phonesim (modified for EPS).
Basic use cases that has been considered and tested are below.
1. Setting the modem to online.
2. CSFB for voice call.
3. Recamp the modem into EPS once voice call terminates.
Todo List / Grey areas
1. We haven't addressed any IMS related issues here.
2. Not sure if USSD/voice call atoms apply for PS_ONLY Mode1/PS_ONLY Mode2.
3. Dedicated contexts haven't been addressed.
Note: This design & development has been done from our current understanding of the 3gpp specs and tested against modified version of phonesim accordingly.
I assume this would stand good in terms of giving us good base from where further development of LTE related things can be taken forward.
Modified phonesim would be sent as different patch.
Special thanks to Arun Ravindran, Jeevaka Badrappan, Rajesh Nagaiah for extending their support all along the activity.
***
Vijay Nayani (20):
include: add generalised packet headers
build: add generalised packet headers
gprs: move bearer_to_string to common file
build: add generalised packet files
atmodem: add generalised packet source
phonesim: use generalised packet source files
common: add preferred_ue_mode enum
include: add set preferred ue mode api
modem: add preferred ue mode handling
doc: add PreferredMode property to modem
modem: generalise feature map table
packet: add context type default
include: add get technology api
packet: add get technology api implementation
include: add default context param and api
packet: add default context implementation
atmodem: add lte specific functions
phonesim: Add cemode query implementation
phonesim: atoms creation based on UE mode
modem: Add netreg watch for tech switch
Makefile.am | 9 +-
doc/modem-api.txt | 18 +
drivers/atmodem/atmodem.c | 4 +
drivers/atmodem/atmodem.h | 6 +
drivers/atmodem/packet-context.c | 329 ++++
drivers/atmodem/packet-service.c | 662 +++++++++
include/modem.h | 2 +
include/packet-context.h | 127 ++
include/packet-service.h | 111 ++
include/ps-provision.h | 59 +
plugins/phonesim.c | 188 ++-
src/common.c | 23 +
src/common.h | 20 +
src/gprs.c | 35 -
src/modem.c | 143 ++-
src/ofono.h | 14 +
src/packet.c | 3054 ++++++++++++++++++++++++++++++++++++++
src/ps-provision.c | 101 ++
18 files changed, 4789 insertions(+), 116 deletions(-)
create mode 100644 drivers/atmodem/packet-context.c
create mode 100644 drivers/atmodem/packet-service.c
create mode 100644 include/packet-context.h
create mode 100644 include/packet-service.h
create mode 100644 include/ps-provision.h
create mode 100644 src/packet.c
create mode 100644 src/ps-provision.c
^ permalink raw reply [flat|nested] 41+ messages in thread
* [RFC PATCH 01/20] include: add generalised packet headers
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
@ 2011-04-11 10:19 ` Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 02/20] build: " Vijay Nayani
` (18 subsequent siblings)
19 siblings, 0 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:19 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 10595 bytes --]
Files are just a copy-paste of the gprs, gprs-context
and gprs-provision.h. Just the names has been made
more generic.
---
include/packet-context.h | 126 ++++++++++++++++++++++++++++++++++++++++++++++
include/packet-service.h | 95 ++++++++++++++++++++++++++++++++++
include/ps-provision.h | 59 +++++++++++++++++++++
3 files changed, 280 insertions(+), 0 deletions(-)
create mode 100644 include/packet-context.h
create mode 100644 include/packet-service.h
create mode 100644 include/ps-provision.h
diff --git a/include/packet-context.h b/include/packet-context.h
new file mode 100644
index 0000000..44fd69f
--- /dev/null
+++ b/include/packet-context.h
@@ -0,0 +1,126 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ * Copyright 2011 EB(Elektrobit).
+ *
+ * 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_PACKET_CONTEXT_H
+#define __OFONO_PACKET_CONTEXT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ofono/types.h>
+
+struct ofono_packet_context;
+
+#define OFONO_PS_MAX_APN_LENGTH 127
+#define OFONO_PS_MAX_USERNAME_LENGTH 63
+#define OFONO_PS_MAX_PASSWORD_LENGTH 255
+
+enum ofono_packet_proto {
+ OFONO_PACKET_PROTO_IP = 0,
+ OFONO_PACKET_PROTO_IPV6,
+ OFONO_PACKET_PROTO_IPV4V6,
+};
+
+enum ofono_packet_context_type {
+ OFONO_PACKET_CONTEXT_TYPE_ANY = 0,
+ OFONO_PACKET_CONTEXT_TYPE_INTERNET,
+ OFONO_PACKET_CONTEXT_TYPE_MMS,
+ OFONO_PACKET_CONTEXT_TYPE_WAP,
+ OFONO_PACKET_CONTEXT_TYPE_IMS,
+};
+
+struct ofono_packet_context_param {
+ unsigned int cid;
+ int direction;
+ char apn[OFONO_PS_MAX_APN_LENGTH + 1];
+ char username[OFONO_PS_MAX_USERNAME_LENGTH + 1];
+ char password[OFONO_PS_MAX_PASSWORD_LENGTH + 1];
+ enum ofono_packet_proto proto;
+};
+
+typedef void (*ofono_packet_context_cb_t)(const struct ofono_error *error,
+ void *data);
+
+struct ofono_packet_context_driver {
+ const char *name;
+ int (*probe)(struct ofono_packet_context *pc, unsigned int vendor,
+ void *data);
+ void (*remove)(struct ofono_packet_context *pc);
+ void (*activate_context)(struct ofono_packet_context *gc,
+ const struct ofono_packet_context_param *ctx,
+ ofono_packet_context_cb_t cb, void *data);
+ void (*deactivate_context)(struct ofono_packet_context *pc,
+ unsigned int id,
+ ofono_packet_context_cb_t cb,
+ void *data);
+};
+
+void ofono_packet_context_deactivated(struct ofono_packet_context *pc,
+ unsigned int id);
+
+int ofono_packet_context_driver_register(
+ const struct ofono_packet_context_driver *d);
+void ofono_packet_context_driver_unregister(
+ const struct ofono_packet_context_driver *d);
+
+struct ofono_packet_context *ofono_packet_context_create(
+ struct ofono_modem *modem,
+ unsigned int vendor,
+ const char *driver, void *data);
+void ofono_packet_context_remove(struct ofono_packet_context *pc);
+
+void ofono_packet_context_set_data(struct ofono_packet_context *pc, void *data);
+void *ofono_packet_context_get_data(struct ofono_packet_context *pc);
+
+struct ofono_modem *ofono_packet_context_get_modem(
+ struct ofono_packet_context *pc);
+
+void ofono_packet_context_set_type(struct ofono_packet_context *pc,
+ enum ofono_packet_context_type type);
+
+void ofono_packet_context_set_interface(struct ofono_packet_context *pc,
+ const char *interface);
+
+void ofono_packet_context_set_ipv4_address(struct ofono_packet_context *pc,
+ const char *address,
+ gboolean static_ip);
+void ofono_packet_context_set_ipv4_netmask(struct ofono_packet_context *pc,
+ const char *netmask);
+void ofono_packet_context_set_ipv4_gateway(struct ofono_packet_context *pc,
+ const char *gateway);
+void ofono_packet_context_set_ipv4_dns_servers(struct ofono_packet_context *pc,
+ const char **dns);
+
+void ofono_packet_context_set_ipv6_address(struct ofono_packet_context *pc,
+ const char *address);
+void ofono_packet_context_set_ipv6_prefix_length(struct ofono_packet_context *gc,
+ unsigned char length);
+void ofono_packet_context_set_ipv6_gateway(struct ofono_packet_context *pc,
+ const char *gateway);
+void ofono_packet_context_set_ipv6_dns_servers(struct ofono_packet_context *pc,
+ const char **dns);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OFONO_PACKET_CONTEXT_H */
diff --git a/include/packet-service.h b/include/packet-service.h
new file mode 100644
index 0000000..bc5eceb
--- /dev/null
+++ b/include/packet-service.h
@@ -0,0 +1,95 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ * Copyright 2011 EB(Elektrobit).
+ *
+ * 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_PACKET_SERVICE_H
+#define __OFONO_PACKET_SERVICE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ofono/types.h>
+
+struct ofono_packet_service;
+struct ofono_packet_context;
+
+typedef void (*ofono_packet_service_status_cb_t)(
+ const struct ofono_error *error,
+ int status, void *data);
+
+typedef void (*ofono_packet_service_cb_t)(const struct ofono_error *error,
+ void *data);
+
+struct ofono_packet_service_driver {
+ const char *name;
+ int (*probe)(struct ofono_packet_service *ps, unsigned int vendor,
+ void *data);
+ void (*remove)(struct ofono_packet_service *ps);
+ void (*set_attached)(struct ofono_packet_service *ps, int attached,
+ ofono_packet_service_cb_t cb, void *data);
+ void (*attached_status)(struct ofono_packet_service *ps,
+ ofono_packet_service_status_cb_t cb,
+ void *data);
+};
+
+enum packet_service_suspend_cause {
+ PACKET_SERVICE_SUSPENDED_DETACHED,
+ PACKET_SERVICE_SUSPENDED_SIGNALLING,
+ PACKET_SERVICE_SUSPENDED_CALL,
+ PACKET_SERVICE_SUSPENDED_NO_COVERAGE,
+ PACKET_SERVICE_SUSPENDED_UNKNOWN_CAUSE,
+};
+
+void ofono_packet_service_status_notify(struct ofono_packet_service *ps,
+ int status);
+void ofono_packet_service_detached_notify(struct ofono_packet_service *ps);
+void ofono_packet_service_suspend_notify(struct ofono_packet_service *ps,
+ int cause);
+void ofono_packet_service_resume_notify(struct ofono_packet_service *ps);
+void ofono_packet_service_bearer_notify(struct ofono_packet_service *ps,
+ int bearer);
+
+int ofono_packet_service_driver_register(
+ const struct ofono_packet_service_driver *d);
+void ofono_packet_service_driver_unregister(
+ const struct ofono_packet_service_driver *d);
+
+struct ofono_packet_service *ofono_packet_service_create(
+ struct ofono_modem *modem,
+ unsigned int vendor, const char *driver,
+ void *data);
+void ofono_packet_service_register(struct ofono_packet_service *ps);
+void ofono_packet_service_remove(struct ofono_packet_service *ps);
+
+void ofono_packet_service_set_data(struct ofono_packet_service *ps, void *data);
+void *ofono_packet_service_get_data(struct ofono_packet_service *ps);
+
+void ofono_packet_service_set_cid_range(struct ofono_packet_service *ps,
+ unsigned int min, unsigned int max);
+void ofono_packet_service_add_context(struct ofono_packet_service *ps,
+ struct ofono_packet_context *pc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OFONO_PACKET_SERVICE_H */
diff --git a/include/ps-provision.h b/include/ps-provision.h
new file mode 100644
index 0000000..2570712
--- /dev/null
+++ b/include/ps-provision.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * oFono - Open Telephony stack for Linux
+ *
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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_PS_PROVISION_H
+#define __OFONO_PS_PROVISION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "packet-context.h"
+
+struct ofono_ps_provision_data {
+ enum ofono_packet_context_type type;
+ enum ofono_packet_proto proto;
+ char *name;
+ char *apn;
+ char *username;
+ char *password;
+ char *message_proxy;
+ char *message_center;
+};
+
+struct ofono_ps_provision_driver {
+ const char *name;
+ int priority;
+ int (*get_settings)(const char *mcc, const char *mnc, const char *spn,
+ struct ofono_ps_provision_data **settings,
+ int *count);
+};
+
+int ofono_ps_provision_driver_register(
+ const struct ofono_ps_provision_driver *driver);
+void ofono_ps_provision_driver_unregister(
+ const struct ofono_ps_provision_driver *driver);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OFONO_PS_PROVISION_H */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 02/20] build: add generalised packet headers
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
2011-04-11 10:19 ` [RFC PATCH 01/20] include: add generalised packet headers Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 03/20] gprs: move bearer_to_string to common file Vijay Nayani
` (17 subsequent siblings)
19 siblings, 0 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 937 bytes --]
---
Makefile.am | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 2886b5d..ac65d4d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -10,13 +10,14 @@ pkginclude_HEADERS = include/log.h include/plugin.h include/history.h \
include/netreg.h include/voicecall.h include/devinfo.h \
include/cbs.h include/call-volume.h \
include/gprs.h include/gprs-context.h \
+ include/packet-service.h include/packet-context.h \
include/radio-settings.h include/stk.h \
include/audio-settings.h include/nettime.h \
include/ctm.h include/cdma-voicecall.h \
include/cdma-sms.h include/sim-auth.h \
include/gprs-provision.h include/emulator.h \
include/location-reporting.h \
- include/cdma-connman.h \
+ include/cdma-connman.h include/ps-provision.h \
include/gnss.h
nodist_pkginclude_HEADERS = include/version.h
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 03/20] gprs: move bearer_to_string to common file
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
2011-04-11 10:19 ` [RFC PATCH 01/20] include: add generalised packet headers Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 02/20] build: " Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 04/20] build: add generalised packet files Vijay Nayani
` (16 subsequent siblings)
19 siblings, 0 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 3027 bytes --]
Inorder for gprs/context and packet service/context
to coexist packet_bearer_to_string is moved to
common source file.
---
src/common.c | 23 +++++++++++++++++++++++
src/common.h | 12 ++++++++++++
src/gprs.c | 35 -----------------------------------
3 files changed, 35 insertions(+), 35 deletions(-)
diff --git a/src/common.c b/src/common.c
index e65a677..45866c0 100644
--- a/src/common.c
+++ b/src/common.c
@@ -696,6 +696,29 @@ const char *registration_tech_to_string(int tech)
}
}
+const char *packet_bearer_to_string(int bearer)
+{
+ switch (bearer) {
+ case PACKET_BEARER_NONE:
+ return "none";
+ case PACKET_BEARER_GPRS:
+ return "gprs";
+ case PACKET_BEARER_EGPRS:
+ return "edge";
+ case PACKET_BEARER_UMTS:
+ return "umts";
+ case PACKET_BEARER_HSUPA:
+ return "hsupa";
+ case PACKET_BEARER_HSDPA:
+ return "hsdpa";
+ case PACKET_BEARER_HSUPA_HSDPA:
+ return "hspa";
+ case PACKET_BEARER_EPS:
+ return "lte";
+ }
+ return "";
+}
+
gboolean is_valid_apn(const char *apn)
{
int i;
diff --git a/src/common.h b/src/common.h
index 6dc7bff..5fc3ead 100644
--- a/src/common.h
+++ b/src/common.h
@@ -128,6 +128,18 @@ enum context_status {
CONTEXT_STATUS_ACTIVATED = 1,
};
+/* 27.007 Section 7.29 */
+enum packet_bearer {
+ PACKET_BEARER_NONE = 0,
+ PACKET_BEARER_GPRS = 1,
+ PACKET_BEARER_EGPRS = 2,
+ PACKET_BEARER_UMTS = 3,
+ PACKET_BEARER_HSUPA = 4,
+ PACKET_BEARER_HSDPA = 5,
+ PACKET_BEARER_HSUPA_HSDPA = 6,
+ PACKET_BEARER_EPS = 7,
+};
+
const char *telephony_error_to_str(const struct ofono_error *error);
gboolean valid_number_format(const char *number, int length);
diff --git a/src/gprs.c b/src/gprs.c
index deffeb8..59a5a70 100644
--- a/src/gprs.c
+++ b/src/gprs.c
@@ -60,18 +60,6 @@
static GSList *g_drivers = NULL;
static GSList *g_context_drivers = NULL;
-/* 27.007 Section 7.29 */
-enum packet_bearer {
- PACKET_BEARER_NONE = 0,
- PACKET_BEARER_GPRS = 1,
- PACKET_BEARER_EGPRS = 2,
- PACKET_BEARER_UMTS = 3,
- PACKET_BEARER_HSUPA = 4,
- PACKET_BEARER_HSDPA = 5,
- PACKET_BEARER_HSUPA_HSDPA = 6,
- PACKET_BEARER_EPS = 7,
-};
-
struct ofono_gprs {
GSList *contexts;
ofono_bool_t attached;
@@ -152,29 +140,6 @@ struct pri_context {
static void gprs_netreg_update(struct ofono_gprs *gprs);
static void gprs_deactivate_next(struct ofono_gprs *gprs);
-const char *packet_bearer_to_string(int bearer)
-{
- switch (bearer) {
- case PACKET_BEARER_NONE:
- return "none";
- case PACKET_BEARER_GPRS:
- return "gprs";
- case PACKET_BEARER_EGPRS:
- return "edge";
- case PACKET_BEARER_UMTS:
- return "umts";
- case PACKET_BEARER_HSUPA:
- return "hsupa";
- case PACKET_BEARER_HSDPA:
- return "hsdpa";
- case PACKET_BEARER_HSUPA_HSDPA:
- return "hspa";
- case PACKET_BEARER_EPS:
- return "lte";
- }
- return "";
-}
-
static const char *gprs_context_default_name(enum ofono_gprs_context_type type)
{
switch (type) {
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 04/20] build: add generalised packet files
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (2 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 03/20] gprs: move bearer_to_string to common file Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 05/20] atmodem: add generalised packet source Vijay Nayani
` (15 subsequent siblings)
19 siblings, 0 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 82600 bytes --]
packet.c and ps-provision.c are just the copy-paste
of gprs.c and gprs-provision.c files with generic
naming convention.
---
Makefile.am | 4 +-
src/ofono.h | 14 +
src/packet.c | 2939 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/ps-provision.c | 101 ++
4 files changed, 3056 insertions(+), 2 deletions(-)
create mode 100644 src/packet.c
create mode 100644 src/ps-provision.c
diff --git a/Makefile.am b/Makefile.am
index ac65d4d..c1cc701 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -379,7 +379,7 @@ src_ofonod_SOURCES = $(gdbus_sources) $(builtin_sources) src/ofono.ver \
src/phonebook.c src/history.c src/message-waiting.c \
src/simutil.h src/simutil.c src/storage.h \
src/storage.c src/cbs.c src/watch.c src/call-volume.c \
- src/gprs.c src/idmap.h src/idmap.c \
+ src/gprs.c src/idmap.h src/idmap.c src/packet.c \
src/radio-settings.c src/stkutil.h src/stkutil.c \
src/nettime.c src/stkagent.c src/stkagent.h \
src/simfs.c src/simfs.h src/audio-settings.c \
@@ -388,7 +388,7 @@ src_ofonod_SOURCES = $(gdbus_sources) $(builtin_sources) src/ofono.ver \
src/message.h src/message.c src/gprs-provision.c \
src/emulator.c src/location-reporting.c \
src/cdma-connman.c src/gnss.c \
- src/gnssagent.c src/gnssagent.h
+ src/gnssagent.c src/gnssagent.h src/ps-provision.c
src_ofonod_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@ -ldl
diff --git a/src/ofono.h b/src/ofono.h
index 156bc40..206c593 100644
--- a/src/ofono.h
+++ b/src/ofono.h
@@ -122,6 +122,8 @@ enum ofono_atom_type {
OFONO_ATOM_TYPES_CALL_VOLUME,
OFONO_ATOM_TYPE_GPRS,
OFONO_ATOM_TYPE_GPRS_CONTEXT,
+ OFONO_ATOM_TYPE_PACKET_SERVICE,
+ OFONO_ATOM_TYPE_PACKET_CONTEXT,
OFONO_ATOM_TYPE_RADIO_SETTINGS,
OFONO_ATOM_TYPE_AUDIO_SETTINGS,
OFONO_ATOM_TYPE_STK,
@@ -239,6 +241,8 @@ gboolean __ofono_call_settings_is_busy(struct ofono_call_settings *cs);
#include <ofono/phonebook.h>
#include <ofono/gprs.h>
#include <ofono/gprs-context.h>
+#include <ofono/packet-service.h>
+#include <ofono/packet-context.h>
#include <ofono/radio-settings.h>
#include <ofono/audio-settings.h>
#include <ofono/ctm.h>
@@ -463,5 +467,15 @@ void __ofono_gprs_provision_free_settings(
struct ofono_gprs_provision_data *settings,
int count);
+#include <ofono/ps-provision.h>
+
+ofono_bool_t __ofono_ps_provision_get_settings(const char *mcc,
+ const char *mnc, const char *spn,
+ struct ofono_ps_provision_data **settings,
+ int *count);
+void __ofono_ps_provision_free_settings(
+ struct ofono_ps_provision_data *settings,
+ int count);
+
#include <ofono/emulator.h>
#include <ofono/gnss.h>
diff --git a/src/packet.c b/src/packet.c
new file mode 100644
index 0000000..1acbf76
--- /dev/null
+++ b/src/packet.c
@@ -0,0 +1,2939 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ *
+ * 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "ofono.h"
+
+#include "common.h"
+#include "storage.h"
+#include "idmap.h"
+#include "simutil.h"
+#include "util.h"
+
+#define PS_FLAG_ATTACHING 0x1
+#define PS_FLAG_RECHECK 0x2
+
+#define SETTINGS_STORE "ps"
+#define SETTINGS_GROUP "Settings"
+#define MAX_CONTEXT_NAME_LENGTH 127
+#define MAX_MESSAGE_PROXY_LENGTH 255
+#define MAX_MESSAGE_CENTER_LENGTH 255
+#define MAX_CONTEXTS 256
+#define SUSPEND_TIMEOUT 8
+
+static GSList *g_drivers = NULL;
+static GSList *g_context_drivers = NULL;
+
+struct ofono_packet_service {
+ GSList *contexts;
+ ofono_bool_t attached;
+ ofono_bool_t driver_attached;
+ ofono_bool_t roaming_allowed;
+ ofono_bool_t powered;
+ ofono_bool_t suspended;
+ int status;
+ int flags;
+ int bearer;
+ guint suspend_timeout;
+ struct idmap *pid_map;
+ unsigned int last_context_id;
+ struct idmap *cid_map;
+ int netreg_status;
+ struct ofono_netreg *netreg;
+ unsigned int netreg_watch;
+ unsigned int status_watch;
+ GKeyFile *settings;
+ char *imsi;
+ DBusMessage *pending;
+ GSList *context_drivers;
+ const struct ofono_packet_service_driver *driver;
+ void *driver_data;
+ struct ofono_atom *atom;
+ struct ofono_sim_context *sim_context;
+};
+
+struct ipv4_settings {
+ gboolean static_ip;
+ char *ip;
+ char *netmask;
+ char *gateway;
+ char **dns;
+ char *proxy;
+};
+
+struct ipv6_settings {
+ char *ip;
+ unsigned char prefix_len;
+ char *gateway;
+ char **dns;
+};
+
+struct context_settings {
+ char *interface;
+ struct ipv4_settings *ipv4;
+ struct ipv6_settings *ipv6;
+};
+
+struct ofono_packet_context {
+ struct ofono_packet_service *ps;
+ enum ofono_packet_context_type type;
+ ofono_bool_t inuse;
+ const struct ofono_packet_context_driver *driver;
+ void *driver_data;
+ struct context_settings *settings;
+ struct ofono_atom *atom;
+};
+
+struct context {
+ ofono_bool_t active;
+ enum ofono_packet_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];
+ unsigned int id;
+ char *path;
+ char *key;
+ char *proxy_host;
+ uint16_t proxy_port;
+ DBusMessage *pending;
+ struct ofono_packet_context_param context;
+ struct ofono_packet_context *context_driver;
+ struct ofono_packet_service *ps;
+};
+
+static void ps_netreg_update(struct ofono_packet_service *ps);
+static void ps_deactivate_next(struct ofono_packet_service *ps);
+
+static const char *packet_context_default_name(enum ofono_packet_context_type type)
+{
+ switch (type) {
+ case OFONO_PACKET_CONTEXT_TYPE_ANY:
+ return NULL;
+ case OFONO_PACKET_CONTEXT_TYPE_INTERNET:
+ return "Internet";
+ case OFONO_PACKET_CONTEXT_TYPE_MMS:
+ return "MMS";
+ case OFONO_PACKET_CONTEXT_TYPE_WAP:
+ return "WAP";
+ case OFONO_PACKET_CONTEXT_TYPE_IMS:
+ return "IMS";
+ }
+
+ return NULL;
+}
+
+static const char *packet_context_type_to_string(
+ enum ofono_packet_context_type type)
+{
+ switch (type) {
+ case OFONO_PACKET_CONTEXT_TYPE_ANY:
+ return NULL;
+ case OFONO_PACKET_CONTEXT_TYPE_INTERNET:
+ return "internet";
+ case OFONO_PACKET_CONTEXT_TYPE_MMS:
+ return "mms";
+ case OFONO_PACKET_CONTEXT_TYPE_WAP:
+ return "wap";
+ case OFONO_PACKET_CONTEXT_TYPE_IMS:
+ return "ims";
+ }
+
+ return NULL;
+}
+
+static gboolean packet_context_string_to_type(const char *str,
+ enum ofono_packet_context_type *out)
+{
+ if (g_str_equal(str, "internet")) {
+ *out = OFONO_PACKET_CONTEXT_TYPE_INTERNET;
+ return TRUE;
+ } else if (g_str_equal(str, "wap")) {
+ *out = OFONO_PACKET_CONTEXT_TYPE_WAP;
+ return TRUE;
+ } else if (g_str_equal(str, "mms")) {
+ *out = OFONO_PACKET_CONTEXT_TYPE_MMS;
+ return TRUE;
+ } else if (g_str_equal(str, "ims")) {
+ *out = OFONO_PACKET_CONTEXT_TYPE_IMS;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static const char *packet_proto_to_string(enum ofono_packet_proto proto)
+{
+ switch (proto) {
+ case OFONO_PACKET_PROTO_IP:
+ return "ip";
+ case OFONO_PACKET_PROTO_IPV6:
+ return "ipv6";
+ case OFONO_PACKET_PROTO_IPV4V6:
+ return "dual";
+ };
+
+ return NULL;
+}
+
+static gboolean packet_proto_from_string(const char *str,
+ enum ofono_packet_proto *proto)
+{
+ if (g_str_equal(str, "ip")) {
+ *proto = OFONO_PACKET_PROTO_IP;
+ return TRUE;
+ } else if (g_str_equal(str, "ipv6")) {
+ *proto = OFONO_PACKET_PROTO_IPV6;
+ return TRUE;
+ } else if (g_str_equal(str, "dual")) {
+ *proto = OFONO_PACKET_PROTO_IPV4V6;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static unsigned int ps_cid_alloc(struct ofono_packet_service *ps)
+{
+ return idmap_alloc(ps->cid_map);
+}
+
+static void ps_cid_release(struct ofono_packet_service *ps, unsigned int id)
+{
+ idmap_put(ps->cid_map, id);
+}
+
+static gboolean assign_context(struct context *ctx)
+{
+ struct idmap *cidmap = ctx->ps->cid_map;
+ unsigned int cid_min;
+ GSList *l;
+
+ if (cidmap == NULL)
+ return FALSE;
+
+ cid_min = idmap_get_min(cidmap);
+
+ ctx->context.cid = ps_cid_alloc(ctx->ps);
+ if (ctx->context.cid == 0)
+ return FALSE;
+
+ for (l = ctx->ps->context_drivers; l; l = l->next) {
+ struct ofono_packet_context *pc = l->data;
+
+ if (pc->inuse == TRUE)
+ continue;
+
+ if (pc->driver == NULL)
+ continue;
+
+ if (pc->driver->activate_context == NULL ||
+ pc->driver->deactivate_context == NULL)
+ continue;
+
+ if (pc->type != OFONO_PACKET_CONTEXT_TYPE_ANY &&
+ pc->type != ctx->type)
+ continue;
+
+ ctx->context_driver = pc;
+ ctx->context_driver->inuse = TRUE;
+
+ if (ctx->context.proto == OFONO_PACKET_PROTO_IPV4V6 ||
+ ctx->context.proto == OFONO_PACKET_PROTO_IP)
+ pc->settings->ipv4 = g_new0(struct ipv4_settings, 1);
+
+ if (ctx->context.proto == OFONO_PACKET_PROTO_IPV4V6 ||
+ ctx->context.proto == OFONO_PACKET_PROTO_IPV6)
+ pc->settings->ipv6 = g_new0(struct ipv6_settings, 1);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void release_context(struct context *ctx)
+{
+ if (ctx == NULL || ctx->ps == NULL || ctx->context_driver == NULL)
+ return;
+
+ ps_cid_release(ctx->ps, ctx->context.cid);
+ ctx->context.cid = 0;
+ ctx->context_driver->inuse = FALSE;
+ ctx->context_driver = NULL;
+ ctx->active = FALSE;
+}
+
+static struct context *packet_context_by_path(
+ struct ofono_packet_service *ps,
+ const char *ctx_path)
+{
+ GSList *l;
+
+ for (l = ps->contexts; l; l = l->next) {
+ struct context *ctx = l->data;
+
+ if (g_str_equal(ctx_path, ctx->path))
+ return ctx;
+ }
+
+ return NULL;
+}
+
+static void context_settings_free(struct context_settings *settings)
+{
+ if (settings->ipv4) {
+ g_free(settings->ipv4->ip);
+ g_free(settings->ipv4->netmask);
+ g_free(settings->ipv4->gateway);
+ g_strfreev(settings->ipv4->dns);
+ g_free(settings->ipv4->proxy);
+
+ g_free(settings->ipv4);
+ settings->ipv4 = NULL;
+ }
+
+ if (settings->ipv6) {
+ g_free(settings->ipv6->ip);
+ g_free(settings->ipv6->gateway);
+ g_strfreev(settings->ipv6->dns);
+
+ g_free(settings->ipv6);
+ settings->ipv6 = NULL;
+ }
+
+ g_free(settings->interface);
+ settings->interface = NULL;
+}
+
+static void context_settings_append_ipv4(struct context_settings *settings,
+ DBusMessageIter *iter)
+{
+ DBusMessageIter variant;
+ DBusMessageIter array;
+ char typesig[5];
+ char arraysig[6];
+ const char *method;
+
+ 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 || settings->ipv4 == NULL)
+ goto done;
+
+ ofono_dbus_dict_append(&array, "Interface",
+ DBUS_TYPE_STRING, &settings->interface);
+
+ /* If we have a Proxy, no other settings are relevant */
+ if (settings->ipv4->proxy) {
+ ofono_dbus_dict_append(&array, "Proxy", DBUS_TYPE_STRING,
+ &settings->ipv4->proxy);
+ goto done;
+ }
+
+ if (settings->ipv4->static_ip == TRUE)
+ method = "static";
+ else
+ method = "dhcp";
+
+ ofono_dbus_dict_append(&array, "Method", DBUS_TYPE_STRING, &method);
+
+ if (settings->ipv4->ip)
+ ofono_dbus_dict_append(&array, "Address", DBUS_TYPE_STRING,
+ &settings->ipv4->ip);
+
+ if (settings->ipv4->netmask)
+ ofono_dbus_dict_append(&array, "Netmask", DBUS_TYPE_STRING,
+ &settings->ipv4->netmask);
+
+ if (settings->ipv4->gateway)
+ ofono_dbus_dict_append(&array, "Gateway", DBUS_TYPE_STRING,
+ &settings->ipv4->gateway);
+
+ if (settings->ipv4->dns)
+ ofono_dbus_dict_append_array(&array, "DomainNameServers",
+ DBUS_TYPE_STRING,
+ &settings->ipv4->dns);
+
+done:
+ dbus_message_iter_close_container(&variant, &array);
+
+ dbus_message_iter_close_container(iter, &variant);
+}
+
+static void context_settings_append_ipv4_dict(struct context_settings *settings,
+ DBusMessageIter *dict)
+{
+ DBusMessageIter entry;
+ const char *key = "Settings";
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ context_settings_append_ipv4(settings, &entry);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+static void context_settings_append_ipv6(struct context_settings *settings,
+ DBusMessageIter *iter)
+{
+ 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 || settings->ipv6 == NULL)
+ goto done;
+
+ ofono_dbus_dict_append(&array, "Interface",
+ DBUS_TYPE_STRING, &settings->interface);
+
+ if (settings->ipv6->ip)
+ ofono_dbus_dict_append(&array, "Address", DBUS_TYPE_STRING,
+ &settings->ipv6->ip);
+
+ if (settings->ipv6->prefix_len)
+ ofono_dbus_dict_append(&array, "PrefixLength", DBUS_TYPE_BYTE,
+ &settings->ipv6->prefix_len);
+
+ if (settings->ipv6->gateway)
+ ofono_dbus_dict_append(&array, "Gateway", DBUS_TYPE_STRING,
+ &settings->ipv6->gateway);
+
+ if (settings->ipv6->dns)
+ ofono_dbus_dict_append_array(&array, "DomainNameServers",
+ DBUS_TYPE_STRING,
+ &settings->ipv6->dns);
+
+done:
+ dbus_message_iter_close_container(&variant, &array);
+
+ dbus_message_iter_close_container(iter, &variant);
+}
+
+static void context_settings_append_ipv6_dict(struct context_settings *settings,
+ DBusMessageIter *dict)
+{
+ DBusMessageIter entry;
+ const char *key = "IPv6.Settings";
+
+ dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry);
+
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+ context_settings_append_ipv6(settings, &entry);
+
+ dbus_message_iter_close_container(dict, &entry);
+}
+
+static void signal_settings(struct context *ctx, const char *prop,
+ void (*append)(struct context_settings *, DBusMessageIter *))
+
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path = ctx->path;
+ DBusMessage *signal;
+ DBusMessageIter iter;
+ struct context_settings *settings;
+
+ signal = dbus_message_new_signal(path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "PropertyChanged");
+
+ if (signal == NULL)
+ return;
+
+ dbus_message_iter_init_append(signal, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &prop);
+
+ if (ctx->context_driver)
+ settings = ctx->context_driver->settings;
+ else
+ settings = NULL;
+
+ append(settings, &iter);
+ g_dbus_send_message(conn, signal);
+}
+
+static void context_signal_settings(struct context *ctx,
+ gboolean ipv4, gboolean ipv6)
+{
+ if (ipv4)
+ signal_settings(ctx, "Settings",
+ context_settings_append_ipv4);
+
+ if (ipv6)
+ signal_settings(ctx, "IPv6.Settings",
+ context_settings_append_ipv6);
+}
+
+static void parse_proxy(struct context *ctx, const char *proxy)
+{
+ char *scheme, *host, *port, *path;
+
+ scheme = g_strdup(proxy);
+ if (scheme == NULL)
+ return;
+
+ host = strstr(scheme, "://");
+ if (host != NULL) {
+ *host = '\0';
+ host += 3;
+
+ if (strcasecmp(scheme, "https") == 0)
+ ctx->proxy_port = 443;
+ else if (strcasecmp(scheme, "http") == 0)
+ ctx->proxy_port = 80;
+ else {
+ g_free(scheme);
+ return;
+ }
+ } else {
+ host = scheme;
+ ctx->proxy_port = 80;
+ }
+
+ path = strchr(host, '/');
+ if (path != NULL)
+ *(path++) = '\0';
+
+ port = strrchr(host, ':');
+ if (port != NULL) {
+ char *end;
+ int tmp = strtol(port + 1, &end, 10);
+
+ if (*end == '\0') {
+ *port = '\0';
+ ctx->proxy_port = tmp;
+ }
+ }
+
+ g_free(ctx->proxy_host);
+ ctx->proxy_host = g_strdup(host);
+
+ g_free(scheme);
+}
+
+static void ifupdown(const char *interface, ofono_bool_t active)
+{
+ struct ifreq ifr;
+ int sk;
+
+ if (interface == NULL)
+ return;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, interface, IFNAMSIZ);
+
+ if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0)
+ goto done;
+
+ if (active == TRUE) {
+ if (ifr.ifr_flags & IFF_UP)
+ goto done;
+ ifr.ifr_flags |= IFF_UP;
+ } else {
+ if (!(ifr.ifr_flags & IFF_UP))
+ goto done;
+ ifr.ifr_flags &= ~IFF_UP;
+ }
+
+ if (ioctl(sk, SIOCSIFFLAGS, &ifr) < 0)
+ ofono_error("Failed to change interface flags");
+
+done:
+ close(sk);
+}
+
+static void set_ipv4_addr(const char *interface, const char *address)
+{
+ struct ifreq ifr;
+ struct sockaddr_in addr;
+ int sk;
+
+ if (interface == NULL)
+ return;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, interface, IFNAMSIZ);
+
+ if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0)
+ goto done;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = address ? inet_addr(address) : INADDR_ANY;
+ memcpy(&ifr.ifr_addr, &addr, sizeof(ifr.ifr_addr));
+
+ if (ioctl(sk, SIOCSIFADDR, &ifr) < 0) {
+ ofono_error("Failed to set interface address");
+ goto done;
+ }
+
+ if (address == NULL)
+ goto done;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr("255.255.255.255");
+ memcpy(&ifr.ifr_netmask, &addr, sizeof(ifr.ifr_netmask));
+
+ if (ioctl(sk, SIOCSIFNETMASK, &ifr) < 0)
+ ofono_error("Failed to set interface netmask");
+
+done:
+ close(sk);
+}
+
+static void setproxy(const char *interface, const char *proxy)
+{
+ struct rtentry rt;
+ struct sockaddr_in addr;
+ int sk;
+
+ if (interface == NULL)
+ return;
+
+ sk = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sk < 0)
+ return;
+
+ memset(&rt, 0, sizeof(rt));
+ rt.rt_flags = RTF_UP | RTF_HOST;
+ rt.rt_dev = (char *) interface;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr(proxy);
+ memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
+
+ if (ioctl(sk, SIOCADDRT, &rt) < 0)
+ ofono_error("Failed to add proxy host route");
+
+ close(sk);
+}
+
+static void reset_context_settings(struct context *ctx)
+{
+ struct context_settings *settings;
+ char *interface;
+ gboolean signal_ipv4;
+ gboolean signal_ipv6;
+
+ if (ctx->context_driver == NULL)
+ return;
+
+ settings = ctx->context_driver->settings;
+
+ interface = settings->interface;
+ settings->interface = NULL;
+
+ signal_ipv4 = settings->ipv4 != NULL;
+ signal_ipv6 = settings->ipv6 != NULL;
+
+ context_settings_free(settings);
+
+ context_signal_settings(ctx, signal_ipv4, signal_ipv6);
+
+ if (ctx->type == OFONO_PACKET_CONTEXT_TYPE_MMS) {
+ set_ipv4_addr(interface, NULL);
+
+ g_free(ctx->proxy_host);
+ ctx->proxy_host = NULL;
+ ctx->proxy_port = 0;
+ }
+
+ ifupdown(interface, FALSE);
+
+ g_free(interface);
+}
+
+static void update_mms_context_settings(struct context *ctx)
+{
+ struct ofono_packet_context *pc = ctx->context_driver;
+ struct context_settings *settings = pc->settings;
+
+ if (ctx->message_proxy)
+ settings->ipv4->proxy = g_strdup(ctx->message_proxy);
+
+ parse_proxy(ctx, ctx->message_proxy);
+
+ DBG("proxy %s port %u", ctx->proxy_host, ctx->proxy_port);
+
+ set_ipv4_addr(settings->interface, settings->ipv4->ip);
+
+ if (ctx->proxy_host)
+ setproxy(settings->interface, ctx->proxy_host);
+}
+
+static void append_context_properties(struct context *ctx,
+ DBusMessageIter *dict)
+{
+ const char *type = packet_context_type_to_string(ctx->type);
+ const char *proto = packet_proto_to_string(ctx->context.proto);
+ const char *name = ctx->name;
+ dbus_bool_t value;
+ const char *strvalue;
+ struct context_settings *settings;
+
+ ofono_dbus_dict_append(dict, "Name", DBUS_TYPE_STRING, &name);
+
+ value = ctx->active;
+ ofono_dbus_dict_append(dict, "Active", DBUS_TYPE_BOOLEAN, &value);
+
+ ofono_dbus_dict_append(dict, "Type", DBUS_TYPE_STRING, &type);
+
+ ofono_dbus_dict_append(dict, "Protocol", DBUS_TYPE_STRING, &proto);
+
+ strvalue = ctx->context.apn;
+ ofono_dbus_dict_append(dict, "AccessPointName", DBUS_TYPE_STRING,
+ &strvalue);
+
+ strvalue = ctx->context.username;
+ ofono_dbus_dict_append(dict, "Username", DBUS_TYPE_STRING,
+ &strvalue);
+
+ strvalue = ctx->context.password;
+ ofono_dbus_dict_append(dict, "Password", DBUS_TYPE_STRING,
+ &strvalue);
+
+ if (ctx->type == OFONO_PACKET_CONTEXT_TYPE_MMS) {
+ strvalue = ctx->message_proxy;
+ ofono_dbus_dict_append(dict, "MessageProxy",
+ DBUS_TYPE_STRING, &strvalue);
+
+ strvalue = ctx->message_center;
+ ofono_dbus_dict_append(dict, "MessageCenter",
+ DBUS_TYPE_STRING, &strvalue);
+ }
+
+ if (ctx->context_driver)
+ settings = ctx->context_driver->settings;
+ else
+ settings = NULL;
+
+ context_settings_append_ipv4_dict(settings, dict);
+ context_settings_append_ipv6_dict(settings, dict);
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct context *ctx = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ OFONO_PROPERTIES_ARRAY_SIGNATURE,
+ &dict);
+ append_context_properties(ctx, &dict);
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static void activate_callback(const struct ofono_error *error, void *data)
+{
+ struct context *ctx = data;
+ struct ofono_packet_context *pc = ctx->context_driver;
+ DBusConnection *conn = ofono_dbus_get_connection();
+ dbus_bool_t value;
+
+ DBG("%p", ctx);
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ DBG("Activating context failed with error: %s",
+ telephony_error_to_str(error));
+ __ofono_dbus_pending_reply(&ctx->pending,
+ __ofono_error_failed(ctx->pending));
+ context_settings_free(ctx->context_driver->settings);
+ release_context(ctx);
+ return;
+ }
+
+ ctx->active = TRUE;
+ __ofono_dbus_pending_reply(&ctx->pending,
+ dbus_message_new_method_return(ctx->pending));
+
+ if (pc->settings->interface != NULL) {
+ ifupdown(pc->settings->interface, TRUE);
+
+ if (ctx->type == OFONO_PACKET_CONTEXT_TYPE_MMS &&
+ pc->settings->ipv4)
+ update_mms_context_settings(ctx);
+
+ context_signal_settings(ctx, pc->settings->ipv4 != NULL,
+ pc->settings->ipv6 != NULL);
+ }
+
+ value = ctx->active;
+ ofono_dbus_signal_property_changed(conn, ctx->path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "Active", DBUS_TYPE_BOOLEAN, &value);
+}
+
+static void deactivate_callback(const struct ofono_error *error, void *data)
+{
+ struct context *ctx = data;
+ DBusConnection *conn = ofono_dbus_get_connection();
+ dbus_bool_t value;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ DBG("Deactivating context failed with error: %s",
+ telephony_error_to_str(error));
+ __ofono_dbus_pending_reply(&ctx->pending,
+ __ofono_error_failed(ctx->pending));
+ return;
+ }
+
+ __ofono_dbus_pending_reply(&ctx->pending,
+ dbus_message_new_method_return(ctx->pending));
+
+ reset_context_settings(ctx);
+ release_context(ctx);
+
+ value = ctx->active;
+ ofono_dbus_signal_property_changed(conn, ctx->path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "Active", DBUS_TYPE_BOOLEAN, &value);
+}
+
+static DBusMessage *set_apn(struct context *ctx, DBusConnection *conn,
+ DBusMessage *msg, const char *apn)
+{
+ GKeyFile *settings = ctx->ps->settings;
+
+ if (strlen(apn) > OFONO_PS_MAX_APN_LENGTH)
+ return __ofono_error_invalid_format(msg);
+
+ if (g_str_equal(apn, ctx->context.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);
+
+ if (settings) {
+ g_key_file_set_string(settings, ctx->key,
+ "AccessPointName", apn);
+ storage_sync(ctx->ps->imsi, SETTINGS_STORE, settings);
+ }
+
+ g_dbus_send_reply(conn, msg, DBUS_TYPE_INVALID);
+
+ ofono_dbus_signal_property_changed(conn, ctx->path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "AccessPointName",
+ DBUS_TYPE_STRING, &apn);
+
+ return NULL;
+}
+
+static DBusMessage *set_username(struct context *ctx,
+ DBusConnection *conn, DBusMessage *msg,
+ const char *username)
+{
+ GKeyFile *settings = ctx->ps->settings;
+
+ if (strlen(username) > OFONO_PS_MAX_USERNAME_LENGTH)
+ return __ofono_error_invalid_format(msg);
+
+ if (g_str_equal(username, ctx->context.username))
+ return dbus_message_new_method_return(msg);
+
+ strcpy(ctx->context.username, username);
+
+ if (settings) {
+ g_key_file_set_string(settings, ctx->key,
+ "Username", username);
+ storage_sync(ctx->ps->imsi, SETTINGS_STORE, settings);
+ }
+
+ g_dbus_send_reply(conn, msg, DBUS_TYPE_INVALID);
+
+ ofono_dbus_signal_property_changed(conn, ctx->path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "Username",
+ DBUS_TYPE_STRING, &username);
+
+ return NULL;
+}
+
+static DBusMessage *set_password(struct context *ctx,
+ DBusConnection *conn, DBusMessage *msg,
+ const char *password)
+{
+ GKeyFile *settings = ctx->ps->settings;
+
+ if (strlen(password) > OFONO_PS_MAX_PASSWORD_LENGTH)
+ return __ofono_error_invalid_format(msg);
+
+ if (g_str_equal(password, ctx->context.password))
+ return dbus_message_new_method_return(msg);
+
+ strcpy(ctx->context.password, password);
+
+ if (settings) {
+ g_key_file_set_string(settings, ctx->key,
+ "Password", password);
+ storage_sync(ctx->ps->imsi, SETTINGS_STORE, settings);
+ }
+
+ g_dbus_send_reply(conn, msg, DBUS_TYPE_INVALID);
+
+ ofono_dbus_signal_property_changed(conn, ctx->path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "Password",
+ DBUS_TYPE_STRING, &password);
+
+ return NULL;
+}
+
+static DBusMessage *set_type(struct context *ctx, DBusConnection *conn,
+ DBusMessage *msg, const char *type)
+{
+ GKeyFile *settings = ctx->ps->settings;
+ enum ofono_packet_context_type context_type;
+
+ if (packet_context_string_to_type(type, &context_type) == FALSE)
+ return __ofono_error_invalid_format(msg);
+
+ if (ctx->type == context_type)
+ return dbus_message_new_method_return(msg);
+
+ ctx->type = context_type;
+
+ if (settings) {
+ g_key_file_set_string(settings, ctx->key, "Type", type);
+ storage_sync(ctx->ps->imsi, SETTINGS_STORE, settings);
+ }
+
+ g_dbus_send_reply(conn, msg, DBUS_TYPE_INVALID);
+
+ ofono_dbus_signal_property_changed(conn, ctx->path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "Type", DBUS_TYPE_STRING, &type);
+
+ return NULL;
+}
+
+static DBusMessage *set_proto(struct context *ctx,
+ DBusConnection *conn,
+ DBusMessage *msg, const char *str)
+{
+ GKeyFile *settings = ctx->ps->settings;
+ enum ofono_packet_proto proto;
+
+ if (packet_proto_from_string(str, &proto) == FALSE)
+ return __ofono_error_invalid_format(msg);
+
+ if (ctx->context.proto == proto)
+ return dbus_message_new_method_return(msg);
+
+ ctx->context.proto = proto;
+
+ if (settings) {
+ g_key_file_set_string(settings, ctx->key, "Protocol", str);
+ storage_sync(ctx->ps->imsi, SETTINGS_STORE, settings);
+ }
+
+ g_dbus_send_reply(conn, msg, DBUS_TYPE_INVALID);
+
+ ofono_dbus_signal_property_changed(conn, ctx->path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "Protocol", DBUS_TYPE_STRING, &str);
+
+ return NULL;
+}
+
+static DBusMessage *set_name(struct context *ctx, DBusConnection *conn,
+ DBusMessage *msg, const char *name)
+{
+ GKeyFile *settings = ctx->ps->settings;
+
+ if (strlen(name) > MAX_CONTEXT_NAME_LENGTH)
+ return __ofono_error_invalid_format(msg);
+
+ if (ctx->name && g_str_equal(ctx->name, name))
+ return dbus_message_new_method_return(msg);
+
+ strcpy(ctx->name, name);
+
+ if (settings) {
+ g_key_file_set_string(settings, ctx->key, "Name", ctx->name);
+ storage_sync(ctx->ps->imsi, SETTINGS_STORE, settings);
+ }
+
+ g_dbus_send_reply(conn, msg, DBUS_TYPE_INVALID);
+
+ ofono_dbus_signal_property_changed(conn, ctx->path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "Name", DBUS_TYPE_STRING, &name);
+
+ return NULL;
+}
+
+static DBusMessage *set_message_proxy(struct context *ctx,
+ DBusConnection *conn,
+ DBusMessage *msg, const char *proxy)
+{
+ GKeyFile *settings = ctx->ps->settings;
+
+ if (strlen(proxy) > MAX_MESSAGE_PROXY_LENGTH)
+ return __ofono_error_invalid_format(msg);
+
+ if (ctx->message_proxy && g_str_equal(ctx->message_proxy, proxy))
+ return dbus_message_new_method_return(msg);
+
+ strcpy(ctx->message_proxy, proxy);
+
+ if (settings) {
+ g_key_file_set_string(settings, ctx->key, "MessageProxy",
+ ctx->message_proxy);
+ storage_sync(ctx->ps->imsi, SETTINGS_STORE, settings);
+ }
+
+ g_dbus_send_reply(conn, msg, DBUS_TYPE_INVALID);
+
+ ofono_dbus_signal_property_changed(conn, ctx->path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "MessageProxy", DBUS_TYPE_STRING, &proxy);
+
+ return NULL;
+}
+
+static DBusMessage *set_message_center(struct context *ctx,
+ DBusConnection *conn,
+ DBusMessage *msg, const char *center)
+{
+ GKeyFile *settings = ctx->ps->settings;
+
+ if (strlen(center) > MAX_MESSAGE_CENTER_LENGTH)
+ return __ofono_error_invalid_format(msg);
+
+ if (ctx->message_center && g_str_equal(ctx->message_center, center))
+ return dbus_message_new_method_return(msg);
+
+ strcpy(ctx->message_center, center);
+
+ if (settings) {
+ g_key_file_set_string(settings, ctx->key, "MessageCenter",
+ ctx->message_center);
+ storage_sync(ctx->ps->imsi, SETTINGS_STORE, settings);
+ }
+
+ g_dbus_send_reply(conn, msg, DBUS_TYPE_INVALID);
+
+ ofono_dbus_signal_property_changed(conn, ctx->path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "MessageCenter", DBUS_TYPE_STRING, ¢er);
+
+ return NULL;
+}
+
+static DBusMessage *set_property(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct context *ctx = data;
+ DBusMessageIter iter;
+ DBusMessageIter var;
+ const char *property;
+ dbus_bool_t value;
+ const char *str;
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return __ofono_error_invalid_args(msg);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&iter, &property);
+ dbus_message_iter_next(&iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_recurse(&iter, &var);
+
+ if (g_str_equal(property, "Active")) {
+ struct ofono_packet_context *pc;
+
+ if (ctx->ps->pending)
+ return __ofono_error_busy(msg);
+
+ if (ctx->pending)
+ return __ofono_error_busy(msg);
+
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BOOLEAN)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&var, &value);
+
+ if (ctx->active == (ofono_bool_t) value)
+ return dbus_message_new_method_return(msg);
+
+ if (value && !ctx->ps->attached)
+ return __ofono_error_not_attached(msg);
+
+ if (ctx->ps->flags & PS_FLAG_ATTACHING)
+ return __ofono_error_attach_in_progress(msg);
+
+ if (value && assign_context(ctx) == FALSE)
+ return __ofono_error_not_implemented(msg);
+
+ pc = ctx->context_driver;
+
+ ctx->pending = dbus_message_ref(msg);
+
+ if (value)
+ pc->driver->activate_context(pc, &ctx->context,
+ activate_callback, ctx);
+ else
+ pc->driver->deactivate_context(pc, ctx->context.cid,
+ deactivate_callback, ctx);
+
+ return NULL;
+ }
+
+ /* All other properties are read-only when context is active */
+ if (ctx->active == TRUE)
+ return __ofono_error_in_use(msg);
+
+ if (!strcmp(property, "AccessPointName")) {
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&var, &str);
+
+ return set_apn(ctx, conn, msg, str);
+ } else if (!strcmp(property, "Type")) {
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&var, &str);
+
+ return set_type(ctx, conn, msg, str);
+ } else if (!strcmp(property, "Protocol")) {
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&var, &str);
+
+ return set_proto(ctx, conn, msg, str);
+ } else if (!strcmp(property, "Username")) {
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&var, &str);
+
+ return set_username(ctx, conn, msg, str);
+ } else if (!strcmp(property, "Password")) {
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&var, &str);
+
+ return set_password(ctx, conn, msg, str);
+ } else if (!strcmp(property, "Name")) {
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&var, &str);
+
+ return set_name(ctx, conn, msg, str);
+ }
+
+ if (ctx->type != OFONO_PACKET_CONTEXT_TYPE_MMS)
+ return __ofono_error_invalid_args(msg);
+
+ if (!strcmp(property, "MessageProxy")) {
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&var, &str);
+
+ return set_message_proxy(ctx, conn, msg, str);
+ } else if (!strcmp(property, "MessageCenter")) {
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&var, &str);
+
+ return set_message_center(ctx, conn, msg, str);
+ }
+
+ return __ofono_error_invalid_args(msg);
+}
+
+static GDBusMethodTable context_methods[] = {
+ { "GetProperties", "", "a{sv}", get_properties },
+ { "SetProperty", "sv", "", set_property,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { }
+};
+
+static GDBusSignalTable context_signals[] = {
+ { "PropertyChanged", "sv" },
+ { }
+};
+
+static struct context *context_create(struct ofono_packet_service *ps,
+ const char *name,
+ enum ofono_packet_context_type type)
+{
+ struct context *context = g_try_new0(struct context, 1);
+
+ if (context == NULL)
+ return NULL;
+
+ if (name == NULL) {
+ name = packet_context_default_name(type);
+ if (name == NULL) {
+ g_free(context);
+ return NULL;
+ }
+ }
+
+ context->ps = ps;
+ strcpy(context->name, name);
+ context->type = type;
+
+ return context;
+}
+
+static void context_destroy(gpointer userdata)
+{
+ struct context *ctx = userdata;
+
+ g_free(ctx->proxy_host);
+ g_free(ctx->path);
+ g_free(ctx);
+}
+
+static gboolean context_dbus_register(struct context *ctx)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ char path[256];
+ const char *basepath;
+
+ basepath = __ofono_atom_get_path(ctx->ps->atom);
+
+ snprintf(path, sizeof(path), "%s/context%u", basepath, ctx->id);
+
+ if (!g_dbus_register_interface(conn, path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ context_methods, context_signals,
+ NULL, ctx, context_destroy)) {
+ ofono_error("Could not register PrimaryContext %s", path);
+ idmap_put(ctx->ps->pid_map, ctx->id);
+ context_destroy(ctx);
+
+ return FALSE;
+ }
+
+ ctx->path = g_strdup(path);
+ ctx->key = ctx->path + strlen(basepath) + 1;
+
+ return TRUE;
+}
+
+static gboolean context_dbus_unregister(struct context *ctx)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ char path[256];
+
+ strcpy(path, ctx->path);
+ idmap_put(ctx->ps->pid_map, ctx->id);
+
+ return g_dbus_unregister_interface(conn, path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE);
+}
+
+static void update_suspended_property(struct ofono_packet_service *ps,
+ ofono_bool_t suspended)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path = __ofono_atom_get_path(ps->atom);
+ dbus_bool_t value = suspended;
+
+ if (ps->suspend_timeout) {
+ g_source_remove(ps->suspend_timeout);
+ ps->suspend_timeout = 0;
+ }
+
+ if (ps->suspended == suspended)
+ return;
+
+ DBG("%s GPRS service %s", __ofono_atom_get_path(ps->atom),
+ suspended ? "suspended" : "resumed");
+
+ ps->suspended = suspended;
+
+ if (ps->attached)
+ ofono_dbus_signal_property_changed(conn, path,
+ OFONO_CONNECTION_MANAGER_INTERFACE,
+ "Suspended", DBUS_TYPE_BOOLEAN, &value);
+}
+
+static gboolean suspend_timeout(gpointer data)
+{
+ struct ofono_packet_service *ps = data;
+
+ ps->suspend_timeout = 0;
+ update_suspended_property(ps, TRUE);
+ return FALSE;
+}
+
+void ofono_packet_service_suspend_notify(struct ofono_packet_service *ps,
+ int cause)
+{
+ switch (cause) {
+ case PACKET_SERVICE_SUSPENDED_DETACHED:
+ case PACKET_SERVICE_SUSPENDED_CALL:
+ case PACKET_SERVICE_SUSPENDED_NO_COVERAGE:
+ update_suspended_property(ps, TRUE);
+ break;
+
+ case PACKET_SERVICE_SUSPENDED_SIGNALLING:
+ case PACKET_SERVICE_SUSPENDED_UNKNOWN_CAUSE:
+ if (ps->suspend_timeout)
+ g_source_remove(ps->suspend_timeout);
+ ps->suspend_timeout = g_timeout_add_seconds(SUSPEND_TIMEOUT,
+ suspend_timeout,
+ ps);
+ break;
+ }
+}
+
+void ofono_packet_service_resume_notify(struct ofono_packet_service *ps)
+{
+ update_suspended_property(ps, FALSE);
+}
+
+static void ps_attached_update(struct ofono_packet_service *ps)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path;
+ ofono_bool_t attached;
+ dbus_bool_t value;
+
+ attached = ps->driver_attached &&
+ (ps->status == NETWORK_REGISTRATION_STATUS_REGISTERED ||
+ ps->status == NETWORK_REGISTRATION_STATUS_ROAMING);
+
+ if (attached == ps->attached)
+ return;
+
+ ps->attached = attached;
+
+ if (ps->attached == FALSE) {
+ GSList *l;
+ struct context *ctx;
+
+ for (l = ps->contexts; l; l = l->next) {
+ ctx = l->data;
+
+ if (ctx->active == FALSE)
+ continue;
+
+ reset_context_settings(ctx);
+ release_context(ctx);
+
+ value = FALSE;
+ ofono_dbus_signal_property_changed(conn, ctx->path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "Active", DBUS_TYPE_BOOLEAN, &value);
+ }
+
+ ps->bearer = -1;
+ }
+
+ path = __ofono_atom_get_path(ps->atom);
+ value = attached;
+ ofono_dbus_signal_property_changed(conn, path,
+ OFONO_CONNECTION_MANAGER_INTERFACE,
+ "Attached", DBUS_TYPE_BOOLEAN, &value);
+}
+
+static void registration_status_cb(const struct ofono_error *error,
+ int status, void *data)
+{
+ struct ofono_packet_service *ps = data;
+
+ DBG("%s error %d status %d", __ofono_atom_get_path(ps->atom),
+ error->type, status);
+
+ if (error->type == OFONO_ERROR_TYPE_NO_ERROR)
+ ofono_packet_service_status_notify(ps, status);
+
+ if (ps->flags & PS_FLAG_RECHECK) {
+ ps->flags &= ~PS_FLAG_RECHECK;
+ ps_netreg_update(ps);
+ }
+}
+
+static void ps_attach_callback(const struct ofono_error *error,
+ void *data)
+{
+ struct ofono_packet_service *ps = data;
+
+ DBG("%s error = %d", __ofono_atom_get_path(ps->atom), error->type);
+
+ ps->flags &= ~PS_FLAG_ATTACHING;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+ ps->driver_attached = !ps->driver_attached;
+
+ if (ps->driver->attached_status) {
+ ps->driver->attached_status(ps, registration_status_cb,
+ ps);
+ return;
+ }
+
+ ps_attached_update(ps);
+
+ if (ps->flags & PS_FLAG_RECHECK) {
+ ps->flags &= ~PS_FLAG_RECHECK;
+ ps_netreg_update(ps);
+ }
+}
+
+static void ps_netreg_removed(struct ofono_packet_service *ps)
+{
+ ps->netreg = NULL;
+
+ ps->flags &= ~(PS_FLAG_RECHECK | PS_FLAG_ATTACHING);
+ ps->status_watch = 0;
+ ps->netreg_status = NETWORK_REGISTRATION_STATUS_NOT_REGISTERED;
+ ps->driver_attached = FALSE;
+
+ ps_attached_update(ps);
+}
+
+static void ps_netreg_update(struct ofono_packet_service *ps)
+{
+ ofono_bool_t attach;
+
+ attach = ps->netreg_status == NETWORK_REGISTRATION_STATUS_REGISTERED;
+
+ attach = attach || (ps->roaming_allowed &&
+ ps->netreg_status == NETWORK_REGISTRATION_STATUS_ROAMING);
+
+ attach = attach && ps->powered;
+
+ if (ps->driver_attached == attach)
+ return;
+
+ if (ps->flags & PS_FLAG_ATTACHING) {
+ ps->flags |= PS_FLAG_RECHECK;
+ return;
+ }
+
+ ps->flags |= PS_FLAG_ATTACHING;
+
+ ps->driver->set_attached(ps, attach, ps_attach_callback,
+ ps);
+ ps->driver_attached = attach;
+}
+
+static void netreg_status_changed(int status, int lac, int ci, int tech,
+ const char *mcc, const char *mnc,
+ void *data)
+{
+ struct ofono_packet_service *ps = data;
+
+ DBG("%d", status);
+
+ if (ps->netreg_status == status)
+ return;
+
+ ps->netreg_status = status;
+
+ ps_netreg_update(ps);
+}
+
+static DBusMessage *ps_get_properties(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct ofono_packet_service *ps = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ dbus_bool_t value;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ OFONO_PROPERTIES_ARRAY_SIGNATURE,
+ &dict);
+
+ value = ps->attached;
+ ofono_dbus_dict_append(&dict, "Attached", DBUS_TYPE_BOOLEAN, &value);
+
+ if (ps->bearer != -1) {
+ const char *bearer = packet_bearer_to_string(ps->bearer);
+
+ ofono_dbus_dict_append(&dict, "Bearer",
+ DBUS_TYPE_STRING, &bearer);
+ }
+
+ value = ps->roaming_allowed;
+ ofono_dbus_dict_append(&dict, "RoamingAllowed",
+ DBUS_TYPE_BOOLEAN, &value);
+
+ value = ps->powered;
+ ofono_dbus_dict_append(&dict, "Powered", DBUS_TYPE_BOOLEAN, &value);
+
+ if (ps->attached) {
+ value = ps->suspended;
+ ofono_dbus_dict_append(&dict, "Suspended",
+ DBUS_TYPE_BOOLEAN, &value);
+ }
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static DBusMessage *ps_set_property(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct ofono_packet_service *ps = data;
+ DBusMessageIter iter;
+ DBusMessageIter var;
+ const char *property;
+ dbus_bool_t value;
+ const char *path;
+
+ if (ps->pending)
+ return __ofono_error_busy(msg);
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return __ofono_error_invalid_args(msg);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&iter, &property);
+ dbus_message_iter_next(&iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_recurse(&iter, &var);
+
+ if (!strcmp(property, "RoamingAllowed")) {
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BOOLEAN)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&var, &value);
+
+ if (ps->roaming_allowed == (ofono_bool_t) value)
+ return dbus_message_new_method_return(msg);
+
+ ps->roaming_allowed = value;
+
+ if (ps->settings) {
+ g_key_file_set_integer(ps->settings, SETTINGS_GROUP,
+ "RoamingAllowed",
+ ps->roaming_allowed);
+ storage_sync(ps->imsi, SETTINGS_STORE,
+ ps->settings);
+ }
+
+ ps_netreg_update(ps);
+ } else if (!strcmp(property, "Powered")) {
+ if (ps->driver->set_attached == NULL)
+ return __ofono_error_not_implemented(msg);
+
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_BOOLEAN)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&var, &value);
+
+ if (ps->powered == (ofono_bool_t) value)
+ return dbus_message_new_method_return(msg);
+
+ ps->powered = value;
+
+ if (ps->settings) {
+ g_key_file_set_integer(ps->settings, SETTINGS_GROUP,
+ "Powered", ps->powered);
+ storage_sync(ps->imsi, SETTINGS_STORE,
+ ps->settings);
+ }
+
+ ps_netreg_update(ps);
+ } else {
+ return __ofono_error_invalid_args(msg);
+ }
+
+ path = __ofono_atom_get_path(ps->atom);
+ ofono_dbus_signal_property_changed(conn, path,
+ OFONO_CONNECTION_MANAGER_INTERFACE,
+ property, DBUS_TYPE_BOOLEAN, &value);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static void write_context_settings(struct ofono_packet_service *ps,
+ struct context *context)
+{
+ g_key_file_set_string(ps->settings, context->key,
+ "Name", context->name);
+ g_key_file_set_string(ps->settings, context->key,
+ "AccessPointName", context->context.apn);
+ g_key_file_set_string(ps->settings, context->key,
+ "Username", context->context.username);
+ g_key_file_set_string(ps->settings, context->key,
+ "Password", context->context.password);
+ g_key_file_set_string(ps->settings, context->key, "Type",
+ packet_context_type_to_string(context->type));
+ g_key_file_set_string(ps->settings, context->key, "Protocol",
+ packet_proto_to_string(context->context.proto));
+
+ if (context->type == OFONO_PACKET_CONTEXT_TYPE_MMS) {
+ g_key_file_set_string(ps->settings, context->key,
+ "MessageProxy",
+ context->message_proxy);
+ g_key_file_set_string(ps->settings, context->key,
+ "MessageCenter",
+ context->message_center);
+ }
+}
+
+static struct context *add_context(struct ofono_packet_service *ps,
+ const char *name,
+ enum ofono_packet_context_type type)
+{
+ unsigned int id;
+ struct context *context;
+
+ if (ps->last_context_id)
+ id = idmap_alloc_next(ps->pid_map, ps->last_context_id);
+ else
+ id = idmap_alloc(ps->pid_map);
+
+ if (id > idmap_get_max(ps->pid_map))
+ return NULL;
+
+ context = context_create(ps, name, type);
+ if (context == NULL) {
+ idmap_put(ps->pid_map, id);
+ ofono_error("Unable to allocate context struct");
+ return NULL;
+ }
+
+ context->id = id;
+
+ DBG("Registering new context");
+
+ if (!context_dbus_register(context)) {
+ ofono_error("Unable to register primary context");
+ return NULL;
+ }
+
+ ps->last_context_id = id;
+
+ if (ps->settings) {
+ write_context_settings(ps, context);
+ storage_sync(ps->imsi, SETTINGS_STORE, ps->settings);
+ }
+
+ ps->contexts = g_slist_append(ps->contexts, context);
+
+ return context;
+}
+
+static DBusMessage *ps_add_context(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_packet_service *ps = data;
+ struct context *context;
+ const char *typestr;
+ const char *name;
+ const char *path;
+ enum ofono_packet_context_type type;
+ DBusMessage *signal;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &typestr,
+ DBUS_TYPE_INVALID))
+ return __ofono_error_invalid_args(msg);
+
+ if (packet_context_string_to_type(typestr, &type) == FALSE)
+ return __ofono_error_invalid_format(msg);
+
+ name = packet_context_default_name(type);
+ if (name == NULL)
+ name = typestr;
+
+ context = add_context(ps, name, type);
+ if (context == NULL)
+ return __ofono_error_failed(msg);
+
+ path = context->path;
+
+ g_dbus_send_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+ path = __ofono_atom_get_path(ps->atom);
+ signal = dbus_message_new_signal(path,
+ OFONO_CONNECTION_MANAGER_INTERFACE,
+ "ContextAdded");
+
+ if (signal) {
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+
+ dbus_message_iter_init_append(signal, &iter);
+
+ path = context->path;
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+ &path);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ OFONO_PROPERTIES_ARRAY_SIGNATURE,
+ &dict);
+ append_context_properties(context, &dict);
+ dbus_message_iter_close_container(&iter, &dict);
+
+ g_dbus_send_message(conn, signal);
+ }
+
+ return NULL;
+}
+
+static void ps_deactivate_for_remove(const struct ofono_error *error,
+ void *data)
+{
+ struct context *ctx = data;
+ struct ofono_packet_service *ps = ctx->ps;
+ DBusConnection *conn;
+ char *path;
+ const char *atompath;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ DBG("Removing context failed with error: %s",
+ telephony_error_to_str(error));
+
+ __ofono_dbus_pending_reply(&ps->pending,
+ __ofono_error_failed(ps->pending));
+ return;
+ }
+
+ reset_context_settings(ctx);
+ release_context(ctx);
+
+ if (ps->settings) {
+ g_key_file_remove_group(ps->settings, ctx->key, NULL);
+ storage_sync(ps->imsi, SETTINGS_STORE, ps->settings);
+ }
+
+ /* Make a backup copy of path for signal emission below */
+ path = g_strdup(ctx->path);
+
+ context_dbus_unregister(ctx);
+ ps->contexts = g_slist_remove(ps->contexts, ctx);
+
+ __ofono_dbus_pending_reply(&ps->pending,
+ dbus_message_new_method_return(ps->pending));
+
+ atompath = __ofono_atom_get_path(ps->atom);
+ conn = ofono_dbus_get_connection();
+ g_dbus_emit_signal(conn, atompath, OFONO_CONNECTION_MANAGER_INTERFACE,
+ "ContextRemoved", DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+ g_free(path);
+}
+
+static DBusMessage *ps_remove_context(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_packet_service *ps = data;
+ struct context *ctx;
+ const char *path;
+ const char *atompath;
+
+ if (ps->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);
+
+ if (path[0] == '\0')
+ return __ofono_error_invalid_format(msg);
+
+ ctx = packet_context_by_path(ps, path);
+ if (ctx == NULL)
+ return __ofono_error_not_found(msg);
+
+ if (ctx->active) {
+ struct ofono_packet_context *pc = ctx->context_driver;
+
+ /* This context is already being messed with */
+ if (ctx->pending)
+ return __ofono_error_busy(msg);
+
+ ps->pending = dbus_message_ref(msg);
+ pc->driver->deactivate_context(pc, ctx->context.cid,
+ ps_deactivate_for_remove, ctx);
+ return NULL;
+ }
+
+ if (ps->settings) {
+ g_key_file_remove_group(ps->settings, ctx->key, NULL);
+ storage_sync(ps->imsi, SETTINGS_STORE, ps->settings);
+ }
+
+ DBG("Unregistering context: %s", ctx->path);
+ context_dbus_unregister(ctx);
+ ps->contexts = g_slist_remove(ps->contexts, ctx);
+
+ g_dbus_send_reply(conn, msg, DBUS_TYPE_INVALID);
+
+ atompath = __ofono_atom_get_path(ps->atom);
+ g_dbus_emit_signal(conn, atompath, OFONO_CONNECTION_MANAGER_INTERFACE,
+ "ContextRemoved", DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+ return NULL;
+}
+
+static void ps_deactivate_for_all(const struct ofono_error *error,
+ void *data)
+{
+ struct context *ctx = data;
+ struct ofono_packet_service *ps = ctx->ps;
+ DBusConnection *conn;
+ dbus_bool_t value;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ __ofono_dbus_pending_reply(&ps->pending,
+ __ofono_error_failed(ps->pending));
+ return;
+ }
+
+ reset_context_settings(ctx);
+ release_context(ctx);
+
+ value = ctx->active;
+ conn = ofono_dbus_get_connection();
+ ofono_dbus_signal_property_changed(conn, ctx->path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "Active", DBUS_TYPE_BOOLEAN, &value);
+
+ ps_deactivate_next(ps);
+}
+
+static void ps_deactivate_next(struct ofono_packet_service *ps)
+{
+ GSList *l;
+ struct context *ctx;
+ struct ofono_packet_context *pc;
+
+ for (l = ps->contexts; l; l = l->next) {
+ ctx = l->data;
+
+ if (ctx->active == FALSE)
+ continue;
+
+ pc = ctx->context_driver;
+ pc->driver->deactivate_context(pc, ctx->context.cid,
+ ps_deactivate_for_all, ctx);
+
+ return;
+ }
+
+ __ofono_dbus_pending_reply(&ps->pending,
+ dbus_message_new_method_return(ps->pending));
+}
+
+static DBusMessage *ps_deactivate_all(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_packet_service *ps = data;
+ GSList *l;
+ struct context *ctx;
+
+ if (ps->pending)
+ return __ofono_error_busy(msg);
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID))
+ return __ofono_error_invalid_args(msg);
+
+ for (l = ps->contexts; l; l = l->next) {
+ ctx = l->data;
+
+ if (ctx->pending)
+ return __ofono_error_busy(msg);
+ }
+
+ ps->pending = dbus_message_ref(msg);
+
+ ps_deactivate_next(ps);
+
+ return NULL;
+}
+
+static DBusMessage *ps_get_contexts(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_packet_service *ps = data;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array;
+ DBusMessageIter entry, dict;
+ const char *path;
+ GSList *l;
+ struct context *ctx;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_OBJECT_PATH_AS_STRING
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+ DBUS_STRUCT_END_CHAR_AS_STRING,
+ &array);
+
+ for (l = ps->contexts; l; l = l->next) {
+ ctx = l->data;
+
+ path = ctx->path;
+
+ dbus_message_iter_open_container(&array, DBUS_TYPE_STRUCT,
+ NULL, &entry);
+ dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
+ &path);
+ dbus_message_iter_open_container(&entry, DBUS_TYPE_ARRAY,
+ OFONO_PROPERTIES_ARRAY_SIGNATURE,
+ &dict);
+
+ append_context_properties(ctx, &dict);
+ dbus_message_iter_close_container(&entry, &dict);
+ dbus_message_iter_close_container(&array, &entry);
+ }
+
+ dbus_message_iter_close_container(&iter, &array);
+
+ return reply;
+}
+
+static GDBusMethodTable manager_methods[] = {
+ { "GetProperties", "", "a{sv}", ps_get_properties },
+ { "SetProperty", "sv", "", ps_set_property },
+ { "AddContext", "s", "o", ps_add_context,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "RemoveContext", "o", "", ps_remove_context,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "DeactivateAll", "", "", ps_deactivate_all,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { "GetContexts", "", "a(oa{sv})", ps_get_contexts },
+ { }
+};
+
+static GDBusSignalTable manager_signals[] = {
+ { "PropertyChanged", "sv" },
+ { "ContextAdded", "oa{sv}" },
+ { "ContextRemoved", "o" },
+ { }
+};
+
+void ofono_packet_service_detached_notify(struct ofono_packet_service *ps)
+{
+ DBG("%s", __ofono_atom_get_path(ps->atom));
+
+ ps->driver_attached = FALSE;
+ ps_attached_update(ps);
+
+ /*
+ * TODO: The network forced a detach, we should wait for some time
+ * and try to re-attach. This might also be related to a suspend
+ * event while voicecall is active.
+ */
+}
+
+void ofono_packet_service_status_notify(struct ofono_packet_service *ps, int status)
+{
+ DBG("%s status %d", __ofono_atom_get_path(ps->atom), status);
+
+ ps->status = status;
+
+ if (status != NETWORK_REGISTRATION_STATUS_REGISTERED &&
+ status != NETWORK_REGISTRATION_STATUS_ROAMING) {
+ ps_attached_update(ps);
+ return;
+ }
+
+ /* We registered without being powered */
+ if (ps->powered == FALSE)
+ goto detach;
+
+ if (ps->roaming_allowed == FALSE &&
+ status == NETWORK_REGISTRATION_STATUS_ROAMING)
+ goto detach;
+
+ ps->driver_attached = TRUE;
+ ps_attached_update(ps);
+
+ return;
+
+detach:
+ ps->flags |= PS_FLAG_ATTACHING;
+ ps->driver->set_attached(ps, FALSE, ps_attach_callback, ps);
+}
+
+void ofono_packet_service_set_cid_range(struct ofono_packet_service *ps,
+ unsigned int min, unsigned int max)
+{
+ if (ps == NULL)
+ return;
+
+ if (ps->cid_map)
+ idmap_free(ps->cid_map);
+
+ ps->cid_map = idmap_new_from_range(min, max);
+}
+
+static void packet_context_unregister(struct ofono_atom *atom)
+{
+ struct ofono_packet_context *pc = __ofono_atom_get_data(atom);
+
+ if (pc->ps == NULL)
+ return;
+
+ if (pc->settings) {
+ context_settings_free(pc->settings);
+ g_free(pc->settings);
+ pc->settings = NULL;
+ }
+
+ pc->ps->context_drivers = g_slist_remove(pc->ps->context_drivers,
+ pc);
+ pc->ps = NULL;
+}
+
+void ofono_packet_service_add_context(struct ofono_packet_service *ps,
+ struct ofono_packet_context *pc)
+{
+ if (pc->driver == NULL)
+ return;
+
+ pc->ps = ps;
+ pc->settings = g_new0(struct context_settings, 1);
+
+ ps->context_drivers = g_slist_append(ps->context_drivers, pc);
+ __ofono_atom_register(pc->atom, packet_context_unregister);
+}
+
+void ofono_packet_service_bearer_notify(struct ofono_packet_service *ps, int bearer)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path;
+ const char *value;
+
+ if (ps->bearer == bearer)
+ return;
+
+ ps->bearer = bearer;
+ path = __ofono_atom_get_path(ps->atom);
+ value = packet_bearer_to_string(bearer);
+ ofono_dbus_signal_property_changed(conn, path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "Bearer", DBUS_TYPE_STRING, &value);
+}
+
+void ofono_packet_context_deactivated(struct ofono_packet_context *pc,
+ unsigned int cid)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ GSList *l;
+ struct context *ctx;
+ dbus_bool_t value;
+
+ if (pc->ps == NULL)
+ return;
+
+ for (l = pc->ps->contexts; l; l = l->next) {
+ ctx = l->data;
+
+ if (ctx->context.cid != cid)
+ continue;
+
+ if (ctx->active == FALSE)
+ break;
+
+ reset_context_settings(ctx);
+ release_context(ctx);
+
+ value = FALSE;
+ ofono_dbus_signal_property_changed(conn, ctx->path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "Active", DBUS_TYPE_BOOLEAN, &value);
+ }
+}
+
+int ofono_packet_context_driver_register(const struct ofono_packet_context_driver *d)
+{
+ DBG("driver: %p, name: %s", d, d->name);
+
+ if (d->probe == NULL)
+ return -EINVAL;
+
+ g_context_drivers = g_slist_prepend(g_context_drivers, (void *) d);
+
+ return 0;
+}
+
+void ofono_packet_context_driver_unregister(const struct ofono_packet_context_driver *d)
+{
+ DBG("driver: %p, name: %s", d, d->name);
+
+ g_context_drivers = g_slist_remove(g_context_drivers, (void *) d);
+}
+
+static void packet_context_remove(struct ofono_atom *atom)
+{
+ struct ofono_packet_context *pc = __ofono_atom_get_data(atom);
+
+ DBG("atom: %p", atom);
+
+ if (pc == NULL)
+ return;
+
+ if (pc->driver && pc->driver->remove)
+ pc->driver->remove(pc);
+
+ g_free(pc);
+}
+
+struct ofono_packet_context *ofono_packet_context_create(struct ofono_modem *modem,
+ unsigned int vendor,
+ const char *driver, void *data)
+{
+ struct ofono_packet_context *pc;
+ GSList *l;
+
+ if (driver == NULL)
+ return NULL;
+
+ pc = g_try_new0(struct ofono_packet_context, 1);
+ if (pc == NULL)
+ return NULL;
+
+ pc->type = OFONO_PACKET_CONTEXT_TYPE_ANY;
+
+ pc->atom = __ofono_modem_add_atom(modem, OFONO_ATOM_TYPE_PACKET_CONTEXT,
+ packet_context_remove, pc);
+
+ for (l = g_context_drivers; l; l = l->next) {
+ const struct ofono_packet_context_driver *drv = l->data;
+
+ if (g_strcmp0(drv->name, driver))
+ continue;
+
+ if (drv->probe(pc, vendor, data) < 0)
+ continue;
+
+ pc->driver = drv;
+ break;
+ }
+
+ return pc;
+}
+
+void ofono_packet_context_remove(struct ofono_packet_context *pc)
+{
+ if (pc == NULL)
+ return;
+
+ __ofono_atom_free(pc->atom);
+}
+
+void ofono_packet_context_set_data(struct ofono_packet_context *pc, void *data)
+{
+ pc->driver_data = data;
+}
+
+void *ofono_packet_context_get_data(struct ofono_packet_context *pc)
+{
+ return pc->driver_data;
+}
+
+struct ofono_modem *ofono_packet_context_get_modem(struct ofono_packet_context *pc)
+{
+ return __ofono_atom_get_modem(pc->atom);
+}
+
+void ofono_packet_context_set_type(struct ofono_packet_context *pc,
+ enum ofono_packet_context_type type)
+{
+ DBG("type %d", type);
+
+ pc->type = type;
+}
+
+void ofono_packet_context_set_interface(struct ofono_packet_context *pc,
+ const char *interface)
+{
+ struct context_settings *settings = pc->settings;
+
+ g_free(settings->interface);
+ settings->interface = g_strdup(interface);
+}
+
+void ofono_packet_context_set_ipv4_address(struct ofono_packet_context *pc,
+ const char *address,
+ gboolean static_ip)
+{
+ struct context_settings *settings = pc->settings;
+
+ if (settings->ipv4 == NULL)
+ return;
+
+ g_free(settings->ipv4->ip);
+ settings->ipv4->ip = g_strdup(address);
+ settings->ipv4->static_ip = static_ip;
+}
+
+void ofono_packet_context_set_ipv4_netmask(struct ofono_packet_context *pc,
+ const char *netmask)
+{
+ struct context_settings *settings = pc->settings;
+
+ if (settings->ipv4 == NULL)
+ return;
+
+ g_free(settings->ipv4->netmask);
+ settings->ipv4->netmask = g_strdup(netmask);
+}
+
+void ofono_packet_context_set_ipv4_gateway(struct ofono_packet_context *pc,
+ const char *gateway)
+{
+ struct context_settings *settings = pc->settings;
+
+ if (settings->ipv4 == NULL)
+ return;
+
+ g_free(settings->ipv4->gateway);
+ settings->ipv4->gateway = g_strdup(gateway);
+}
+
+void ofono_packet_context_set_ipv4_dns_servers(struct ofono_packet_context *pc,
+ const char **dns)
+{
+ struct context_settings *settings = pc->settings;
+
+ if (settings->ipv4 == NULL)
+ return;
+
+ g_strfreev(settings->ipv4->dns);
+ settings->ipv4->dns = g_strdupv((char **) dns);
+}
+
+void ofono_packet_context_set_ipv6_address(struct ofono_packet_context *pc,
+ const char *address)
+{
+ struct context_settings *settings = pc->settings;
+
+ if (settings->ipv6 == NULL)
+ return;
+
+ g_free(settings->ipv6->ip);
+ settings->ipv6->ip = g_strdup(address);
+}
+
+void ofono_packet_context_set_ipv6_prefix_length(struct ofono_packet_context *pc,
+ unsigned char length)
+{
+ struct context_settings *settings = pc->settings;
+
+ if (settings->ipv6 == NULL)
+ return;
+
+ settings->ipv6->prefix_len = length;
+}
+
+void ofono_packet_context_set_ipv6_gateway(struct ofono_packet_context *pc,
+ const char *gateway)
+{
+ struct context_settings *settings = pc->settings;
+
+ if (settings->ipv6 == NULL)
+ return;
+
+ g_free(settings->ipv6->gateway);
+ settings->ipv6->gateway = g_strdup(gateway);
+}
+
+void ofono_packet_context_set_ipv6_dns_servers(struct ofono_packet_context *pc,
+ const char **dns)
+{
+ struct context_settings *settings = pc->settings;
+
+ if (settings->ipv6 == NULL)
+ return;
+
+ g_strfreev(settings->ipv6->dns);
+ settings->ipv6->dns = g_strdupv((char **) dns);
+}
+
+int ofono_packet_service_driver_register(
+ const struct ofono_packet_service_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_packet_service_driver_unregister(
+ const struct ofono_packet_service_driver *d)
+{
+ DBG("driver: %p, name: %s", d, d->name);
+
+ g_drivers = g_slist_remove(g_drivers, (void *) d);
+}
+
+static void free_contexts(struct ofono_packet_service *ps)
+{
+ GSList *l;
+
+ if (ps->settings) {
+ storage_close(ps->imsi, SETTINGS_STORE,
+ ps->settings, TRUE);
+
+ g_free(ps->imsi);
+ ps->imsi = NULL;
+ ps->settings = NULL;
+ }
+
+ for (l = ps->contexts; l; l = l->next) {
+ struct context *context = l->data;
+
+ context_dbus_unregister(context);
+ }
+
+ g_slist_free(ps->contexts);
+}
+
+static void packet_service_unregister(struct ofono_atom *atom)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_packet_service *ps = __ofono_atom_get_data(atom);
+ struct ofono_modem *modem = __ofono_atom_get_modem(atom);
+ const char *path = __ofono_atom_get_path(atom);
+
+ free_contexts(ps);
+
+ if (ps->cid_map) {
+ idmap_free(ps->cid_map);
+ ps->cid_map = NULL;
+ }
+
+ if (ps->netreg_watch) {
+ if (ps->status_watch) {
+ __ofono_netreg_remove_status_watch(ps->netreg,
+ ps->status_watch);
+ ps->status_watch = 0;
+ }
+
+ __ofono_modem_remove_atom_watch(modem, ps->netreg_watch);
+ ps->netreg_watch = 0;
+ ps->netreg = NULL;
+ }
+
+ ofono_modem_remove_interface(modem,
+ OFONO_CONNECTION_MANAGER_INTERFACE);
+ g_dbus_unregister_interface(conn, path,
+ OFONO_CONNECTION_MANAGER_INTERFACE);
+}
+
+static void packet_service_remove(struct ofono_atom *atom)
+{
+ struct ofono_packet_service *ps = __ofono_atom_get_data(atom);
+
+ DBG("atom: %p", atom);
+
+ if (ps == NULL)
+ return;
+
+ if (ps->suspend_timeout)
+ g_source_remove(ps->suspend_timeout);
+
+ if (ps->pid_map) {
+ idmap_free(ps->pid_map);
+ ps->pid_map = NULL;
+ }
+
+ g_slist_free(ps->context_drivers);
+
+ if (ps->driver && ps->driver->remove)
+ ps->driver->remove(ps);
+
+ if (ps->sim_context)
+ ofono_sim_context_free(ps->sim_context);
+
+ g_free(ps);
+}
+
+struct ofono_packet_service *ofono_packet_service_create(
+ struct ofono_modem *modem,
+ unsigned int vendor,
+ const char *driver, void *data)
+{
+ struct ofono_packet_service *ps;
+ GSList *l;
+
+ if (driver == NULL)
+ return NULL;
+
+ ps = g_try_new0(struct ofono_packet_service, 1);
+ if (ps == NULL)
+ return NULL;
+
+ ps->atom = __ofono_modem_add_atom(modem,
+ OFONO_ATOM_TYPE_PACKET_SERVICE,
+ packet_service_remove, ps);
+
+ for (l = g_drivers; l; l = l->next) {
+ const struct ofono_packet_service_driver *drv = l->data;
+
+ if (g_strcmp0(drv->name, driver))
+ continue;
+
+ if (drv->probe(ps, vendor, data) < 0)
+ continue;
+
+ ps->driver = drv;
+ break;
+ }
+
+ ps->status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
+ ps->netreg_status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
+ ps->pid_map = idmap_new(MAX_CONTEXTS);
+
+ return ps;
+}
+
+static void netreg_watch(struct ofono_atom *atom,
+ enum ofono_atom_watch_condition cond,
+ void *data)
+{
+ struct ofono_packet_service *ps = data;
+
+ if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
+ ps_netreg_removed(ps);
+ return;
+ }
+
+ ps->netreg = __ofono_atom_get_data(atom);
+ ps->netreg_status = ofono_netreg_get_status(ps->netreg);
+ ps->status_watch = __ofono_netreg_add_status_watch(ps->netreg,
+ netreg_status_changed, ps, NULL);
+
+ ps_netreg_update(ps);
+}
+
+static gboolean load_context(struct ofono_packet_service *ps, const char *group)
+{
+ char *name = NULL;
+ char *typestr = NULL;
+ char *protostr = NULL;
+ char *username = NULL;
+ char *password = NULL;
+ char *apn = NULL;
+ char *msgproxy = NULL;
+ char *msgcenter = NULL;
+ gboolean ret = FALSE;
+ gboolean legacy = FALSE;
+ struct context *context;
+ enum ofono_packet_context_type type;
+ enum ofono_packet_proto proto;
+ unsigned int id;
+
+ if (sscanf(group, "context%d", &id) != 1) {
+ if (sscanf(group, "primarycontext%d", &id) != 1)
+ goto error;
+
+ legacy = TRUE;
+ }
+
+ if (id < 1 || id > MAX_CONTEXTS)
+ goto error;
+
+ name = g_key_file_get_string(ps->settings, group, "Name", NULL);
+ if (name == NULL)
+ goto error;
+
+ typestr = g_key_file_get_string(ps->settings, group, "Type", NULL);
+ if (typestr == NULL)
+ goto error;
+
+ if (packet_context_string_to_type(typestr, &type) == FALSE)
+ goto error;
+
+ protostr = g_key_file_get_string(ps->settings, group,
+ "Protocol", NULL);
+ if (protostr == NULL)
+ protostr = g_strdup("ip");
+
+ if (packet_proto_from_string(protostr, &proto) == FALSE)
+ goto error;
+
+ username = g_key_file_get_string(ps->settings, group,
+ "Username", NULL);
+ if (username == NULL)
+ goto error;
+
+ if (strlen(username) > OFONO_PS_MAX_USERNAME_LENGTH)
+ goto error;
+
+ password = g_key_file_get_string(ps->settings, group,
+ "Password", NULL);
+ if (password == NULL)
+ goto error;
+
+ if (strlen(password) > OFONO_PS_MAX_PASSWORD_LENGTH)
+ goto error;
+
+ apn = g_key_file_get_string(ps->settings, group,
+ "AccessPointName", NULL);
+ if (apn == NULL)
+ goto error;
+
+ if (strlen(apn) > OFONO_PS_MAX_APN_LENGTH)
+ goto error;
+
+ if (type == OFONO_PACKET_CONTEXT_TYPE_MMS) {
+ msgproxy = g_key_file_get_string(ps->settings, group,
+ "MessageProxy", NULL);
+
+ msgcenter = g_key_file_get_string(ps->settings, group,
+ "MessageCenter", NULL);
+ }
+
+ /*
+ * Accept empty (just created) APNs, but don't allow other
+ * invalid ones
+ */
+ if (apn[0] != '\0' && is_valid_apn(apn) == FALSE)
+ goto error;
+
+ context = context_create(ps, name, type);
+ if (context == NULL)
+ goto error;
+
+ idmap_take(ps->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;
+
+ if (msgproxy != NULL)
+ strcpy(context->message_proxy, msgproxy);
+
+ if (msgcenter != NULL)
+ strcpy(context->message_center, msgcenter);
+
+ if (context_dbus_register(context) == FALSE)
+ goto error;
+
+ ps->last_context_id = id;
+
+ ps->contexts = g_slist_append(ps->contexts, context);
+ ret = TRUE;
+
+ if (legacy) {
+ write_context_settings(ps, context);
+ g_key_file_remove_group(ps->settings, group, NULL);
+ }
+
+error:
+ g_free(name);
+ g_free(typestr);
+ g_free(protostr);
+ g_free(username);
+ g_free(password);
+ g_free(apn);
+ g_free(msgproxy);
+ g_free(msgcenter);
+
+ return ret;
+}
+
+static void ps_load_settings(struct ofono_packet_service *ps,
+ const char *imsi)
+{
+ GError *error;
+ gboolean legacy = FALSE;
+ char **groups;
+ int i;
+
+ ps->settings = storage_open(imsi, SETTINGS_STORE);
+
+ if (ps->settings == NULL)
+ return;
+
+ ps->imsi = g_strdup(imsi);
+
+ error = NULL;
+ ps->powered = g_key_file_get_boolean(ps->settings, SETTINGS_GROUP,
+ "Powered", &error);
+
+ /*
+ * If any error occurs, simply switch to defaults.
+ * Default to Powered = True
+ * and RoamingAllowed = False
+ */
+ if (error) {
+ g_error_free(error);
+ ps->powered = TRUE;
+ g_key_file_set_boolean(ps->settings, SETTINGS_GROUP,
+ "Powered", ps->powered);
+ }
+
+ error = NULL;
+ ps->roaming_allowed = g_key_file_get_boolean(ps->settings,
+ SETTINGS_GROUP,
+ "RoamingAllowed",
+ &error);
+
+ if (error) {
+ g_error_free(error);
+ ps->roaming_allowed = FALSE;
+ g_key_file_set_boolean(ps->settings, SETTINGS_GROUP,
+ "RoamingAllowed",
+ ps->roaming_allowed);
+ }
+
+ groups = g_key_file_get_groups(ps->settings, NULL);
+
+ for (i = 0; groups[i]; i++) {
+ if (g_str_equal(groups[i], SETTINGS_GROUP))
+ continue;
+
+ if (!g_str_has_prefix(groups[i], "context")) {
+ if (!g_str_has_prefix(groups[i], "primarycontext"))
+ goto remove;
+
+ legacy = TRUE;
+ }
+
+ if (load_context(ps, groups[i]) == TRUE)
+ continue;
+
+remove:
+ g_key_file_remove_group(ps->settings, groups[i], NULL);
+ }
+
+ g_strfreev(groups);
+
+ if (legacy)
+ storage_sync(imsi, SETTINGS_STORE, ps->settings);
+}
+
+static void provision_context(const struct ofono_ps_provision_data *ap,
+ struct ofono_packet_service *ps)
+{
+ unsigned int id;
+ struct context *context = NULL;
+
+ /* Sanity check */
+ if (ap == NULL)
+ return;
+
+ if (ap->name == NULL || strlen(ap->name) > MAX_CONTEXT_NAME_LENGTH)
+ return;
+
+ if (ap->apn == NULL || strlen(ap->apn) > OFONO_PS_MAX_APN_LENGTH)
+ return;
+
+ if (is_valid_apn(ap->apn) == FALSE)
+ return;
+
+ if (ap->username &&
+ strlen(ap->username) > OFONO_PS_MAX_USERNAME_LENGTH)
+ return;
+
+ if (ap->password &&
+ strlen(ap->password) > OFONO_PS_MAX_PASSWORD_LENGTH)
+ return;
+
+ if (ap->message_proxy &&
+ strlen(ap->message_proxy) > MAX_MESSAGE_PROXY_LENGTH)
+ return;
+
+ if (ap->message_center &&
+ strlen(ap->message_center) > MAX_MESSAGE_CENTER_LENGTH)
+ return;
+
+ if (ps->last_context_id)
+ id = idmap_alloc_next(ps->pid_map, ps->last_context_id);
+ else
+ id = idmap_alloc(ps->pid_map);
+
+ if (id > idmap_get_max(ps->pid_map))
+ return;
+
+ context = context_create(ps, ap->name, ap->type);
+ if (context == NULL) {
+ idmap_put(ps->pid_map, id);
+ return;
+ }
+
+ context->id = id;
+
+ if (ap->username != NULL)
+ strcpy(context->context.username, ap->username);
+
+ if (ap->password != NULL)
+ strcpy(context->context.password, ap->password);
+
+ strcpy(context->context.apn, ap->apn);
+ context->context.proto = ap->proto;
+
+ if (ap->type == OFONO_PACKET_CONTEXT_TYPE_MMS) {
+ if (ap->message_proxy != NULL)
+ strcpy(context->message_proxy, ap->message_proxy);
+
+ if (ap->message_center != NULL)
+ strcpy(context->message_center, ap->message_center);
+ }
+
+ if (context_dbus_register(context) == FALSE)
+ return;
+
+ ps->last_context_id = id;
+
+ if (ps->settings) {
+ write_context_settings(ps, context);
+ storage_sync(ps->imsi, SETTINGS_STORE, ps->settings);
+ }
+
+ ps->contexts = g_slist_append(ps->contexts, context);
+}
+
+static void provision_contexts(struct ofono_packet_service *ps, const char *mcc,
+ const char *mnc, const char *spn)
+{
+ struct ofono_ps_provision_data *settings;
+ int count;
+ int i;
+
+ if (__ofono_ps_provision_get_settings(mcc, mnc, spn,
+ &settings, &count) == FALSE) {
+ ofono_warn("Provisioning failed");
+ return;
+ }
+
+ for (i = 0; i < count; i++)
+ provision_context(&settings[i], ps);
+
+ __ofono_ps_provision_free_settings(settings, count);
+}
+
+static void ofono_packet_service_finish_register(
+ struct ofono_packet_service *ps)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct ofono_modem *modem = __ofono_atom_get_modem(ps->atom);
+ const char *path = __ofono_atom_get_path(ps->atom);
+
+ if (ps->contexts == NULL) /* Automatic provisioning failed */
+ add_context(ps, NULL, OFONO_PACKET_CONTEXT_TYPE_INTERNET);
+
+ if (!g_dbus_register_interface(conn, path,
+ OFONO_CONNECTION_MANAGER_INTERFACE,
+ manager_methods, manager_signals, NULL,
+ ps, NULL)) {
+ ofono_error("Could not create %s interface",
+ OFONO_CONNECTION_MANAGER_INTERFACE);
+
+ free_contexts(ps);
+ return;
+ }
+
+ ofono_modem_add_interface(modem,
+ OFONO_CONNECTION_MANAGER_INTERFACE);
+
+ ps->netreg_watch = __ofono_modem_add_atom_watch(modem,
+ OFONO_ATOM_TYPE_NETREG,
+ netreg_watch, ps, NULL);
+
+ __ofono_atom_register(ps->atom, packet_service_unregister);
+}
+
+static void sim_spn_read_cb(int ok, int length, int record,
+ const unsigned char *data,
+ int record_length, void *userdata)
+{
+ struct ofono_packet_service *ps = userdata;
+ char *spn = NULL;
+ struct ofono_atom *sim_atom;
+ struct ofono_sim *sim = NULL;
+
+ if (ok)
+ spn = sim_string_to_utf8(data + 1, length - 1);
+
+ sim_atom = __ofono_modem_find_atom(__ofono_atom_get_modem(ps->atom),
+ OFONO_ATOM_TYPE_SIM);
+ if (sim_atom) {
+ sim = __ofono_atom_get_data(sim_atom);
+ provision_contexts(ps, ofono_sim_get_mcc(sim),
+ ofono_sim_get_mnc(sim), spn);
+ }
+
+ g_free(spn);
+ ofono_packet_service_finish_register(ps);
+}
+
+void ofono_packet_service_register(struct ofono_packet_service *ps)
+{
+ struct ofono_modem *modem = __ofono_atom_get_modem(ps->atom);
+ struct ofono_atom *sim_atom;
+ struct ofono_sim *sim = NULL;
+
+ sim_atom = __ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_SIM);
+
+ if (sim_atom) {
+ const char *imsi;
+ sim = __ofono_atom_get_data(sim_atom);
+
+ imsi = ofono_sim_get_imsi(sim);
+ ps_load_settings(ps, imsi);
+ }
+
+ if (ps->contexts == NULL && sim != NULL) {
+ /* Get Service Provider Name from SIM for provisioning */
+ ps->sim_context = ofono_sim_context_create(sim);
+
+ if (ofono_sim_read(ps->sim_context, SIM_EFSPN_FILEID,
+ OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ sim_spn_read_cb, ps) >= 0)
+ return;
+ }
+
+ ofono_packet_service_finish_register(ps);
+}
+
+void ofono_packet_service_remove(struct ofono_packet_service *ps)
+{
+ __ofono_atom_free(ps->atom);
+}
+
+void ofono_packet_service_set_data(struct ofono_packet_service *ps,
+ void *data)
+{
+ ps->driver_data = data;
+}
+
+void *ofono_packet_service_get_data(struct ofono_packet_service *ps)
+{
+ return ps->driver_data;
+}
diff --git a/src/ps-provision.c b/src/ps-provision.c
new file mode 100644
index 0000000..aa4621f
--- /dev/null
+++ b/src/ps-provision.c
@@ -0,0 +1,101 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib.h>
+#include "ofono.h"
+
+static GSList *g_drivers = NULL;
+
+void __ofono_ps_provision_free_settings(
+ struct ofono_ps_provision_data *settings,
+ int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ g_free(settings[i].name);
+ g_free(settings[i].apn);
+ g_free(settings[i].username);
+ g_free(settings[i].password);
+ g_free(settings[i].message_proxy);
+ g_free(settings[i].message_center);
+ }
+
+ g_free(settings);
+}
+
+ofono_bool_t __ofono_ps_provision_get_settings(const char *mcc,
+ const char *mnc, const char *spn,
+ struct ofono_ps_provision_data **settings,
+ int *count)
+{
+ GSList *d;
+
+ if (mcc == NULL || strlen(mcc) == 0 || mnc == NULL || strlen(mnc) == 0)
+ return FALSE;
+
+ for (d = g_drivers; d != NULL; d = d->next) {
+ const struct ofono_ps_provision_driver *driver = d->data;
+
+ if (driver->get_settings == NULL)
+ continue;
+
+ DBG("Calling provisioning plugin '%s'", driver->name);
+
+ if (driver->get_settings(mcc, mnc, spn, settings, count) < 0)
+ continue;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gint compare_priority(gconstpointer a, gconstpointer b)
+{
+ const struct ofono_ps_provision_driver *plugin1 = a;
+ const struct ofono_ps_provision_driver *plugin2 = b;
+
+ return plugin2->priority - plugin1->priority;
+}
+
+int ofono_ps_provision_driver_register(
+ const struct ofono_ps_provision_driver *driver)
+{
+ DBG("driver: %p name: %s", driver, driver->name);
+
+ g_drivers = g_slist_insert_sorted(g_drivers, (void *) driver,
+ compare_priority);
+ return 0;
+}
+
+void ofono_ps_provision_driver_unregister(
+ const struct ofono_ps_provision_driver *driver)
+{
+ DBG("driver: %p name: %s", driver, driver->name);
+
+ g_drivers = g_slist_remove(g_drivers, driver);
+}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 05/20] atmodem: add generalised packet source
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (3 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 04/20] build: add generalised packet files Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 06/20] phonesim: use generalised packet source files Vijay Nayani
` (14 subsequent siblings)
19 siblings, 0 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 22101 bytes --]
packet-context.c and packet-service.c file contents
are same as gprs-context.c and gprs.c. Just
renamed for a generalised solution.
---
Makefile.am | 2 +
drivers/atmodem/atmodem.c | 4 +
drivers/atmodem/atmodem.h | 6 +
drivers/atmodem/packet-context.c | 329 +++++++++++++++++++++++++++++
drivers/atmodem/packet-service.c | 424 ++++++++++++++++++++++++++++++++++++++
5 files changed, 765 insertions(+), 0 deletions(-)
create mode 100644 drivers/atmodem/packet-context.c
create mode 100644 drivers/atmodem/packet-service.c
diff --git a/Makefile.am b/Makefile.am
index c1cc701..249c6c9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -181,6 +181,8 @@ builtin_sources += $(gatchat_sources) \
drivers/atmodem/atutil.c \
drivers/atmodem/gprs.c \
drivers/atmodem/gprs-context.c \
+ drivers/atmodem/packet-service.c \
+ drivers/atmodem/packet-context.c \
drivers/atmodem/sim-auth.c \
drivers/atmodem/gnss.c
diff --git a/drivers/atmodem/atmodem.c b/drivers/atmodem/atmodem.c
index be93f41..28a5d4b 100644
--- a/drivers/atmodem/atmodem.c
+++ b/drivers/atmodem/atmodem.c
@@ -50,6 +50,8 @@ static int atmodem_init(void)
at_call_volume_init();
at_gprs_init();
at_gprs_context_init();
+ at_packet_service_init();
+ at_packet_context_init();
at_sim_auth_init();
at_gnss_init();
@@ -75,6 +77,8 @@ static void atmodem_exit(void)
at_call_volume_exit();
at_gprs_exit();
at_gprs_context_exit();
+ at_packet_service_exit();
+ at_packet_context_exit();
at_gnss_exit();
}
diff --git a/drivers/atmodem/atmodem.h b/drivers/atmodem/atmodem.h
index 41f480f..067e998 100644
--- a/drivers/atmodem/atmodem.h
+++ b/drivers/atmodem/atmodem.h
@@ -69,6 +69,12 @@ extern void at_gprs_exit(void);
extern void at_gprs_context_init(void);
extern void at_gprs_context_exit(void);
+extern void at_packet_service_init(void);
+extern void at_packet_service_exit(void);
+
+extern void at_packet_context_init(void);
+extern void at_packet_context_exit(void);
+
extern void at_sim_auth_init(void);
extern void at_sim_auth_exit(void);
diff --git a/drivers/atmodem/packet-context.c b/drivers/atmodem/packet-context.c
new file mode 100644
index 0000000..1182212
--- /dev/null
+++ b/drivers/atmodem/packet-context.c
@@ -0,0 +1,329 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ *
+ * 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/packet-context.h>
+
+#include "gatchat.h"
+#include "gatresult.h"
+#include "gatppp.h"
+
+#include "atmodem.h"
+
+#define TUN_SYSFS_DIR "/sys/devices/virtual/misc/tun"
+
+#define STATIC_IP_NETMASK "255.255.255.255"
+
+static const char *none_prefix[] = { NULL };
+
+enum state {
+ STATE_IDLE,
+ STATE_ENABLING,
+ STATE_DISABLING,
+ STATE_ACTIVE,
+};
+
+struct packet_context_data {
+ GAtChat *chat;
+ unsigned int active_context;
+ char username[OFONO_PS_MAX_USERNAME_LENGTH + 1];
+ char password[OFONO_PS_MAX_PASSWORD_LENGTH + 1];
+ GAtPPP *ppp;
+ enum state state;
+ ofono_packet_context_cb_t cb;
+ void *cb_data; /* Callback data */
+};
+
+static void ppp_debug(const char *str, void *data)
+{
+ ofono_info("%s: %s", (const char *) data, str);
+}
+
+static void ppp_connect(const char *interface, const char *local,
+ const char *remote,
+ const char *dns1, const char *dns2,
+ gpointer user_data)
+{
+ struct ofono_packet_context *pc = user_data;
+ struct packet_context_data *pcd = ofono_packet_context_get_data(pc);
+ const char *dns[3];
+
+ DBG("");
+
+ dns[0] = dns1;
+ dns[1] = dns2;
+ dns[2] = 0;
+
+ ofono_info("IP: %s", local);
+ ofono_info("DNS: %s, %s", dns1, dns2);
+
+ pcd->state = STATE_ACTIVE;
+ ofono_packet_context_set_interface(pc, interface);
+ ofono_packet_context_set_ipv4_address(pc, local, TRUE);
+ ofono_packet_context_set_ipv4_netmask(pc, STATIC_IP_NETMASK);
+ ofono_packet_context_set_ipv4_dns_servers(pc, dns);
+
+ CALLBACK_WITH_SUCCESS(pcd->cb, pcd->cb_data);
+}
+
+static void ppp_disconnect(GAtPPPDisconnectReason reason, gpointer user_data)
+{
+ struct ofono_packet_context *pc = user_data;
+ struct packet_context_data *pcd = ofono_packet_context_get_data(pc);
+
+ DBG("");
+
+ g_at_ppp_unref(pcd->ppp);
+ pcd->ppp = NULL;
+
+ switch (pcd->state) {
+ case STATE_ENABLING:
+ CALLBACK_WITH_FAILURE(pcd->cb, pcd->cb_data);
+ break;
+ case STATE_DISABLING:
+ CALLBACK_WITH_SUCCESS(pcd->cb, pcd->cb_data);
+ break;
+ default:
+ ofono_packet_context_deactivated(pc, pcd->active_context);
+ break;
+ }
+
+ pcd->active_context = 0;
+ pcd->state = STATE_IDLE;
+ /*
+ * If the channel of pcd->chat is NULL, it might cause
+ * packet_context_remove get called and the packet context will be
+ * removed.
+ */
+ g_at_chat_resume(pcd->chat);
+}
+
+static gboolean setup_ppp(struct ofono_packet_context *pc)
+{
+ struct packet_context_data *pcd = ofono_packet_context_get_data(pc);
+ GAtIO *io;
+
+ DBG("");
+
+ io = g_at_chat_get_io(pcd->chat);
+
+ g_at_chat_suspend(pcd->chat);
+
+ /* open ppp */
+ pcd->ppp = g_at_ppp_new_from_io(io);
+
+ if (pcd->ppp == NULL) {
+ g_at_chat_resume(pcd->chat);
+ return FALSE;
+ }
+
+ if (getenv("OFONO_PPP_DEBUG"))
+ g_at_ppp_set_debug(pcd->ppp, ppp_debug, "PPP");
+
+ g_at_ppp_set_credentials(pcd->ppp, pcd->username, pcd->password);
+
+ /* set connect and disconnect callbacks */
+ g_at_ppp_set_connect_function(pcd->ppp, ppp_connect, pc);
+ g_at_ppp_set_disconnect_function(pcd->ppp, ppp_disconnect, pc);
+
+ /* open the ppp connection */
+ g_at_ppp_open(pcd->ppp);
+
+ return TRUE;
+}
+
+static void at_cgdata_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_packet_context *pc = user_data;
+ struct packet_context_data *pcd = ofono_packet_context_get_data(pc);
+
+ DBG("ok %d", ok);
+
+ if (!ok) {
+ struct ofono_error error;
+
+ ofono_info("Unable to enter data state");
+
+ pcd->active_context = 0;
+ pcd->state = STATE_IDLE;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+ pcd->cb(&error, pcd->cb_data);
+ return;
+ }
+
+ setup_ppp(pc);
+}
+
+static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_packet_context *pc = user_data;
+ struct packet_context_data *pcd = ofono_packet_context_get_data(pc);
+ char buf[64];
+
+ DBG("ok %d", ok);
+
+ if (!ok) {
+ struct ofono_error error;
+
+ pcd->active_context = 0;
+ pcd->state = STATE_IDLE;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+ pcd->cb(&error, pcd->cb_data);
+ return;
+ }
+
+ sprintf(buf, "AT+CGDATA=\"PPP\",%u", pcd->active_context);
+ if (g_at_chat_send(pcd->chat, buf, none_prefix,
+ at_cgdata_cb, pc, NULL) > 0)
+ return;
+
+ pcd->active_context = 0;
+ pcd->state = STATE_IDLE;
+
+ CALLBACK_WITH_FAILURE(pcd->cb, pcd->cb_data);
+}
+
+static void at_packet_context_activate(struct ofono_packet_context *pc,
+ const struct ofono_packet_context_param *ctx,
+ ofono_packet_context_cb_t cb, void *data)
+{
+ struct packet_context_data *pcd = ofono_packet_context_get_data(pc);
+ char buf[OFONO_PS_MAX_APN_LENGTH + 128];
+ int len;
+
+ /* IPv6 support not implemented */
+ if (ctx->proto != OFONO_PACKET_PROTO_IP)
+ goto error;
+
+ DBG("cid %u", ctx->cid);
+
+ pcd->active_context = ctx->cid;
+ pcd->cb = cb;
+ pcd->cb_data = data;
+ memcpy(pcd->username, ctx->username, sizeof(ctx->username));
+ memcpy(pcd->password, ctx->password, sizeof(ctx->password));
+
+ pcd->state = STATE_ENABLING;
+
+ len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IP\"", ctx->cid);
+
+ if (ctx->apn)
+ snprintf(buf + len, sizeof(buf) - len - 3, ",\"%s\"",
+ ctx->apn);
+
+ if (g_at_chat_send(pcd->chat, buf, none_prefix,
+ at_cgdcont_cb, pc, NULL) > 0)
+ return;
+
+error:
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void at_packet_context_deactivate(struct ofono_packet_context *pc,
+ unsigned int cid,
+ ofono_packet_context_cb_t cb, void *data)
+{
+ struct packet_context_data *pcd = ofono_packet_context_get_data(pc);
+
+ DBG("cid %u", cid);
+
+ pcd->state = STATE_DISABLING;
+ pcd->cb = cb;
+ pcd->cb_data = data;
+
+ g_at_ppp_shutdown(pcd->ppp);
+}
+
+static int at_packet_context_probe(struct ofono_packet_context *pc,
+ unsigned int vendor, void *data)
+{
+ GAtChat *chat = data;
+ struct packet_context_data *pcd;
+ struct stat st;
+
+ DBG("");
+
+ if (stat(TUN_SYSFS_DIR, &st) < 0) {
+ ofono_error("Missing support for TUN/TAP devices");
+ return -ENODEV;
+ }
+
+ pcd = g_try_new0(struct packet_context_data, 1);
+ if (pcd == NULL)
+ return -ENOMEM;
+
+ pcd->chat = g_at_chat_clone(chat);
+
+ ofono_packet_context_set_data(pc, pcd);
+
+ return 0;
+}
+
+static void at_packet_context_remove(struct ofono_packet_context *pc)
+{
+ struct packet_context_data *pcd = ofono_packet_context_get_data(pc);
+
+ DBG("");
+
+ if (pcd->state != STATE_IDLE && pcd->ppp) {
+ g_at_ppp_unref(pcd->ppp);
+ g_at_chat_resume(pcd->chat);
+ }
+
+ ofono_packet_context_set_data(pc, NULL);
+
+ g_at_chat_unref(pcd->chat);
+ g_free(pcd);
+}
+
+static struct ofono_packet_context_driver driver = {
+ .name = "atmodem",
+ .probe = at_packet_context_probe,
+ .remove = at_packet_context_remove,
+ .activate_context = at_packet_context_activate,
+ .deactivate_context = at_packet_context_deactivate,
+};
+
+void at_packet_context_init(void)
+{
+ ofono_packet_context_driver_register(&driver);
+}
+
+void at_packet_context_exit(void)
+{
+ ofono_packet_context_driver_unregister(&driver);
+}
diff --git a/drivers/atmodem/packet-service.c b/drivers/atmodem/packet-service.c
new file mode 100644
index 0000000..9999d9d
--- /dev/null
+++ b/drivers/atmodem/packet-service.c
@@ -0,0 +1,424 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ * Copyright (C) 2010 ST-Ericsson AB.
+ *
+ * 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/packet-service.h>
+#include <ofono/packet-context.h>
+
+#include "gatchat.h"
+#include "gatresult.h"
+
+#include "atmodem.h"
+#include "vendor.h"
+
+static const char *cgreg_prefix[] = { "+CGREG:", NULL };
+static const char *cgdcont_prefix[] = { "+CGDCONT:", NULL };
+static const char *none_prefix[] = { NULL };
+
+struct packet_service_data {
+ GAtChat *chat;
+ int default_cid;
+ int default_context_type;
+ unsigned int vendor;
+};
+
+static void at_cgatt_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_packet_service_cb_t cb = cbd->cb;
+ struct ofono_error error;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ cb(&error, cbd->data);
+}
+
+static void at_packet_service_set_attached(struct ofono_packet_service *ps,
+ int attached,
+ ofono_packet_service_cb_t cb,
+ void *data)
+{
+ struct packet_service_data *psd = ofono_packet_service_get_data(ps);
+ struct cb_data *cbd = cb_data_new(cb, data);
+ char buf[64];
+
+ snprintf(buf, sizeof(buf), "AT+CGATT=%i", attached ? 1 : 0);
+
+ if (g_at_chat_send(psd->chat, buf, none_prefix,
+ at_cgatt_cb, cbd, g_free) > 0)
+ return;
+
+ g_free(cbd);
+
+ CALLBACK_WITH_FAILURE(cb, data);
+}
+
+static void at_cgreg_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_packet_service_status_cb_t cb = cbd->cb;
+ struct ofono_error error;
+ int status;
+ struct packet_service_data *psd = cbd->user;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (!ok) {
+ cb(&error, -1, cbd->data);
+ return;
+ }
+
+ if (at_util_parse_reg(result, "+CGREG:", NULL, &status,
+ NULL, NULL, NULL, psd->vendor) == FALSE) {
+ CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+ return;
+ }
+
+ cb(&error, status, cbd->data);
+}
+
+static void at_packet_service_registration_status(
+ struct ofono_packet_service *ps,
+ ofono_packet_service_status_cb_t cb,
+ void *data)
+{
+ struct packet_service_data *psd = ofono_packet_service_get_data(ps);
+ struct cb_data *cbd = cb_data_new(cb, data);
+
+ cbd->user = psd;
+
+ switch (psd->vendor) {
+ case OFONO_VENDOR_GOBI:
+ /*
+ * Send *CNTI=0 to find out the current tech, it will be
+ * intercepted in gobi_cnti_notify in network registration
+ */
+ g_at_chat_send(psd->chat, "AT*CNTI=0", none_prefix,
+ NULL, NULL, NULL);
+ break;
+ case OFONO_VENDOR_NOVATEL:
+ /*
+ * Send $CNTI=0 to find out the current tech, it will be
+ * intercepted in nw_cnti_notify in network registration
+ */
+ g_at_chat_send(psd->chat, "AT$CNTI=0", none_prefix,
+ NULL, NULL, NULL);
+ break;
+ }
+
+ if (g_at_chat_send(psd->chat, "AT+CGREG?", cgreg_prefix,
+ at_cgreg_cb, cbd, g_free) > 0)
+ return;
+
+ g_free(cbd);
+
+ CALLBACK_WITH_FAILURE(cb, -1, data);
+}
+
+static void cgreg_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_packet_service *ps = user_data;
+ int status;
+ struct packet_service_data *psd = ofono_packet_service_get_data(ps);
+
+ if (at_util_parse_reg_unsolicited(result, "+CGREG:", &status,
+ NULL, NULL, NULL, psd->vendor) == FALSE)
+ return;
+
+ ofono_packet_service_status_notify(ps, status);
+}
+
+static void cgev_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_packet_service *ps = user_data;
+ GAtResultIter iter;
+ const char *event;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CGEV:"))
+ return;
+
+ if (!g_at_result_iter_next_unquoted_string(&iter, &event))
+ return;
+
+ if (g_str_equal(event, "NW DETACH") ||
+ g_str_equal(event, "ME DETACH")) {
+ ofono_packet_service_detached_notify(ps);
+ return;
+ }
+}
+
+static void xdatastat_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_packet_service *ps = user_data;
+ GAtResultIter iter;
+ int stat;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+XDATASTAT:"))
+ return;
+
+ if (!g_at_result_iter_next_number(&iter, &stat))
+
+ DBG("stat %d", stat);
+
+ switch (stat) {
+ case 0:
+ ofono_packet_service_suspend_notify(ps,
+ PACKET_SERVICE_SUSPENDED_UNKNOWN_CAUSE);
+ break;
+ case 1:
+ ofono_packet_service_resume_notify(ps);
+ break;
+ }
+}
+
+static void cpsb_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_packet_service *ps = user_data;
+ GAtResultIter iter;
+ gint bearer;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CPSB:"))
+ return;
+
+ if (!g_at_result_iter_next_number(&iter, NULL))
+ return;
+
+ if (!g_at_result_iter_next_number(&iter, &bearer))
+ return;
+
+ ofono_packet_service_bearer_notify(ps, bearer);
+}
+
+static void packet_service_initialized(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_packet_service *ps = user_data;
+ struct packet_service_data *psd = ofono_packet_service_get_data(ps);
+
+ g_at_chat_register(psd->chat, "+CGEV:", cgev_notify, FALSE, ps, NULL);
+ g_at_chat_register(psd->chat, "+CGREG:", cgreg_notify,
+ FALSE, ps, NULL);
+ g_at_chat_register(psd->chat, "+CPSB:", cpsb_notify, FALSE, ps, NULL);
+
+ g_at_chat_send(psd->chat, "AT+CPSB=1", none_prefix, NULL, NULL, NULL);
+
+ switch (psd->vendor) {
+ case OFONO_VENDOR_IFX:
+ /* Register for packet service suspend notifications */
+ g_at_chat_register(psd->chat, "+XDATASTAT:", xdatastat_notify,
+ FALSE, ps, NULL);
+ g_at_chat_send(psd->chat, "AT+XDATASTAT=1", none_prefix,
+ NULL, NULL, NULL);
+ break;
+ }
+
+ ofono_packet_service_register(ps);
+}
+
+static void at_cgreg_test_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_packet_service *ps = user_data;
+ struct packet_service_data *psd = ofono_packet_service_get_data(ps);
+ gint range[2];
+ GAtResultIter iter;
+ int cgreg1 = 0;
+ int cgreg2 = 0;
+ const char *cmd;
+
+ if (!ok)
+ goto error;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CGREG:"))
+ goto error;
+
+ if (!g_at_result_iter_open_list(&iter))
+ goto error;
+
+ while (g_at_result_iter_next_range(&iter, &range[0], &range[1])) {
+ if (1 >= range[0] && 1 <= range[1])
+ cgreg1 = 1;
+ if (2 >= range[0] && 2 <= range[1])
+ cgreg2 = 1;
+ }
+
+ g_at_result_iter_close_list(&iter);
+
+ if (cgreg2)
+ cmd = "AT+CGREG=2";
+ else if (cgreg1)
+ cmd = "AT+CGREG=1";
+ else
+ goto error;
+
+ g_at_chat_send(psd->chat, cmd, none_prefix, NULL, NULL, NULL);
+ g_at_chat_send(psd->chat, "AT+CGAUTO=0", none_prefix, NULL, NULL, NULL);
+
+ switch (psd->vendor) {
+ case OFONO_VENDOR_MBM:
+ /* Ericsson MBM and ST-E modems don't support AT+CGEREP=2,1 */
+ g_at_chat_send(psd->chat, "AT+CGEREP=1,0", none_prefix,
+ packet_service_initialized, ps, NULL);
+ break;
+ case OFONO_VENDOR_NOKIA:
+ /* Nokia data cards don't support AT+CGEREP=1,0 either */
+ g_at_chat_send(psd->chat, "AT+CGEREP=1", none_prefix,
+ packet_service_initialized, ps, NULL);
+ break;
+ default:
+ g_at_chat_send(psd->chat, "AT+CGEREP=2,1", none_prefix,
+ packet_service_initialized, ps, NULL);
+ break;
+ }
+
+ return;
+
+error:
+ ofono_info("GPRS not supported on this device");
+ ofono_packet_service_remove(ps);
+}
+
+static void at_cgdcont_test_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_packet_service *ps = user_data;
+ struct packet_service_data *psd = ofono_packet_service_get_data(ps);
+ GAtResultIter iter;
+ int min, max;
+ const char *pdp_type;
+ gboolean found = FALSE;
+
+ if (!ok)
+ goto error;
+
+ g_at_result_iter_init(&iter, result);
+
+ while (!found && g_at_result_iter_next(&iter, "+CGDCONT:")) {
+ gboolean in_list = FALSE;
+
+ if (!g_at_result_iter_open_list(&iter))
+ continue;
+
+ if (g_at_result_iter_next_range(&iter, &min, &max) == FALSE)
+ continue;
+
+ if (!g_at_result_iter_close_list(&iter))
+ continue;
+
+ if (g_at_result_iter_open_list(&iter))
+ in_list = TRUE;
+
+ if (!g_at_result_iter_next_string(&iter, &pdp_type))
+ continue;
+
+ if (in_list && !g_at_result_iter_close_list(&iter))
+ continue;
+
+ /* We look for IP PDPs */
+ if (g_str_equal(pdp_type, "IP"))
+ found = TRUE;
+ }
+
+ if (found == FALSE)
+ goto error;
+
+ ofono_packet_service_set_cid_range(ps, min, max);
+
+ g_at_chat_send(psd->chat, "AT+CGREG=?", cgreg_prefix,
+ at_cgreg_test_cb, ps, NULL);
+
+ return;
+
+error:
+ ofono_info("Packet service not supported on this device");
+ ofono_packet_service_remove(ps);
+}
+
+static int at_packet_service_probe(struct ofono_packet_service *ps,
+ unsigned int vendor, void *data)
+{
+ GAtChat *chat = data;
+ struct packet_service_data *psd;
+
+ psd = g_try_new0(struct packet_service_data, 1);
+ if (psd == NULL)
+ return -ENOMEM;
+
+ psd->chat = g_at_chat_clone(chat);
+ psd->vendor = vendor;
+
+ ofono_packet_service_set_data(ps, psd);
+
+ g_at_chat_send(psd->chat, "AT+CGDCONT=?", cgdcont_prefix,
+ at_cgdcont_test_cb, ps, NULL);
+
+ return 0;
+}
+
+static void at_packet_service_remove(struct ofono_packet_service *ps)
+{
+ struct packet_service_data *psd = ofono_packet_service_get_data(ps);
+
+ ofono_packet_service_set_data(ps, NULL);
+
+ g_at_chat_unref(psd->chat);
+ g_free(psd);
+}
+
+static struct ofono_packet_service_driver driver = {
+ .name = "atmodem",
+ .probe = at_packet_service_probe,
+ .remove = at_packet_service_remove,
+ .set_attached = at_packet_service_set_attached,
+ .attached_status = at_packet_service_registration_status,
+};
+
+void at_packet_service_init(void)
+{
+ ofono_packet_service_driver_register(&driver);
+}
+
+void at_packet_service_exit(void)
+{
+ ofono_packet_service_driver_unregister(&driver);
+}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 06/20] phonesim: use generalised packet source files
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (4 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 05/20] atmodem: add generalised packet source Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 07/20] common: add preferred_ue_mode enum Vijay Nayani
` (13 subsequent siblings)
19 siblings, 0 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 9252 bytes --]
---
plugins/phonesim.c | 120 ++++++++++++++++++++++++++--------------------------
1 files changed, 60 insertions(+), 60 deletions(-)
diff --git a/plugins/phonesim.c b/plugins/phonesim.c
index 1a6703d..13f942e 100644
--- a/plugins/phonesim.c
+++ b/plugins/phonesim.c
@@ -56,8 +56,8 @@
#include <ofono/sms.h>
#include <ofono/ussd.h>
#include <ofono/voicecall.h>
-#include <ofono/gprs.h>
-#include <ofono/gprs-context.h>
+#include <ofono/packet-service.h>
+#include <ofono/packet-context.h>
#include <ofono/gnss.h>
#include <drivers/atmodem/vendor.h>
@@ -75,18 +75,18 @@ struct phonesim_data {
gboolean use_mux;
};
-struct gprs_context_data {
+struct packet_context_data {
GAtChat *chat;
char *interface;
- enum ofono_gprs_proto proto;
+ enum ofono_packet_proto proto;
};
static void at_cgact_up_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
- ofono_gprs_context_cb_t cb = cbd->cb;
- struct ofono_gprs_context *gc = cbd->user;
- struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+ ofono_packet_context_cb_t cb = cbd->cb;
+ struct ofono_packet_context *pc = cbd->user;
+ struct packet_context_data *pcd = ofono_packet_context_get_data(pc);
struct ofono_error error;
decode_at_error(&error, g_at_result_final_response(result));
@@ -94,16 +94,16 @@ static void at_cgact_up_cb(gboolean ok, GAtResult *result, gpointer user_data)
if (ok == FALSE)
goto done;
- ofono_gprs_context_set_interface(gc, gcd->interface);
+ ofono_packet_context_set_interface(pc, pcd->interface);
- if (gcd->proto == OFONO_GPRS_PROTO_IP ||
- gcd->proto == OFONO_GPRS_PROTO_IPV4V6)
- ofono_gprs_context_set_ipv4_address(gc, NULL, FALSE);
+ if (pcd->proto == OFONO_PACKET_PROTO_IP ||
+ pcd->proto == OFONO_PACKET_PROTO_IPV4V6)
+ ofono_packet_context_set_ipv4_address(pc, NULL, FALSE);
- if (gcd->proto == OFONO_GPRS_PROTO_IPV6 ||
- gcd->proto == OFONO_GPRS_PROTO_IPV4V6) {
- ofono_gprs_context_set_ipv6_address(gc, "fe80::1");
- ofono_gprs_context_set_ipv6_prefix_length(gc, 10);
+ if (pcd->proto == OFONO_PACKET_PROTO_IPV6 ||
+ pcd->proto == OFONO_PACKET_PROTO_IPV4V6) {
+ ofono_packet_context_set_ipv6_address(pc, "fe80::1");
+ ofono_packet_context_set_ipv6_prefix_length(pc, 10);
}
done:
@@ -113,37 +113,37 @@ done:
static void at_cgact_down_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct cb_data *cbd = user_data;
- ofono_gprs_context_cb_t cb = cbd->cb;
+ ofono_packet_context_cb_t cb = cbd->cb;
struct ofono_error error;
decode_at_error(&error, g_at_result_final_response(result));
cb(&error, cbd->data);
}
-static void phonesim_activate_primary(struct ofono_gprs_context *gc,
- const struct ofono_gprs_primary_context *ctx,
- ofono_gprs_context_cb_t cb, void *data)
+static void phonesim_activate_context(struct ofono_packet_context *pc,
+ const struct ofono_packet_context_param *ctx,
+ ofono_packet_context_cb_t cb, void *data)
{
- struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+ struct packet_context_data *pcd = ofono_packet_context_get_data(pc);
struct cb_data *cbd = cb_data_new(cb, data);
- char buf[OFONO_GPRS_MAX_APN_LENGTH + 128];
+ char buf[OFONO_PS_MAX_APN_LENGTH + 128];
int len = 0;
- cbd->user = gc;
- gcd->proto = ctx->proto;
+ cbd->user = pc;
+ pcd->proto = ctx->proto;
switch (ctx->proto) {
- case OFONO_GPRS_PROTO_IP:
+ case OFONO_PACKET_PROTO_IP:
len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IP\"",
ctx->cid);
break;
- case OFONO_GPRS_PROTO_IPV6:
+ case OFONO_PACKET_PROTO_IPV6:
len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IPV6\"",
ctx->cid);
break;
- case OFONO_GPRS_PROTO_IPV4V6:
+ case OFONO_PACKET_PROTO_IPV4V6:
len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IPV4V6\"",
ctx->cid);
break;
@@ -154,11 +154,11 @@ static void phonesim_activate_primary(struct ofono_gprs_context *gc,
ctx->apn);
/* Assume always succeeds */
- if (g_at_chat_send(gcd->chat, buf, none_prefix, NULL, NULL, NULL) == 0)
+ if (g_at_chat_send(pcd->chat, buf, none_prefix, NULL, NULL, NULL) == 0)
goto error;
sprintf(buf, "AT+CGACT=1,%u", ctx->cid);
- if (g_at_chat_send(gcd->chat, buf, none_prefix,
+ if (g_at_chat_send(pcd->chat, buf, none_prefix,
at_cgact_up_cb, cbd, g_free) > 0)
return;
@@ -168,19 +168,19 @@ error:
CALLBACK_WITH_FAILURE(cb, data);
}
-static void phonesim_deactivate_primary(struct ofono_gprs_context *gc,
+static void phonesim_deactivate_context(struct ofono_packet_context *pc,
unsigned int id,
- ofono_gprs_context_cb_t cb, void *data)
+ ofono_packet_context_cb_t cb, void *data)
{
- struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+ struct packet_context_data *pcd = ofono_packet_context_get_data(pc);
struct cb_data *cbd = cb_data_new(cb, data);
char buf[128];
- cbd->user = gc;
+ cbd->user = pc;
snprintf(buf, sizeof(buf), "AT+CGACT=0,%u", id);
- if (g_at_chat_send(gcd->chat, buf, none_prefix,
+ if (g_at_chat_send(pcd->chat, buf, none_prefix,
at_cgact_down_cb, cbd, g_free) > 0)
return;
@@ -189,36 +189,36 @@ static void phonesim_deactivate_primary(struct ofono_gprs_context *gc,
CALLBACK_WITH_FAILURE(cb, data);
}
-static int phonesim_context_probe(struct ofono_gprs_context *gc,
+static int phonesim_context_probe(struct ofono_packet_context *pc,
unsigned int vendor, void *data)
{
GAtChat *chat = data;
- struct gprs_context_data *gcd;
+ struct packet_context_data *pcd;
- gcd = g_try_new0(struct gprs_context_data, 1);
- if (gcd == NULL)
+ pcd = g_try_new0(struct packet_context_data, 1);
+ if (pcd == NULL)
return -ENOMEM;
- gcd->chat = g_at_chat_clone(chat);
- gcd->interface = g_strdup_printf("dummy%d", next_iface++);
+ pcd->chat = g_at_chat_clone(chat);
+ pcd->interface = g_strdup_printf("dummy%d", next_iface++);
- ofono_gprs_context_set_data(gc, gcd);
+ ofono_packet_context_set_data(pc, pcd);
return 0;
}
-static void phonesim_context_remove(struct ofono_gprs_context *gc)
+static void phonesim_context_remove(struct ofono_packet_context *pc)
{
- struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+ struct packet_context_data *pcd = ofono_packet_context_get_data(pc);
DBG("");
- ofono_gprs_context_set_data(gc, NULL);
+ ofono_packet_context_set_data(pc, NULL);
- g_at_chat_unref(gcd->chat);
- g_free(gcd->interface);
+ g_at_chat_unref(pcd->chat);
+ g_free(pcd->interface);
- g_free(gcd);
+ g_free(pcd);
}
static void phonesim_ctm_support_cb(gboolean ok, GAtResult *result,
@@ -340,12 +340,12 @@ static void phonesim_ctm_set(struct ofono_ctm *ctm, ofono_bool_t enable,
g_free(cbd);
}
-static struct ofono_gprs_context_driver context_driver = {
+static struct ofono_packet_context_driver context_driver = {
.name = "phonesim",
.probe = phonesim_context_probe,
.remove = phonesim_context_remove,
- .activate_primary = phonesim_activate_primary,
- .deactivate_primary = phonesim_deactivate_primary,
+ .activate_context = phonesim_activate_context,
+ .deactivate_context = phonesim_deactivate_context,
};
static struct ofono_ctm_driver ctm_driver = {
@@ -667,8 +667,8 @@ static void phonesim_post_online(struct ofono_modem *modem)
{
struct phonesim_data *data = ofono_modem_get_data(modem);
struct ofono_message_waiting *mw;
- struct ofono_gprs *gprs;
- struct ofono_gprs_context *gc1, *gc2;
+ struct ofono_packet_service *ps;
+ struct ofono_packet_context *pc1, *pc2;
DBG("%p", modem);
@@ -689,15 +689,15 @@ static void phonesim_post_online(struct ofono_modem *modem)
if (!data->calypso)
ofono_cbs_create(modem, 0, "atmodem", data->chat);
- gprs = ofono_gprs_create(modem, 0, "atmodem", data->chat);
+ ps = ofono_packet_service_create(modem, 0, "atmodem", data->chat);
- gc1 = ofono_gprs_context_create(modem, 0, "phonesim", data->chat);
- if (gprs && gc1)
- ofono_gprs_add_context(gprs, gc1);
+ pc1 = ofono_packet_context_create(modem, 0, "phonesim", data->chat);
+ if (ps && pc1)
+ ofono_packet_service_add_context(ps, pc1);
- gc2 = ofono_gprs_context_create(modem, 0, "phonesim", data->chat);
- if (gprs && gc2)
- ofono_gprs_add_context(gprs, gc2);
+ pc2 = ofono_packet_context_create(modem, 0, "phonesim", data->chat);
+ if (ps && pc2)
+ ofono_packet_service_add_context(ps, pc2);
mw = ofono_message_waiting_create(modem);
if (mw)
@@ -816,7 +816,7 @@ static int phonesim_init(void)
if (err < 0)
return err;
- ofono_gprs_context_driver_register(&context_driver);
+ ofono_packet_context_driver_register(&context_driver);
ofono_ctm_driver_register(&ctm_driver);
@@ -840,7 +840,7 @@ static void phonesim_exit(void)
ofono_ctm_driver_unregister(&ctm_driver);
- ofono_gprs_context_driver_unregister(&context_driver);
+ ofono_packet_context_driver_unregister(&context_driver);
ofono_modem_driver_unregister(&phonesim_driver);
}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 07/20] common: add preferred_ue_mode enum
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (5 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 06/20] phonesim: use generalised packet source files Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 08/20] include: add set preferred ue mode api Vijay Nayani
` (12 subsequent siblings)
19 siblings, 0 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 658 bytes --]
---
src/common.h | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/src/common.h b/src/common.h
index 5fc3ead..cfc620c 100644
--- a/src/common.h
+++ b/src/common.h
@@ -41,6 +41,14 @@ enum network_registration_status {
NETWORK_REGISTRATION_STATUS_ROAMING = 5,
};
+/* 27.007 section 10.1.28 <mode> */
+enum preferred_ue_mode {
+ PREFERRED_UE_MODE_PS_DATA_CENTRIC = 0,
+ PREFERRED_UE_MODE_CS_PS_VOICE_CENTRIC = 1,
+ PREFERRED_UE_MODE_CS_PS_DATA_CENTRIC = 2,
+ PREFERRED_UE_MODE_PS_VOICE_CENTRIC = 3,
+};
+
/* 27.007 Section 7.6 */
enum clip_validity {
CLIP_VALIDITY_VALID = 0,
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 08/20] include: add set preferred ue mode api
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (6 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 07/20] common: add preferred_ue_mode enum Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 19:34 ` Denis Kenzior
2011-04-11 10:20 ` [RFC PATCH 09/20] modem: add preferred ue mode handling Vijay Nayani
` (11 subsequent siblings)
19 siblings, 1 reply; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 673 bytes --]
---
include/modem.h | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/include/modem.h b/include/modem.h
index 5a34370..e416f50 100644
--- a/include/modem.h
+++ b/include/modem.h
@@ -51,6 +51,8 @@ void ofono_modem_reset(struct ofono_modem *modem);
void ofono_modem_set_powered(struct ofono_modem *modem, ofono_bool_t powered);
ofono_bool_t ofono_modem_get_powered(struct ofono_modem *modem);
+void ofono_modem_set_preferred_ue_mode(struct ofono_modem *modem, int mode);
+
ofono_bool_t ofono_modem_get_online(struct ofono_modem *modem);
ofono_bool_t ofono_modem_get_emergency_mode(struct ofono_modem *modem);
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 09/20] modem: add preferred ue mode handling
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (7 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 08/20] include: add set preferred ue mode api Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 19:36 ` Denis Kenzior
2011-04-11 10:20 ` [RFC PATCH 10/20] doc: add PreferredMode property to modem Vijay Nayani
` (10 subsequent siblings)
19 siblings, 1 reply; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 2578 bytes --]
---
src/modem.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 44 insertions(+), 0 deletions(-)
diff --git a/src/modem.c b/src/modem.c
index a8b8744..bb0374a 100644
--- a/src/modem.c
+++ b/src/modem.c
@@ -75,6 +75,7 @@ struct ofono_modem {
char *lock_owner;
guint lock_watch;
guint timeout;
+ int pref_mode;
ofono_bool_t online;
struct ofono_watchlist *online_watches;
struct ofono_watchlist *powered_watches;
@@ -119,6 +120,22 @@ struct modem_property {
void *value;
};
+static const char *preferred_ue_mode_to_string(int mode)
+{
+ switch (mode) {
+ case PREFERRED_UE_MODE_PS_DATA_CENTRIC:
+ return "PS mode 2";
+ case PREFERRED_UE_MODE_CS_PS_VOICE_CENTRIC:
+ return "PS/CS mode 1";
+ case PREFERRED_UE_MODE_CS_PS_DATA_CENTRIC:
+ return "PS/CS mode 2";
+ case PREFERRED_UE_MODE_PS_VOICE_CENTRIC:
+ return "PS mode 1";
+ }
+
+ return "unknown";
+}
+
unsigned int __ofono_modem_callid_next(struct ofono_modem *modem)
{
unsigned int i;
@@ -748,6 +765,14 @@ void __ofono_modem_append_properties(struct ofono_modem *modem,
ofono_dbus_dict_append(dict, "Emergency", DBUS_TYPE_BOOLEAN,
&emergency);
+ if (modem->pref_mode != -1) {
+ const char *mode = preferred_ue_mode_to_string(
+ modem->pref_mode);
+
+ ofono_dbus_dict_append(dict, "PreferredMode",
+ DBUS_TYPE_STRING, &mode);
+ }
+
devinfo_atom = __ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_DEVINFO);
/* We cheat a little here and don't check the registered status */
@@ -1181,6 +1206,24 @@ ofono_bool_t ofono_modem_get_powered(struct ofono_modem *modem)
return modem->powered;
}
+void ofono_modem_set_preferred_ue_mode(struct ofono_modem *modem, int mode)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *strmode;
+
+ if (modem->pref_mode == mode)
+ return;
+
+ modem->pref_mode = mode;
+
+ strmode = preferred_ue_mode_to_string(mode);
+
+ ofono_dbus_signal_property_changed(conn, modem->path,
+ OFONO_MODEM_INTERFACE,
+ "PreferredMode",
+ DBUS_TYPE_STRING, &strmode);
+}
+
static gboolean trigger_interface_update(void *data)
{
struct ofono_modem *modem = data;
@@ -1777,6 +1820,7 @@ struct ofono_modem *ofono_modem_create(const char *name, const char *type)
modem->driver_type = g_strdup(type);
modem->properties = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, unregister_property);
+ modem->pref_mode = -1;
g_modem_list = g_slist_prepend(g_modem_list, modem);
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 10/20] doc: add PreferredMode property to modem
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (8 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 09/20] modem: add preferred ue mode handling Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 19:27 ` Denis Kenzior
2011-04-11 10:20 ` [RFC PATCH 11/20] modem: generalise feature map table Vijay Nayani
` (9 subsequent siblings)
19 siblings, 1 reply; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1152 bytes --]
---
doc/modem-api.txt | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/doc/modem-api.txt b/doc/modem-api.txt
index fa400a2..c79bffa 100644
--- a/doc/modem-api.txt
+++ b/doc/modem-api.txt
@@ -54,6 +54,24 @@ Properties boolean Powered [readwrite]
modem. The Emergency is true if an emergency call or
related operation is currently active.
+ string PreferredMode [readonly, optional]
+
+ Preferred UE mode setting. A UE attached for EPS services
+ shall operate in one of the following operation modes:
+
+ "PS mode 2" UE registers only to EPS
+ services, and UE's usage setting
+ is "data centric".
+ "CS/PS mode 1" UE registers to both EPS and
+ non-EPS services, and UE's usage
+ setting is "voice centric".
+ "CS/PS mode 2" UE registers to both EPS and
+ non-EPS services, and UE's usage
+ setting is "data centric".
+ "PS mode 1" UE registers only to EPS
+ services, and UE's usage setting
+ is "voice centric".
+
string Name [readonly, optional]
Friendly name of the modem device.
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 11/20] modem: generalise feature map table
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (9 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 10/20] doc: add PreferredMode property to modem Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 12/20] packet: add context type default Vijay Nayani
` (8 subsequent siblings)
19 siblings, 0 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1375 bytes --]
Only change is "gprs" to "packet".
---
src/modem.c | 20 ++++++++++----------
1 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/modem.c b/src/modem.c
index bb0374a..aecb35a 100644
--- a/src/modem.c
+++ b/src/modem.c
@@ -1260,16 +1260,16 @@ static const struct {
const char *interface;
const char *feature;
} feature_map[] = {
- { OFONO_NETWORK_REGISTRATION_INTERFACE, "net" },
- { OFONO_RADIO_SETTINGS_INTERFACE, "rat" },
- { OFONO_CELL_BROADCAST_INTERFACE, "cbs" },
- { OFONO_MESSAGE_MANAGER_INTERFACE, "sms" },
- { OFONO_SIM_MANAGER_INTERFACE, "sim" },
- { OFONO_STK_INTERFACE, "stk" },
- { OFONO_SUPPLEMENTARY_SERVICES_INTERFACE, "ussd" },
- { OFONO_CONNECTION_MANAGER_INTERFACE, "gprs" },
- { OFONO_TEXT_TELEPHONY_INTERFACE, "tty" },
- { OFONO_LOCATION_REPORTING_INTERFACE, "gps" },
+ { OFONO_NETWORK_REGISTRATION_INTERFACE, "net" },
+ { OFONO_RADIO_SETTINGS_INTERFACE, "rat" },
+ { OFONO_CELL_BROADCAST_INTERFACE, "cbs" },
+ { OFONO_MESSAGE_MANAGER_INTERFACE, "sms" },
+ { OFONO_SIM_MANAGER_INTERFACE, "sim" },
+ { OFONO_STK_INTERFACE, "stk" },
+ { OFONO_SUPPLEMENTARY_SERVICES_INTERFACE, "ussd" },
+ { OFONO_CONNECTION_MANAGER_INTERFACE, "packet" },
+ { OFONO_TEXT_TELEPHONY_INTERFACE, "tty" },
+ { OFONO_LOCATION_REPORTING_INTERFACE, "gps" },
{ },
};
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 12/20] packet: add context type default
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (10 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 11/20] modem: generalise feature map table Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 19:40 ` Denis Kenzior
2011-04-11 10:20 ` [RFC PATCH 13/20] include: add get technology api Vijay Nayani
` (7 subsequent siblings)
19 siblings, 1 reply; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1608 bytes --]
OFONO_PACKET_CONTEXT_TYPE_DEFAULT is added to
ofono_packet_context_type and conversion functions
are updated for the same.
---
include/packet-context.h | 1 +
src/packet.c | 7 +++++++
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/include/packet-context.h b/include/packet-context.h
index 44fd69f..02a5c42 100644
--- a/include/packet-context.h
+++ b/include/packet-context.h
@@ -47,6 +47,7 @@ enum ofono_packet_context_type {
OFONO_PACKET_CONTEXT_TYPE_MMS,
OFONO_PACKET_CONTEXT_TYPE_WAP,
OFONO_PACKET_CONTEXT_TYPE_IMS,
+ OFONO_PACKET_CONTEXT_TYPE_DEFAULT,
};
struct ofono_packet_context_param {
diff --git a/src/packet.c b/src/packet.c
index 1acbf76..6077617 100644
--- a/src/packet.c
+++ b/src/packet.c
@@ -153,6 +153,8 @@ static const char *packet_context_default_name(enum ofono_packet_context_type ty
return "WAP";
case OFONO_PACKET_CONTEXT_TYPE_IMS:
return "IMS";
+ case OFONO_PACKET_CONTEXT_TYPE_DEFAULT:
+ return "Default";
}
return NULL;
@@ -172,6 +174,8 @@ static const char *packet_context_type_to_string(
return "wap";
case OFONO_PACKET_CONTEXT_TYPE_IMS:
return "ims";
+ case OFONO_PACKET_CONTEXT_TYPE_DEFAULT:
+ return "default";
}
return NULL;
@@ -192,6 +196,9 @@ static gboolean packet_context_string_to_type(const char *str,
} else if (g_str_equal(str, "ims")) {
*out = OFONO_PACKET_CONTEXT_TYPE_IMS;
return TRUE;
+ } else if (g_str_equal(str, "default")) {
+ *out = OFONO_PACKET_CONTEXT_TYPE_DEFAULT;
+ return TRUE;
}
return FALSE;
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 13/20] include: add get technology api
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (11 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 12/20] packet: add context type default Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 14/20] packet: add get technology api implementation Vijay Nayani
` (6 subsequent siblings)
19 siblings, 0 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 658 bytes --]
Added for the driver to be aware of the registered
technology
---
include/packet-service.h | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/include/packet-service.h b/include/packet-service.h
index bc5eceb..d8cfd21 100644
--- a/include/packet-service.h
+++ b/include/packet-service.h
@@ -88,6 +88,8 @@ void ofono_packet_service_set_cid_range(struct ofono_packet_service *ps,
void ofono_packet_service_add_context(struct ofono_packet_service *ps,
struct ofono_packet_context *pc);
+int ofono_packet_service_get_technology(struct ofono_packet_service *ps);
+
#ifdef __cplusplus
}
#endif
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 14/20] packet: add get technology api implementation
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (12 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 13/20] include: add get technology api Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 15/20] include: add default context param and api Vijay Nayani
` (5 subsequent siblings)
19 siblings, 0 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 2213 bytes --]
---
src/packet.c | 16 +++++++++++++++-
1 files changed, 15 insertions(+), 1 deletions(-)
diff --git a/src/packet.c b/src/packet.c
index 6077617..ed8e1ae 100644
--- a/src/packet.c
+++ b/src/packet.c
@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
+ * Copyright 2011 EB(Elektrobit).
*
* 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
@@ -75,6 +76,7 @@ struct ofono_packet_service {
unsigned int last_context_id;
struct idmap *cid_map;
int netreg_status;
+ int netreg_access_tech;
struct ofono_netreg *netreg;
unsigned int netreg_watch;
unsigned int status_watch;
@@ -1537,10 +1539,11 @@ static void netreg_status_changed(int status, int lac, int ci, int tech,
DBG("%d", status);
- if (ps->netreg_status == status)
+ if (ps->netreg_status == status && ps->netreg_access_tech == tech)
return;
ps->netreg_status = status;
+ ps->netreg_access_tech = tech;
ps_netreg_update(ps);
}
@@ -2522,6 +2525,7 @@ struct ofono_packet_service *ofono_packet_service_create(
ps->status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
ps->netreg_status = NETWORK_REGISTRATION_STATUS_UNKNOWN;
+ ps->netreg_access_tech = -1;
ps->pid_map = idmap_new(MAX_CONTEXTS);
return ps;
@@ -2540,6 +2544,7 @@ static void netreg_watch(struct ofono_atom *atom,
ps->netreg = __ofono_atom_get_data(atom);
ps->netreg_status = ofono_netreg_get_status(ps->netreg);
+ ps->netreg_access_tech = ofono_netreg_get_technology(ps->netreg);
ps->status_watch = __ofono_netreg_add_status_watch(ps->netreg,
netreg_status_changed, ps, NULL);
@@ -2944,3 +2949,12 @@ void *ofono_packet_service_get_data(struct ofono_packet_service *ps)
{
return ps->driver_data;
}
+
+int ofono_packet_service_get_technology(struct ofono_packet_service *ps)
+{
+ if (ps->netreg_status != NETWORK_REGISTRATION_STATUS_ROAMING &&
+ ps->netreg_status != NETWORK_REGISTRATION_STATUS_REGISTERED)
+ return -1;
+
+ return ps->netreg_access_tech;
+}
\ No newline at end of file
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 15/20] include: add default context param and api
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (13 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 14/20] packet: add get technology api implementation Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 16/20] packet: add default context implementation Vijay Nayani
` (4 subsequent siblings)
19 siblings, 0 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1146 bytes --]
---
include/packet-service.h | 14 ++++++++++++++
1 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/include/packet-service.h b/include/packet-service.h
index d8cfd21..0e80ae8 100644
--- a/include/packet-service.h
+++ b/include/packet-service.h
@@ -32,6 +32,16 @@ extern "C" {
struct ofono_packet_service;
struct ofono_packet_context;
+struct ofono_default_context_param {
+ int cid;
+ int proto;
+ const char *apn;
+ const char *address;
+ const char *gateway;
+ const char **dns;
+ const char *interface;
+};
+
typedef void (*ofono_packet_service_status_cb_t)(
const struct ofono_error *error,
int status, void *data);
@@ -88,6 +98,10 @@ void ofono_packet_service_set_cid_range(struct ofono_packet_service *ps,
void ofono_packet_service_add_context(struct ofono_packet_service *ps,
struct ofono_packet_context *pc);
+void ofono_packet_service_default_context_notify(
+ struct ofono_packet_service *ps,
+ struct ofono_default_context_param *dc);
+
int ofono_packet_service_get_technology(struct ofono_packet_service *ps);
#ifdef __cplusplus
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 16/20] packet: add default context implementation
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (14 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 15/20] include: add default context param and api Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 17/20] atmodem: add lte specific functions Vijay Nayani
` (3 subsequent siblings)
19 siblings, 0 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 3661 bytes --]
Changes include context creation and signalling of
dbus property property changes.
---
src/packet.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 95 insertions(+), 1 deletions(-)
diff --git a/src/packet.c b/src/packet.c
index ed8e1ae..f8a76c6 100644
--- a/src/packet.c
+++ b/src/packet.c
@@ -2950,6 +2950,100 @@ void *ofono_packet_service_get_data(struct ofono_packet_service *ps)
return ps->driver_data;
}
+void ofono_packet_service_default_context_notify(
+ struct ofono_packet_service *ps,
+ struct ofono_default_context_param *dc)
+{
+ DBusConnection *conn = ofono_dbus_get_connection();
+ struct context *ctx;
+ struct context_settings *settings;
+ GSList *l;
+ dbus_bool_t value;
+
+ /*
+ * Assumption: context id for default EPS context will have value
+ * outside the ranges indicated in the test form of the command
+ * +CGDCONT.
+ */
+ ctx = context_create(ps, "default", OFONO_PACKET_CONTEXT_TYPE_DEFAULT);
+ if (ctx == NULL) {
+ ofono_error("Unable to allocate memory for default context");
+ return;
+ }
+
+ ctx->id = dc->cid;
+ ctx->active = TRUE;
+ ctx->context.proto = dc->proto;
+ strcpy(ctx->context.apn, dc->apn);
+
+ for (l = ctx->ps->context_drivers; l; l = l->next) {
+ struct ofono_packet_context *pc = l->data;
+
+ if (pc->inuse == TRUE)
+ continue;
+
+ if (pc->driver == NULL)
+ continue;
+
+ if (pc->driver->activate_context == NULL ||
+ pc->driver->deactivate_context == NULL)
+ continue;
+
+ if (pc->type != OFONO_PACKET_CONTEXT_TYPE_ANY &&
+ pc->type != ctx->type)
+ continue;
+
+ ctx->context_driver = pc;
+ ctx->context_driver->inuse = TRUE;
+
+ if (ctx->context.proto == OFONO_PACKET_PROTO_IPV4V6 ||
+ ctx->context.proto == OFONO_PACKET_PROTO_IP)
+ pc->settings->ipv4 = g_new0(struct ipv4_settings, 1);
+
+ if (ctx->context.proto == OFONO_PACKET_PROTO_IPV4V6 ||
+ ctx->context.proto == OFONO_PACKET_PROTO_IPV6)
+ pc->settings->ipv6 = g_new0(struct ipv6_settings, 1);
+
+ ofono_packet_context_set_type(pc, ctx->type);
+ ofono_packet_context_set_interface(pc, dc->interface);
+
+ if (pc->settings->ipv4) {
+ ofono_packet_context_set_ipv4_address(pc, dc->address,
+ TRUE);
+ ofono_packet_context_set_ipv4_gateway(pc, dc->gateway);
+ ofono_packet_context_set_ipv4_dns_servers(pc, dc->dns);
+ }
+
+ if (pc->settings->ipv6) {
+ ofono_packet_context_set_ipv6_address(pc, dc->address);
+ ofono_packet_context_set_ipv6_gateway(pc, dc->gateway);
+ ofono_packet_context_set_ipv6_dns_servers(pc, dc->dns);
+ }
+
+ break;
+ }
+
+ settings = ctx->context_driver->settings;
+
+ /*
+ * If context dbus registration fails or unregistered, context id is
+ * put back into the idmap which should not be done for default
+ * context if the context id doesn't fall within range supplied by
+ * +CGDCONT. TODO: This needs to be addressed.
+ */
+ if (!context_dbus_register(ctx)) {
+ ofono_error("Unable to register default context");
+ return;
+ }
+
+ ps->contexts = g_slist_append(ps->contexts, ctx);
+
+ value = ctx->active;
+ ofono_dbus_signal_property_changed(conn, ctx->path,
+ OFONO_CONNECTION_CONTEXT_INTERFACE,
+ "Active", DBUS_TYPE_BOOLEAN, &value);
+}
+
int ofono_packet_service_get_technology(struct ofono_packet_service *ps)
{
if (ps->netreg_status != NETWORK_REGISTRATION_STATUS_ROAMING &&
@@ -2957,4 +3051,4 @@ int ofono_packet_service_get_technology(struct ofono_packet_service *ps)
return -1;
return ps->netreg_access_tech;
-}
\ No newline at end of file
+}
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 17/20] atmodem: add lte specific functions
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (15 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 16/20] packet: add default context implementation Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 19:54 ` Denis Kenzior
2011-04-12 3:43 ` Marcel Holtmann
2011-04-11 10:20 ` [RFC PATCH 18/20] phonesim: Add cemode query implementation Vijay Nayani
` (2 subsequent siblings)
19 siblings, 2 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 9529 bytes --]
Changes include: Registration of CEREG events,
registration status query based on registered
technology, handling of ME PDN ACT CGEV event,
reading of default context params and notification
of default context params to the core.
---
drivers/atmodem/packet-service.c | 238 ++++++++++++++++++++++++++++++++++++++
1 files changed, 238 insertions(+), 0 deletions(-)
diff --git a/drivers/atmodem/packet-service.c b/drivers/atmodem/packet-service.c
index 9999d9d..b766a3b 100644
--- a/drivers/atmodem/packet-service.c
+++ b/drivers/atmodem/packet-service.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
* Copyright (C) 2010 ST-Ericsson AB.
+ * Copyright 2011 EB(Elektrobit).
*
* 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
@@ -40,17 +41,23 @@
#include "gatchat.h"
#include "gatresult.h"
+#include "common.h"
+
#include "atmodem.h"
#include "vendor.h"
static const char *cgreg_prefix[] = { "+CGREG:", NULL };
static const char *cgdcont_prefix[] = { "+CGDCONT:", NULL };
+static const char *cereg_prefix[] = { "+CEREG:", NULL };
+static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
static const char *none_prefix[] = { NULL };
struct packet_service_data {
GAtChat *chat;
int default_cid;
int default_context_type;
+ int cid_min;
+ int cid_max;
unsigned int vendor;
};
@@ -109,6 +116,134 @@ static void at_cgreg_cb(gboolean ok, GAtResult *result, gpointer user_data)
cb(&error, status, cbd->data);
}
+static void at_cereg_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct cb_data *cbd = user_data;
+ ofono_packet_service_status_cb_t cb = cbd->cb;
+ struct ofono_error error;
+ int status;
+ struct packet_service_data *psd = cbd->user;
+
+ decode_at_error(&error, g_at_result_final_response(result));
+
+ if (!ok) {
+ cb(&error, -1, cbd->data);
+ return;
+ }
+
+ if (at_util_parse_reg(result, "+CEREG:", NULL, &status,
+ NULL, NULL, NULL, psd->vendor) == FALSE) {
+ CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
+ return;
+ }
+
+ cb(&error, status, cbd->data);
+}
+
+static void at_cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_packet_service *ps = user_data;
+ struct packet_service_data *psd = ofono_packet_service_get_data(ps);
+ GAtResultIter iter;
+ int cid, bearer_id;
+ const char *apn, *address, *gateway, *dns1, *dns2;
+ const char *dns[3];
+ struct ofono_default_context_param *param;
+
+ if (!ok)
+ return;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (g_at_result_iter_next(&iter, "+CGCONTRDP:") == FALSE)
+ return;
+
+ if (g_at_result_iter_next_number(&iter, &cid) == FALSE)
+ return;
+
+ if (g_at_result_iter_next_number(&iter, &bearer_id) == FALSE)
+ return;
+
+ if (g_at_result_iter_next_string(&iter, &apn) == FALSE)
+ return;
+
+ if (g_at_result_iter_next_string(&iter, &address) == FALSE)
+ goto out;
+
+ if (g_at_result_iter_next_string(&iter, &gateway) == FALSE)
+ goto out;
+
+ if (g_at_result_iter_next_string(&iter, &dns1) == FALSE)
+ goto out;
+
+ if (g_at_result_iter_next_string(&iter, &dns2) == FALSE)
+ goto out;
+
+ dns[0] = dns1;
+ dns[1] = dns2;
+ dns[2] = 0;
+
+out:
+ param = g_new0(struct ofono_default_context_param, 1);
+ if (param == NULL)
+ return;
+
+ param->cid = cid;
+ param->proto = psd->default_context_type;
+ param->apn = apn;
+ param->address = address;
+ param->gateway = gateway;
+ param->dns = dns;
+
+ ofono_packet_service_default_context_notify(ps, param);
+
+ g_free(param);
+ param = NULL;
+}
+
+static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_packet_service *ps = user_data;
+ struct packet_service_data *psd = ofono_packet_service_get_data(ps);
+ GAtResultIter iter;
+ int cid;
+ const char *pdp_type;
+ char buf[64];
+ gboolean found = FALSE;
+
+ if (!ok)
+ return;
+
+ g_at_result_iter_init(&iter, result);
+
+ while (!found && g_at_result_iter_next(&iter, "+CGDCONT:")) {
+ if (g_at_result_iter_next_number(&iter, &cid) == FALSE)
+ return;
+
+ if (psd->default_cid != cid)
+ continue;
+
+ g_at_result_iter_next_string(&iter, &pdp_type);
+
+ found = TRUE;
+ }
+
+ if (found == FALSE)
+ return;
+
+ if (g_str_equal(pdp_type, "IP"))
+ psd->default_context_type = OFONO_PACKET_PROTO_IP;
+ else if (g_str_equal(pdp_type, "IPV6"))
+ psd->default_context_type = OFONO_PACKET_PROTO_IPV6;
+ else if (g_str_equal(pdp_type, "IPV4V6"))
+ psd->default_context_type = OFONO_PACKET_PROTO_IPV4V6;
+
+ snprintf(buf, sizeof(buf), "AT+CGCONTRDP=%i", psd->default_cid);
+
+ g_at_chat_send(psd->chat, buf, cgcontrdp_prefix, at_cgcontrdp_cb,
+ ps, NULL);
+}
+
static void at_packet_service_registration_status(
struct ofono_packet_service *ps,
ofono_packet_service_status_cb_t cb,
@@ -138,6 +273,13 @@ static void at_packet_service_registration_status(
break;
}
+ if (ofono_packet_service_get_technology(ps) ==
+ ACCESS_TECHNOLOGY_EUTRAN) {
+ if (g_at_chat_send(psd->chat, "AT+CEREG?", cereg_prefix,
+ at_cereg_cb, cbd, g_free) > 0)
+ return;
+ }
+
if (g_at_chat_send(psd->chat, "AT+CGREG?", cgreg_prefix,
at_cgreg_cb, cbd, g_free) > 0)
return;
@@ -160,9 +302,23 @@ static void cgreg_notify(GAtResult *result, gpointer user_data)
ofono_packet_service_status_notify(ps, status);
}
+static void cereg_notify(GAtResult *result, gpointer user_data)
+{
+ struct ofono_packet_service *ps = user_data;
+ int status;
+ struct packet_service_data *psd = ofono_packet_service_get_data(ps);
+
+ if (at_util_parse_reg_unsolicited(result, "+CEREG:", &status,
+ NULL, NULL, NULL, psd->vendor) == FALSE)
+ return;
+
+ ofono_packet_service_status_notify(ps, status);
+}
+
static void cgev_notify(GAtResult *result, gpointer user_data)
{
struct ofono_packet_service *ps = user_data;
+ struct packet_service_data *psd = ofono_packet_service_get_data(ps);
GAtResultIter iter;
const char *event;
@@ -179,6 +335,35 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
ofono_packet_service_detached_notify(ps);
return;
}
+
+ if (g_str_has_prefix(event, "ME PDN ACT")) {
+ /*
+ * As per 27.007, this even it sent when the mobile termination
+ * has activated a context. The context represents a PDN
+ * connection in LTE or a Primary PDP context in GSM/UMTS.
+ * The <cid> for this context is provided to the TE. This event
+ * is sent either in result of explicit context activation
+ * request (+CGACT), or in result of implicit context activation
+ * request associated to attach request (+CGATT=1).
+ */
+ int cid;
+
+ cid = g_ascii_strtoll(&event[11], NULL, 0);
+
+ /*
+ * Assumption: context id for default EPS context will have
+ * value outside the ranges indicated in the test form of
+ * the command +CGDCONT.
+ */
+ if (cid >= psd->cid_min && cid <= psd->cid_max)
+ return;
+
+ psd->default_cid = cid;
+ g_at_chat_send(psd->chat, "AT+CGDCONT?", cgdcont_prefix,
+ at_cgdcont_cb, ps, NULL);
+
+ return;
+ }
}
static void xdatastat_notify(GAtResult *result, gpointer user_data)
@@ -236,6 +421,8 @@ static void packet_service_initialized(gboolean ok, GAtResult *result,
g_at_chat_register(psd->chat, "+CGEV:", cgev_notify, FALSE, ps, NULL);
g_at_chat_register(psd->chat, "+CGREG:", cgreg_notify,
FALSE, ps, NULL);
+ g_at_chat_register(psd->chat, "+CEREG:", cereg_notify,
+ FALSE, ps, NULL);
g_at_chat_register(psd->chat, "+CPSB:", cpsb_notify, FALSE, ps, NULL);
g_at_chat_send(psd->chat, "AT+CPSB=1", none_prefix, NULL, NULL, NULL);
@@ -318,6 +505,52 @@ error:
ofono_packet_service_remove(ps);
}
+static void at_cereg_test_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_packet_service *ps = user_data;
+ struct packet_service_data *psd = ofono_packet_service_get_data(ps);
+ gint range[2];
+ GAtResultIter iter;
+ int cereg1 = 0;
+ int cereg2 = 0;
+ const char *cmd;
+
+ if (!ok)
+ goto error;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (!g_at_result_iter_next(&iter, "+CEREG:"))
+ goto error;
+
+ if (!g_at_result_iter_open_list(&iter))
+ goto error;
+
+ while (g_at_result_iter_next_range(&iter, &range[0], &range[1])) {
+ if (1 >= range[0] && 1 <= range[1])
+ cereg1 = 1;
+ if (2 >= range[0] && 2 <= range[1])
+ cereg2 = 1;
+ }
+
+ g_at_result_iter_close_list(&iter);
+
+ if (cereg2)
+ cmd = "AT+CEREG=2";
+ else if (cereg1)
+ cmd = "AT+CEREG=1";
+ else
+ goto error;
+
+ g_at_chat_send(psd->chat, cmd, none_prefix, NULL, NULL, NULL);
+
+ return;
+
+error:
+ ofono_info("EPS not supported on this device");
+}
+
static void at_cgdcont_test_cb(gboolean ok, GAtResult *result,
gpointer user_data)
{
@@ -362,11 +595,16 @@ static void at_cgdcont_test_cb(gboolean ok, GAtResult *result,
if (found == FALSE)
goto error;
+ psd->cid_min = min;
+ psd->cid_max = max;
ofono_packet_service_set_cid_range(ps, min, max);
g_at_chat_send(psd->chat, "AT+CGREG=?", cgreg_prefix,
at_cgreg_test_cb, ps, NULL);
+ g_at_chat_send(psd->chat, "AT+CEREG=?", cereg_prefix,
+ at_cereg_test_cb, ps, NULL);
+
return;
error:
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 18/20] phonesim: Add cemode query implementation
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (16 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 17/20] atmodem: add lte specific functions Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 19/20] phonesim: atoms creation based on UE mode Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 20/20] modem: Add netreg watch for tech switch Vijay Nayani
19 siblings, 0 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 2103 bytes --]
---
plugins/phonesim.c | 34 +++++++++++++++++++++++++++++++++-
1 files changed, 33 insertions(+), 1 deletions(-)
diff --git a/plugins/phonesim.c b/plugins/phonesim.c
index 13f942e..0727baf 100644
--- a/plugins/phonesim.c
+++ b/plugins/phonesim.c
@@ -66,6 +66,7 @@
static const char *none_prefix[] = { NULL };
static const char *ptty_prefix[] = { "+PTTY:", NULL };
+static const char *cemode_prefix[] = { "+CEMODE:", NULL };
static int next_iface = 0;
struct phonesim_data {
@@ -73,6 +74,7 @@ struct phonesim_data {
GAtChat *chat;
gboolean calypso;
gboolean use_mux;
+ int pref_ue_mode;
};
struct packet_context_data {
@@ -419,6 +421,31 @@ static void crst_notify(GAtResult *result, gpointer user_data)
g_idle_add(phonesim_reset, user_data);
}
+static void cemode_read_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct phonesim_data *data = ofono_modem_get_data(modem);
+ GAtResultIter iter;
+ int mode;
+
+ if (!ok)
+ goto out;
+
+ g_at_result_iter_init(&iter, result);
+
+ if (g_at_result_iter_next(&iter, "+CEMODE:") == FALSE)
+ goto out;
+
+ if (g_at_result_iter_next_number(&iter, &mode) == FALSE)
+ goto out;
+
+ data->pref_ue_mode = mode;
+ ofono_modem_set_preferred_ue_mode(modem, mode);
+
+out:
+ ofono_modem_set_powered(modem, TRUE);
+}
+
static void phonesim_disconnected(gpointer user_data)
{
struct ofono_modem *modem = user_data;
@@ -529,6 +556,8 @@ static int phonesim_enable(struct ofono_modem *modem)
return -ENOMEM;
}
+ data->pref_ue_mode = -1;
+
if (data->calypso)
syntax = g_at_syntax_new_gsm_permissive();
else
@@ -574,7 +603,10 @@ static int phonesim_enable(struct ofono_modem *modem)
g_at_chat_register(data->chat, "+CRST:",
crst_notify, FALSE, modem, NULL);
- return 0;
+ g_at_chat_send(data->chat, "AT+CEMODE?", cemode_prefix,
+ cemode_read_cb, modem, NULL);
+
+ return -EINPROGRESS;
}
static void set_online_cb(gboolean ok, GAtResult *result, gpointer user_data)
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 19/20] phonesim: atoms creation based on UE mode
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (17 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 18/20] phonesim: Add cemode query implementation Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 20/20] modem: Add netreg watch for tech switch Vijay Nayani
19 siblings, 0 replies; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 3708 bytes --]
---
plugins/phonesim.c | 42 +++++++++++++++++++++++++++++++-----------
1 files changed, 31 insertions(+), 11 deletions(-)
diff --git a/plugins/phonesim.c b/plugins/phonesim.c
index 0727baf..8e3e928 100644
--- a/plugins/phonesim.c
+++ b/plugins/phonesim.c
@@ -64,6 +64,8 @@
#include <drivers/atmodem/sim-poll.h>
#include <drivers/atmodem/atutil.h>
+#include "common.h"
+
static const char *none_prefix[] = { NULL };
static const char *ptty_prefix[] = { "+PTTY:", NULL };
static const char *cemode_prefix[] = { "+CEMODE:", NULL };
@@ -667,11 +669,16 @@ static void phonesim_pre_sim(struct ofono_modem *modem)
ofono_devinfo_create(modem, 0, "atmodem", data->chat);
sim = ofono_sim_create(modem, 0, "atmodem", data->chat);
+ if (data->pref_ue_mode == PREFERRED_UE_MODE_PS_VOICE_CENTRIC ||
+ data->pref_ue_mode == PREFERRED_UE_MODE_PS_DATA_CENTRIC)
+ goto out;
+
if (data->calypso)
ofono_voicecall_create(modem, 0, "calypsomodem", data->chat);
else
ofono_voicecall_create(modem, 0, "atmodem", data->chat);
+out:
if (sim)
ofono_sim_inserted_notify(sim, TRUE);
}
@@ -682,13 +689,18 @@ static void phonesim_post_sim(struct ofono_modem *modem)
DBG("%p", modem);
- ofono_ctm_create(modem, 0, "phonesim", data->chat);
ofono_phonebook_create(modem, 0, "atmodem", data->chat);
if (!data->calypso)
ofono_stk_create(modem, OFONO_VENDOR_PHONESIM,
"atmodem", data->chat);
+ /* Other atom creations need to be addressed in the future */
+ if (data->pref_ue_mode == PREFERRED_UE_MODE_PS_VOICE_CENTRIC ||
+ data->pref_ue_mode == PREFERRED_UE_MODE_PS_DATA_CENTRIC)
+ return;
+
+ ofono_ctm_create(modem, 0, "phonesim", data->chat);
ofono_call_forwarding_create(modem, 0, "atmodem", data->chat);
if (!data->calypso)
@@ -704,9 +716,6 @@ static void phonesim_post_online(struct ofono_modem *modem)
DBG("%p", modem);
- ofono_ussd_create(modem, 0, "atmodem", data->chat);
- ofono_call_settings_create(modem, 0, "atmodem", data->chat);
-
if (data->calypso)
ofono_netreg_create(modem, OFONO_VENDOR_CALYPSO,
"atmodem", data->chat);
@@ -714,13 +723,6 @@ static void phonesim_post_online(struct ofono_modem *modem)
ofono_netreg_create(modem, OFONO_VENDOR_PHONESIM,
"atmodem", data->chat);
- ofono_call_meter_create(modem, 0, "atmodem", data->chat);
- ofono_call_barring_create(modem, 0, "atmodem", data->chat);
- ofono_call_volume_create(modem, 0, "atmodem", data->chat);
-
- if (!data->calypso)
- ofono_cbs_create(modem, 0, "atmodem", data->chat);
-
ps = ofono_packet_service_create(modem, 0, "atmodem", data->chat);
pc1 = ofono_packet_context_create(modem, 0, "phonesim", data->chat);
@@ -731,6 +733,24 @@ static void phonesim_post_online(struct ofono_modem *modem)
if (ps && pc2)
ofono_packet_service_add_context(ps, pc2);
+ /*
+ * Incase of +CEMODE: 0 or +CEMODE: 3, only LTE atoms are created which
+ * include sim, phonebook, stk, netreg, packet-service and packet-context.
+ */
+ if (data->pref_ue_mode == PREFERRED_UE_MODE_PS_VOICE_CENTRIC ||
+ data->pref_ue_mode == PREFERRED_UE_MODE_PS_DATA_CENTRIC)
+ return;
+
+ ofono_ussd_create(modem, 0, "atmodem", data->chat);
+ ofono_call_settings_create(modem, 0, "atmodem", data->chat);
+
+ ofono_call_meter_create(modem, 0, "atmodem", data->chat);
+ ofono_call_barring_create(modem, 0, "atmodem", data->chat);
+ ofono_call_volume_create(modem, 0, "atmodem", data->chat);
+
+ if (!data->calypso)
+ ofono_cbs_create(modem, 0, "atmodem", data->chat);
+
mw = ofono_message_waiting_create(modem);
if (mw)
ofono_message_waiting_register(mw);
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* [RFC PATCH 20/20] modem: Add netreg watch for tech switch
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
` (18 preceding siblings ...)
2011-04-11 10:20 ` [RFC PATCH 19/20] phonesim: atoms creation based on UE mode Vijay Nayani
@ 2011-04-11 10:20 ` Vijay Nayani
2011-04-11 19:57 ` Denis Kenzior
19 siblings, 1 reply; 41+ messages in thread
From: Vijay Nayani @ 2011-04-11 10:20 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 3393 bytes --]
Placeholder for technology switch based on
registered technology and preferred ue mode also
added along with the netreg status watch.
---
src/modem.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 79 insertions(+), 0 deletions(-)
diff --git a/src/modem.c b/src/modem.c
index aecb35a..65db45c 100644
--- a/src/modem.c
+++ b/src/modem.c
@@ -84,6 +84,9 @@ struct ofono_modem {
struct ofono_sim *sim;
unsigned int sim_watch;
unsigned int sim_ready_watch;
+ struct ofono_netreg *netreg;
+ unsigned int netreg_watch;
+ unsigned int netreg_status_watch;
const struct ofono_modem_driver *driver;
void *driver_data;
char *driver_type;
@@ -1846,6 +1849,75 @@ static void sim_watch(struct ofono_atom *atom,
modem, NULL);
}
+static void netreg_status_watch(int status, int lac, int ci, int tech,
+ const char *mcc, const char *mnc,
+ void *data)
+{
+ struct ofono_modem *modem = data;
+
+ if (status != NETWORK_REGISTRATION_STATUS_REGISTERED &&
+ status != NETWORK_REGISTRATION_STATUS_ROAMING)
+ return;
+
+ switch (tech) {
+ case ACCESS_TECHNOLOGY_EUTRAN:
+ switch(modem->pref_mode) {
+ case PREFERRED_UE_MODE_PS_VOICE_CENTRIC:
+ case PREFERRED_UE_MODE_PS_DATA_CENTRIC:
+ /* No need to do any switching */
+ break;
+ case PREFERRED_UE_MODE_CS_PS_VOICE_CENTRIC:
+ case PREFERRED_UE_MODE_CS_PS_DATA_CENTRIC:
+ /*
+ * All atoms needs to be created which is
+ * already done
+ */
+ break;
+ }
+ break;
+ case ACCESS_TECHNOLOGY_GSM:
+ case ACCESS_TECHNOLOGY_GSM_COMPACT:
+ case ACCESS_TECHNOLOGY_UTRAN:
+ case ACCESS_TECHNOLOGY_GSM_EGPRS:
+ case ACCESS_TECHNOLOGY_UTRAN_HSDPA:
+ case ACCESS_TECHNOLOGY_UTRAN_HSUPA:
+ case ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA:
+ switch(modem->pref_mode) {
+ case PREFERRED_UE_MODE_PS_VOICE_CENTRIC:
+ /* Switch to 3G */
+ break;
+ case PREFERRED_UE_MODE_CS_PS_VOICE_CENTRIC:
+ case PREFERRED_UE_MODE_CS_PS_DATA_CENTRIC:
+ /*
+ * All atoms needs to be created which is already
+ * done.
+ */
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+}
+
+static void netreg_watch(struct ofono_atom *atom,
+ enum ofono_atom_watch_condition cond, void *data)
+{
+ struct ofono_modem *modem = data;
+
+ if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
+ modem->netreg_status_watch = 0;
+ modem->netreg = NULL;
+ return;
+ }
+
+ modem->netreg = __ofono_atom_get_data(atom);
+ modem->netreg_status_watch = __ofono_netreg_add_status_watch(
+ modem->netreg,
+ netreg_status_watch,
+ modem, NULL);
+}
+
void __ofono_modemwatch_init(void)
{
g_modemwatches = __ofono_watchlist_new(g_free);
@@ -1988,6 +2060,10 @@ int ofono_modem_register(struct ofono_modem *modem)
OFONO_ATOM_TYPE_SIM,
sim_watch, modem, NULL);
+ modem->netreg_watch = __ofono_modem_add_atom_watch(modem,
+ OFONO_ATOM_TYPE_NETREG,
+ netreg_watch, modem, NULL);
+
return 0;
}
@@ -2020,6 +2096,9 @@ static void modem_unregister(struct ofono_modem *modem)
modem->sim_watch = 0;
modem->sim_ready_watch = 0;
+ modem->netreg_watch = 0;
+ modem->netreg_status_watch = 0;
+
g_slist_foreach(modem->interface_list, (GFunc) g_free, NULL);
g_slist_free(modem->interface_list);
modem->interface_list = NULL;
--
1.7.0.4
^ permalink raw reply related [flat|nested] 41+ messages in thread
* Re: [RFC PATCH 10/20] doc: add PreferredMode property to modem
2011-04-11 10:20 ` [RFC PATCH 10/20] doc: add PreferredMode property to modem Vijay Nayani
@ 2011-04-11 19:27 ` Denis Kenzior
2011-04-12 11:51 ` Vijay.Nayani
0 siblings, 1 reply; 41+ messages in thread
From: Denis Kenzior @ 2011-04-11 19:27 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1514 bytes --]
Hi Vijay,
On 04/11/2011 05:20 AM, Vijay Nayani wrote:
> ---
> doc/modem-api.txt | 18 ++++++++++++++++++
> 1 files changed, 18 insertions(+), 0 deletions(-)
>
> diff --git a/doc/modem-api.txt b/doc/modem-api.txt
> index fa400a2..c79bffa 100644
> --- a/doc/modem-api.txt
> +++ b/doc/modem-api.txt
> @@ -54,6 +54,24 @@ Properties boolean Powered [readwrite]
> modem. The Emergency is true if an emergency call or
> related operation is currently active.
>
> + string PreferredMode [readonly, optional]
> +
> + Preferred UE mode setting. A UE attached for EPS services
> + shall operate in one of the following operation modes:
> +
> + "PS mode 2" UE registers only to EPS
> + services, and UE's usage setting
> + is "data centric".
> + "CS/PS mode 1" UE registers to both EPS and
> + non-EPS services, and UE's usage
> + setting is "voice centric".
> + "CS/PS mode 2" UE registers to both EPS and
> + non-EPS services, and UE's usage
> + setting is "data centric".
> + "PS mode 1" UE registers only to EPS
> + services, and UE's usage setting
> + is "voice centric".
> +
I don't like that this is being exposed on the modem interface. This
really belongs on a separate atom. Not all modems are going to be LTE
enabled yet...
Have you looked at the IMS/LTE API proposal from Sjur a while back?
> string Name [readonly, optional]
>
> Friendly name of the modem device.
Regards,
-Denis
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC PATCH 08/20] include: add set preferred ue mode api
2011-04-11 10:20 ` [RFC PATCH 08/20] include: add set preferred ue mode api Vijay Nayani
@ 2011-04-11 19:34 ` Denis Kenzior
2011-04-12 10:10 ` Vijay.Nayani
0 siblings, 1 reply; 41+ messages in thread
From: Denis Kenzior @ 2011-04-11 19:34 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 932 bytes --]
Hi Vijay,
On 04/11/2011 05:20 AM, Vijay Nayani wrote:
> ---
> include/modem.h | 2 ++
> 1 files changed, 2 insertions(+), 0 deletions(-)
>
> diff --git a/include/modem.h b/include/modem.h
> index 5a34370..e416f50 100644
> --- a/include/modem.h
> +++ b/include/modem.h
> @@ -51,6 +51,8 @@ void ofono_modem_reset(struct ofono_modem *modem);
> void ofono_modem_set_powered(struct ofono_modem *modem, ofono_bool_t powered);
> ofono_bool_t ofono_modem_get_powered(struct ofono_modem *modem);
>
> +void ofono_modem_set_preferred_ue_mode(struct ofono_modem *modem, int mode);
> +
Are you assuming that the UE mode cannot be changed? If so, doesn't this
map to +CEMODE AT command? Doesn't it allow a set operation to change
the UE mode?
> ofono_bool_t ofono_modem_get_online(struct ofono_modem *modem);
>
> ofono_bool_t ofono_modem_get_emergency_mode(struct ofono_modem *modem);
Regards,
-Denis
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC PATCH 09/20] modem: add preferred ue mode handling
2011-04-11 10:20 ` [RFC PATCH 09/20] modem: add preferred ue mode handling Vijay Nayani
@ 2011-04-11 19:36 ` Denis Kenzior
2011-04-12 11:42 ` Vijay.Nayani
0 siblings, 1 reply; 41+ messages in thread
From: Denis Kenzior @ 2011-04-11 19:36 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 584 bytes --]
Hi Vijay,
> +static const char *preferred_ue_mode_to_string(int mode)
> +{
> + switch (mode) {
> + case PREFERRED_UE_MODE_PS_DATA_CENTRIC:
> + return "PS mode 2";
> + case PREFERRED_UE_MODE_CS_PS_VOICE_CENTRIC:
> + return "PS/CS mode 1";
> + case PREFERRED_UE_MODE_CS_PS_DATA_CENTRIC:
> + return "PS/CS mode 2";
> + case PREFERRED_UE_MODE_PS_VOICE_CENTRIC:
> + return "PS mode 1";
> + }
> +
> + return "unknown";
> +}
> +
These values are really not telling anyone anything. How do you
envision the upper layers using this information?
Regards,
-Denis
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC PATCH 12/20] packet: add context type default
2011-04-11 10:20 ` [RFC PATCH 12/20] packet: add context type default Vijay Nayani
@ 2011-04-11 19:40 ` Denis Kenzior
2011-04-12 2:49 ` Marcel Holtmann
0 siblings, 1 reply; 41+ messages in thread
From: Denis Kenzior @ 2011-04-11 19:40 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1281 bytes --]
Hi Vijay,
On 04/11/2011 05:20 AM, Vijay Nayani wrote:
> OFONO_PACKET_CONTEXT_TYPE_DEFAULT is added to
> ofono_packet_context_type and conversion functions
> are updated for the same.
> ---
> include/packet-context.h | 1 +
> src/packet.c | 7 +++++++
> 2 files changed, 8 insertions(+), 0 deletions(-)
>
> diff --git a/include/packet-context.h b/include/packet-context.h
> index 44fd69f..02a5c42 100644
> --- a/include/packet-context.h
> +++ b/include/packet-context.h
> @@ -47,6 +47,7 @@ enum ofono_packet_context_type {
> OFONO_PACKET_CONTEXT_TYPE_MMS,
> OFONO_PACKET_CONTEXT_TYPE_WAP,
> OFONO_PACKET_CONTEXT_TYPE_IMS,
> + OFONO_PACKET_CONTEXT_TYPE_DEFAULT,
> };
>
My understanding was that whether an EPS bearer is 'default' has no
bearing on what context type (e.g. ims, internet, mms) it actually is.
I remember there was a conversation on how a 'default' context is
chosen, but I already forgot most of it.
To me it makes no sense that a default context is going to be anything
other than internet or ims. The fact that it is a 'default' context
doesn't really help the upper layers in any way. Especially ConnMan
needs to know whether this context can be used for internet access or not.
Regards,
-Denis
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC PATCH 17/20] atmodem: add lte specific functions
2011-04-11 10:20 ` [RFC PATCH 17/20] atmodem: add lte specific functions Vijay Nayani
@ 2011-04-11 19:54 ` Denis Kenzior
2011-04-12 10:11 ` Vijay.Nayani
2011-04-12 3:43 ` Marcel Holtmann
1 sibling, 1 reply; 41+ messages in thread
From: Denis Kenzior @ 2011-04-11 19:54 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 6517 bytes --]
On 04/11/2011 05:20 AM, Vijay Nayani wrote:
> Changes include: Registration of CEREG events,
> registration status query based on registered
> technology, handling of ME PDN ACT CGEV event,
> reading of default context params and notification
> of default context params to the core.
> ---
> drivers/atmodem/packet-service.c | 238 ++++++++++++++++++++++++++++++++++++++
> 1 files changed, 238 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/atmodem/packet-service.c b/drivers/atmodem/packet-service.c
> index 9999d9d..b766a3b 100644
> --- a/drivers/atmodem/packet-service.c
> +++ b/drivers/atmodem/packet-service.c
> @@ -4,6 +4,7 @@
> *
> * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
> * Copyright (C) 2010 ST-Ericsson AB.
> + * Copyright 2011 EB(Elektrobit).
> *
> * 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
> @@ -40,17 +41,23 @@
> #include "gatchat.h"
> #include "gatresult.h"
>
> +#include "common.h"
> +
> #include "atmodem.h"
> #include "vendor.h"
>
> static const char *cgreg_prefix[] = { "+CGREG:", NULL };
> static const char *cgdcont_prefix[] = { "+CGDCONT:", NULL };
> +static const char *cereg_prefix[] = { "+CEREG:", NULL };
> +static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
> static const char *none_prefix[] = { NULL };
>
> struct packet_service_data {
> GAtChat *chat;
> int default_cid;
> int default_context_type;
> + int cid_min;
> + int cid_max;
> unsigned int vendor;
> };
>
> @@ -109,6 +116,134 @@ static void at_cgreg_cb(gboolean ok, GAtResult *result, gpointer user_data)
> cb(&error, status, cbd->data);
> }
>
> +static void at_cereg_cb(gboolean ok, GAtResult *result, gpointer user_data)
> +{
> + struct cb_data *cbd = user_data;
> + ofono_packet_service_status_cb_t cb = cbd->cb;
> + struct ofono_error error;
> + int status;
> + struct packet_service_data *psd = cbd->user;
> +
> + decode_at_error(&error, g_at_result_final_response(result));
> +
> + if (!ok) {
> + cb(&error, -1, cbd->data);
> + return;
> + }
> +
> + if (at_util_parse_reg(result, "+CEREG:", NULL, &status,
> + NULL, NULL, NULL, psd->vendor) == FALSE) {
> + CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
> + return;
> + }
> +
> + cb(&error, status, cbd->data);
> +}
> +
> +static void at_cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
> +{
> + struct ofono_packet_service *ps = user_data;
> + struct packet_service_data *psd = ofono_packet_service_get_data(ps);
> + GAtResultIter iter;
> + int cid, bearer_id;
> + const char *apn, *address, *gateway, *dns1, *dns2;
> + const char *dns[3];
> + struct ofono_default_context_param *param;
> +
> + if (!ok)
> + return;
> +
> + g_at_result_iter_init(&iter, result);
> +
> + if (g_at_result_iter_next(&iter, "+CGCONTRDP:") == FALSE)
> + return;
> +
> + if (g_at_result_iter_next_number(&iter, &cid) == FALSE)
> + return;
> +
> + if (g_at_result_iter_next_number(&iter, &bearer_id) == FALSE)
> + return;
> +
> + if (g_at_result_iter_next_string(&iter, &apn) == FALSE)
> + return;
> +
> + if (g_at_result_iter_next_string(&iter, &address) == FALSE)
> + goto out;
> +
> + if (g_at_result_iter_next_string(&iter, &gateway) == FALSE)
> + goto out;
> +
> + if (g_at_result_iter_next_string(&iter, &dns1) == FALSE)
> + goto out;
> +
> + if (g_at_result_iter_next_string(&iter, &dns2) == FALSE)
> + goto out;
> +
> + dns[0] = dns1;
> + dns[1] = dns2;
> + dns[2] = 0;
> +
> +out:
> + param = g_new0(struct ofono_default_context_param, 1);
> + if (param == NULL)
> + return;
> +
> + param->cid = cid;
> + param->proto = psd->default_context_type;
> + param->apn = apn;
> + param->address = address;
> + param->gateway = gateway;
> + param->dns = dns;
> +
> + ofono_packet_service_default_context_notify(ps, param);
This is really not working out, since you still need to get the
interface for this context. The fact that a context is active does not
necessarily mean that all the resources have been properly allocated.
Namely a gprs-context allocated and all the implications (e.g. AT
channel dedicated to the gprs-context is taken, ppp / high speed data
connection established, etc.)
Only the core can do the context allocation, so you still need to let
the core decide what to do.
> +
> + g_free(param);
> + param = NULL;
> +}
> +
> +static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data)
> +{
> + struct ofono_packet_service *ps = user_data;
> + struct packet_service_data *psd = ofono_packet_service_get_data(ps);
> + GAtResultIter iter;
> + int cid;
> + const char *pdp_type;
> + char buf[64];
> + gboolean found = FALSE;
> +
> + if (!ok)
> + return;
> +
> + g_at_result_iter_init(&iter, result);
> +
> + while (!found && g_at_result_iter_next(&iter, "+CGDCONT:")) {
> + if (g_at_result_iter_next_number(&iter, &cid) == FALSE)
> + return;
> +
> + if (psd->default_cid != cid)
> + continue;
> +
> + g_at_result_iter_next_string(&iter, &pdp_type);
> +
> + found = TRUE;
> + }
> +
> + if (found == FALSE)
> + return;
> +
> + if (g_str_equal(pdp_type, "IP"))
> + psd->default_context_type = OFONO_PACKET_PROTO_IP;
> + else if (g_str_equal(pdp_type, "IPV6"))
> + psd->default_context_type = OFONO_PACKET_PROTO_IPV6;
> + else if (g_str_equal(pdp_type, "IPV4V6"))
> + psd->default_context_type = OFONO_PACKET_PROTO_IPV4V6;
> +
> + snprintf(buf, sizeof(buf), "AT+CGCONTRDP=%i", psd->default_cid);
> +
> + g_at_chat_send(psd->chat, buf, cgcontrdp_prefix, at_cgcontrdp_cb,
> + ps, NULL);
> +}
> +
> static void at_packet_service_registration_status(
> struct ofono_packet_service *ps,
> ofono_packet_service_status_cb_t cb,
> @@ -138,6 +273,13 @@ static void at_packet_service_registration_status(
> break;
> }
>
> + if (ofono_packet_service_get_technology(ps) ==
> + ACCESS_TECHNOLOGY_EUTRAN) {
> + if (g_at_chat_send(psd->chat, "AT+CEREG?", cereg_prefix,
> + at_cereg_cb, cbd, g_free) > 0)
> + return;
> + }
> +
> if (g_at_chat_send(psd->chat, "AT+CGREG?", cgreg_prefix,
> at_cgreg_cb, cbd, g_free) > 0)
> return;
This is really just a bad idea. The core needs to understand the
concept of CEREG properly, not try to hide this in the driver.
Regards,
-Denis
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC PATCH 20/20] modem: Add netreg watch for tech switch
2011-04-11 10:20 ` [RFC PATCH 20/20] modem: Add netreg watch for tech switch Vijay Nayani
@ 2011-04-11 19:57 ` Denis Kenzior
2011-04-12 10:19 ` Vijay.Nayani
0 siblings, 1 reply; 41+ messages in thread
From: Denis Kenzior @ 2011-04-11 19:57 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1535 bytes --]
Hi Vijay,
> +static void netreg_status_watch(int status, int lac, int ci, int tech,
> + const char *mcc, const char *mnc,
> + void *data)
> +{
> + struct ofono_modem *modem = data;
> +
> + if (status != NETWORK_REGISTRATION_STATUS_REGISTERED &&
> + status != NETWORK_REGISTRATION_STATUS_ROAMING)
> + return;
> +
> + switch (tech) {
> + case ACCESS_TECHNOLOGY_EUTRAN:
> + switch(modem->pref_mode) {
> + case PREFERRED_UE_MODE_PS_VOICE_CENTRIC:
> + case PREFERRED_UE_MODE_PS_DATA_CENTRIC:
> + /* No need to do any switching */
> + break;
> + case PREFERRED_UE_MODE_CS_PS_VOICE_CENTRIC:
> + case PREFERRED_UE_MODE_CS_PS_DATA_CENTRIC:
> + /*
> + * All atoms needs to be created which is
> + * already done
> + */
> + break;
> + }
> + break;
> + case ACCESS_TECHNOLOGY_GSM:
> + case ACCESS_TECHNOLOGY_GSM_COMPACT:
> + case ACCESS_TECHNOLOGY_UTRAN:
> + case ACCESS_TECHNOLOGY_GSM_EGPRS:
> + case ACCESS_TECHNOLOGY_UTRAN_HSDPA:
> + case ACCESS_TECHNOLOGY_UTRAN_HSUPA:
> + case ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA:
> + switch(modem->pref_mode) {
> + case PREFERRED_UE_MODE_PS_VOICE_CENTRIC:
> + /* Switch to 3G */
> + break;
> + case PREFERRED_UE_MODE_CS_PS_VOICE_CENTRIC:
> + case PREFERRED_UE_MODE_CS_PS_DATA_CENTRIC:
> + /*
> + * All atoms needs to be created which is already
> + * done.
> + */
> + break;
> + default:
> + break;
> + }
> + break;
> + }
> +}
> +
So what exactly needs to be done here?
Regards,
-Denis
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC PATCH 12/20] packet: add context type default
2011-04-11 19:40 ` Denis Kenzior
@ 2011-04-12 2:49 ` Marcel Holtmann
0 siblings, 0 replies; 41+ messages in thread
From: Marcel Holtmann @ 2011-04-12 2:49 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 3338 bytes --]
Hi Denis,
> > OFONO_PACKET_CONTEXT_TYPE_DEFAULT is added to
> > ofono_packet_context_type and conversion functions
> > are updated for the same.
> > ---
> > include/packet-context.h | 1 +
> > src/packet.c | 7 +++++++
> > 2 files changed, 8 insertions(+), 0 deletions(-)
> >
> > diff --git a/include/packet-context.h b/include/packet-context.h
> > index 44fd69f..02a5c42 100644
> > --- a/include/packet-context.h
> > +++ b/include/packet-context.h
> > @@ -47,6 +47,7 @@ enum ofono_packet_context_type {
> > OFONO_PACKET_CONTEXT_TYPE_MMS,
> > OFONO_PACKET_CONTEXT_TYPE_WAP,
> > OFONO_PACKET_CONTEXT_TYPE_IMS,
> > + OFONO_PACKET_CONTEXT_TYPE_DEFAULT,
> > };
> >
>
> My understanding was that whether an EPS bearer is 'default' has no
> bearing on what context type (e.g. ims, internet, mms) it actually is.
> I remember there was a conversation on how a 'default' context is
> chosen, but I already forgot most of it.
in the end we concluded that the only way to figure out the context type
is by comparing the APN name. And hopefully we have that one configured
and can simply string match it. If we do not, then the whole system will
fall apart.
> To me it makes no sense that a default context is going to be anything
> other than internet or ims. The fact that it is a 'default' context
> doesn't really help the upper layers in any way. Especially ConnMan
> needs to know whether this context can be used for internet access or not.
The concept of default context is as broken as trying to introduce a
special CID 0 meaning. Both do not work. We need to know what type of
context we have.
The real problem that I see here is that there is no clear definition on
what the default context connects to. I think this is the biggest
limitation of 3GPP right now. They should have just said that the
default context always connects to the private IP network of the
carrier. And that will be then the IMS, MMS etc. or some sort of context
that is clearly private to the carrier. And that the Internet context
always needs to be established by host.
Especially for the cases of roaming we need to have the default context
connecting to an operator internal network. Otherwise any kind of
billing will get really complicated. Since on one hand you wanna be
reachable while roaming, but maybe not pay for data roaming. Not to talk
about emergency call handling while roaming.
Lets have a look at the one network that deploys LTE for the public
these days. I did not find an official Verizon page about their APN
names and functions, but this will do:
http://www.4ginfo.com/index.php/verizon-uml290-mac-configuration-warning-a-fix.html
CID 1, Type IPV6, APN vzwims
CID 3, Type IPV4V6, APN vzwinternet
CID 4, Type IPv4V6, APN vzwapp
And if you trust other sources, then CID 2 is this:
CID 2, Type IPV4V6, APN vzwadmin
This does not answer which APN gets activated as default, but I would
assume the network returns vzwims. If someone is on Verizon and has LTE
capable hardware, it would be nice if they try this.
And if you wanna have any legacy software working with LTE data dongle
as before, if would make a lot of sense to not end up having two
Internet contexts activated. I am just saying ;)
Regards
Marcel
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC PATCH 17/20] atmodem: add lte specific functions
2011-04-11 10:20 ` [RFC PATCH 17/20] atmodem: add lte specific functions Vijay Nayani
2011-04-11 19:54 ` Denis Kenzior
@ 2011-04-12 3:43 ` Marcel Holtmann
2011-04-12 12:48 ` Vijay.Nayani
1 sibling, 1 reply; 41+ messages in thread
From: Marcel Holtmann @ 2011-04-12 3:43 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 6072 bytes --]
Hi Vijay,
> +static void at_cgcontrdp_cb(gboolean ok, GAtResult *result, gpointer user_data)
> +{
> + struct ofono_packet_service *ps = user_data;
> + struct packet_service_data *psd = ofono_packet_service_get_data(ps);
> + GAtResultIter iter;
> + int cid, bearer_id;
> + const char *apn, *address, *gateway, *dns1, *dns2;
> + const char *dns[3];
> + struct ofono_default_context_param *param;
> +
> + if (!ok)
> + return;
> +
> + g_at_result_iter_init(&iter, result);
> +
> + if (g_at_result_iter_next(&iter, "+CGCONTRDP:") == FALSE)
> + return;
> +
> + if (g_at_result_iter_next_number(&iter, &cid) == FALSE)
> + return;
> +
> + if (g_at_result_iter_next_number(&iter, &bearer_id) == FALSE)
> + return;
> +
> + if (g_at_result_iter_next_string(&iter, &apn) == FALSE)
> + return;
> +
> + if (g_at_result_iter_next_string(&iter, &address) == FALSE)
> + goto out;
> +
> + if (g_at_result_iter_next_string(&iter, &gateway) == FALSE)
> + goto out;
> +
> + if (g_at_result_iter_next_string(&iter, &dns1) == FALSE)
> + goto out;
> +
> + if (g_at_result_iter_next_string(&iter, &dns2) == FALSE)
> + goto out;
> +
> + dns[0] = dns1;
> + dns[1] = dns2;
> + dns[2] = 0;
> +
> +out:
> + param = g_new0(struct ofono_default_context_param, 1);
> + if (param == NULL)
> + return;
> +
> + param->cid = cid;
> + param->proto = psd->default_context_type;
> + param->apn = apn;
> + param->address = address;
> + param->gateway = gateway;
> + param->dns = dns;
> +
> + ofono_packet_service_default_context_notify(ps, param);
> +
> + g_free(param);
> + param = NULL;
> +}
> +
> +static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data)
> +{
> + struct ofono_packet_service *ps = user_data;
> + struct packet_service_data *psd = ofono_packet_service_get_data(ps);
> + GAtResultIter iter;
> + int cid;
> + const char *pdp_type;
> + char buf[64];
> + gboolean found = FALSE;
> +
> + if (!ok)
> + return;
> +
> + g_at_result_iter_init(&iter, result);
> +
> + while (!found && g_at_result_iter_next(&iter, "+CGDCONT:")) {
> + if (g_at_result_iter_next_number(&iter, &cid) == FALSE)
> + return;
> +
> + if (psd->default_cid != cid)
> + continue;
> +
> + g_at_result_iter_next_string(&iter, &pdp_type);
> +
> + found = TRUE;
> + }
> +
> + if (found == FALSE)
> + return;
> +
> + if (g_str_equal(pdp_type, "IP"))
> + psd->default_context_type = OFONO_PACKET_PROTO_IP;
> + else if (g_str_equal(pdp_type, "IPV6"))
> + psd->default_context_type = OFONO_PACKET_PROTO_IPV6;
> + else if (g_str_equal(pdp_type, "IPV4V6"))
> + psd->default_context_type = OFONO_PACKET_PROTO_IPV4V6;
> +
> + snprintf(buf, sizeof(buf), "AT+CGCONTRDP=%i", psd->default_cid);
this looks wrong to me. Reading the CGDCONT information is not going to
help us. We should just read CGCONTRDP if available or CGADDR it not.
If we are a dual stack, then we will see two lines of CGCONTRDP, if not
then I assume we can tell from the address if we are IP or IPV6. Same
applies to CGADDR in case CGCONTRDP is not available.
And of course we need to keep CGPIAF in mind.
For me it is also important if <IM_CN_Signalling_Flag> is set or not
since that tells us that this is the IMS context. And I would expect
that all networks will use that one as default context.
> + g_at_chat_send(psd->chat, buf, cgcontrdp_prefix, at_cgcontrdp_cb,
> + ps, NULL);
> +}
> +
> static void at_packet_service_registration_status(
> struct ofono_packet_service *ps,
> ofono_packet_service_status_cb_t cb,
> @@ -138,6 +273,13 @@ static void at_packet_service_registration_status(
> break;
> }
>
> + if (ofono_packet_service_get_technology(ps) ==
> + ACCESS_TECHNOLOGY_EUTRAN) {
> + if (g_at_chat_send(psd->chat, "AT+CEREG?", cereg_prefix,
> + at_cereg_cb, cbd, g_free) > 0)
> + return;
> + }
> +
> if (g_at_chat_send(psd->chat, "AT+CGREG?", cgreg_prefix,
> at_cgreg_cb, cbd, g_free) > 0)
> return;
> @@ -160,9 +302,23 @@ static void cgreg_notify(GAtResult *result, gpointer user_data)
> ofono_packet_service_status_notify(ps, status);
> }
>
> +static void cereg_notify(GAtResult *result, gpointer user_data)
> +{
> + struct ofono_packet_service *ps = user_data;
> + int status;
> + struct packet_service_data *psd = ofono_packet_service_get_data(ps);
> +
> + if (at_util_parse_reg_unsolicited(result, "+CEREG:", &status,
> + NULL, NULL, NULL, psd->vendor) == FALSE)
> + return;
> +
> + ofono_packet_service_status_notify(ps, status);
> +}
> +
> static void cgev_notify(GAtResult *result, gpointer user_data)
> {
> struct ofono_packet_service *ps = user_data;
> + struct packet_service_data *psd = ofono_packet_service_get_data(ps);
> GAtResultIter iter;
> const char *event;
>
> @@ -179,6 +335,35 @@ static void cgev_notify(GAtResult *result, gpointer user_data)
> ofono_packet_service_detached_notify(ps);
> return;
> }
> +
> + if (g_str_has_prefix(event, "ME PDN ACT")) {
> + /*
> + * As per 27.007, this even it sent when the mobile termination
> + * has activated a context. The context represents a PDN
> + * connection in LTE or a Primary PDP context in GSM/UMTS.
> + * The <cid> for this context is provided to the TE. This event
> + * is sent either in result of explicit context activation
> + * request (+CGACT), or in result of implicit context activation
> + * request associated to attach request (+CGATT=1).
> + */
> + int cid;
> +
> + cid = g_ascii_strtoll(&event[11], NULL, 0);
> +
> + /*
> + * Assumption: context id for default EPS context will have
> + * value outside the ranges indicated in the test form of
> + * the command +CGDCONT.
> + */
That is still an assumption that needs to be confirmed. So does the
default context activation from just uses APN == "" and then the network
picks the APN to activate. Or does it just use the APN value from CID 1
for example.
Regards
Marcel
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [RFC PATCH 08/20] include: add set preferred ue mode api
2011-04-11 19:34 ` Denis Kenzior
@ 2011-04-12 10:10 ` Vijay.Nayani
2011-04-12 13:52 ` Denis Kenzior
0 siblings, 1 reply; 41+ messages in thread
From: Vijay.Nayani @ 2011-04-12 10:10 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1567 bytes --]
Hi Denis,
> -----Original Message-----
> From: Denis Kenzior [mailto:denkenz(a)gmail.com]
> Sent: 11 April 2011 22:35
> To: ofono(a)ofono.org
> Cc: Nayani Vijay
> Subject: Re: [RFC PATCH 08/20] include: add set preferred ue mode api
>
> Hi Vijay,
>
> On 04/11/2011 05:20 AM, Vijay Nayani wrote:
> > ---
> > include/modem.h | 2 ++
> > 1 files changed, 2 insertions(+), 0 deletions(-)
> >
> > diff --git a/include/modem.h b/include/modem.h index
> 5a34370..e416f50
> > 100644
> > --- a/include/modem.h
> > +++ b/include/modem.h
> > @@ -51,6 +51,8 @@ void ofono_modem_reset(struct ofono_modem
> *modem);
> > void ofono_modem_set_powered(struct ofono_modem *modem,
> ofono_bool_t
> > powered); ofono_bool_t ofono_modem_get_powered(struct ofono_modem
> > *modem);
> >
> > +void ofono_modem_set_preferred_ue_mode(struct ofono_modem
> *modem, int
> > +mode);
> > +
>
> Are you assuming that the UE mode cannot be changed? If so,
> doesn't this map to +CEMODE AT command? Doesn't it allow a
> set operation to change the UE mode?
>
We have made this currently read only as i don't see any usecase of this
being set from user side(settings or any other).
If a set provision need arises, this would bring in new API to driver
side as well to do the job. Also this would be purly apply for LTE.
> > ofono_bool_t ofono_modem_get_online(struct ofono_modem *modem);
> >
> > ofono_bool_t ofono_modem_get_emergency_mode(struct ofono_modem
> > *modem);
>
> Regards,
> -Denis
>
Regards,
Vijay
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [RFC PATCH 17/20] atmodem: add lte specific functions
2011-04-11 19:54 ` Denis Kenzior
@ 2011-04-12 10:11 ` Vijay.Nayani
2011-04-12 13:56 ` Denis Kenzior
0 siblings, 1 reply; 41+ messages in thread
From: Vijay.Nayani @ 2011-04-12 10:11 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 7779 bytes --]
> -----Original Message-----
> From: Denis Kenzior [mailto:denkenz(a)gmail.com]
> Sent: 11 April 2011 22:55
> To: ofono(a)ofono.org
> Cc: Nayani Vijay
> Subject: Re: [RFC PATCH 17/20] atmodem: add lte specific functions
>
> On 04/11/2011 05:20 AM, Vijay Nayani wrote:
> > Changes include: Registration of CEREG events, registration status
> > query based on registered technology, handling of ME PDN ACT CGEV
> > event, reading of default context params and notification
> of default
> > context params to the core.
> > ---
> > drivers/atmodem/packet-service.c | 238
> > ++++++++++++++++++++++++++++++++++++++
> > 1 files changed, 238 insertions(+), 0 deletions(-)
> >
> > diff --git a/drivers/atmodem/packet-service.c
> > b/drivers/atmodem/packet-service.c
> > index 9999d9d..b766a3b 100644
> > --- a/drivers/atmodem/packet-service.c
> > +++ b/drivers/atmodem/packet-service.c
> > @@ -4,6 +4,7 @@
> > *
> > * Copyright (C) 2008-2010 Intel Corporation. All rights
> reserved.
> > * Copyright (C) 2010 ST-Ericsson AB.
> > + * Copyright 2011 EB(Elektrobit).
> > *
> > * 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
> > @@ -40,17 +41,23 @@ #include "gatchat.h"
> > #include "gatresult.h"
> >
> > +#include "common.h"
> > +
> > #include "atmodem.h"
> > #include "vendor.h"
> >
> > static const char *cgreg_prefix[] = { "+CGREG:", NULL }; static
> > const char *cgdcont_prefix[] = { "+CGDCONT:", NULL };
> > +static const char *cereg_prefix[] = { "+CEREG:", NULL };
> static const
> > +char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
> > static const char *none_prefix[] = { NULL };
> >
> > struct packet_service_data {
> > GAtChat *chat;
> > int default_cid;
> > int default_context_type;
> > + int cid_min;
> > + int cid_max;
> > unsigned int vendor;
> > };
> >
> > @@ -109,6 +116,134 @@ static void at_cgreg_cb(gboolean ok,
> GAtResult *result, gpointer user_data)
> > cb(&error, status, cbd->data);
> > }
> >
> > +static void at_cereg_cb(gboolean ok, GAtResult *result, gpointer
> > +user_data) {
> > + struct cb_data *cbd = user_data;
> > + ofono_packet_service_status_cb_t cb = cbd->cb;
> > + struct ofono_error error;
> > + int status;
> > + struct packet_service_data *psd = cbd->user;
> > +
> > + decode_at_error(&error, g_at_result_final_response(result));
> > +
> > + if (!ok) {
> > + cb(&error, -1, cbd->data);
> > + return;
> > + }
> > +
> > + if (at_util_parse_reg(result, "+CEREG:", NULL, &status,
> > + NULL, NULL, NULL, psd->vendor)
> == FALSE) {
> > + CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
> > + return;
> > + }
> > +
> > + cb(&error, status, cbd->data);
> > +}
> > +
> > +static void at_cgcontrdp_cb(gboolean ok, GAtResult
> *result, gpointer
> > +user_data) {
> > + struct ofono_packet_service *ps = user_data;
> > + struct packet_service_data *psd =
> ofono_packet_service_get_data(ps);
> > + GAtResultIter iter;
> > + int cid, bearer_id;
> > + const char *apn, *address, *gateway, *dns1, *dns2;
> > + const char *dns[3];
> > + struct ofono_default_context_param *param;
> > +
> > + if (!ok)
> > + return;
> > +
> > + g_at_result_iter_init(&iter, result);
> > +
> > + if (g_at_result_iter_next(&iter, "+CGCONTRDP:") == FALSE)
> > + return;
> > +
> > + if (g_at_result_iter_next_number(&iter, &cid) == FALSE)
> > + return;
> > +
> > + if (g_at_result_iter_next_number(&iter, &bearer_id) == FALSE)
> > + return;
> > +
> > + if (g_at_result_iter_next_string(&iter, &apn) == FALSE)
> > + return;
> > +
> > + if (g_at_result_iter_next_string(&iter, &address) == FALSE)
> > + goto out;
> > +
> > + if (g_at_result_iter_next_string(&iter, &gateway) == FALSE)
> > + goto out;
> > +
> > + if (g_at_result_iter_next_string(&iter, &dns1) == FALSE)
> > + goto out;
> > +
> > + if (g_at_result_iter_next_string(&iter, &dns2) == FALSE)
> > + goto out;
> > +
> > + dns[0] = dns1;
> > + dns[1] = dns2;
> > + dns[2] = 0;
> > +
> > +out:
> > + param = g_new0(struct ofono_default_context_param, 1);
> > + if (param == NULL)
> > + return;
> > +
> > + param->cid = cid;
> > + param->proto = psd->default_context_type;
> > + param->apn = apn;
> > + param->address = address;
> > + param->gateway = gateway;
> > + param->dns = dns;
> > +
> > + ofono_packet_service_default_context_notify(ps, param);
>
> This is really not working out, since you still need to get
> the interface for this context. The fact that a context is
> active does not necessarily mean that all the resources have
> been properly allocated.
> Namely a gprs-context allocated and all the implications
> (e.g. AT channel dedicated to the gprs-context is taken, ppp
> / high speed data connection established, etc.)
>
> Only the core can do the context allocation, so you still
> need to let the core decide what to do.
>
I agree on your comments here.
Infact have missed out to put a todo here on interface assignment so
that this can be taken up when we work with real modem.
> > +
> > + g_free(param);
> > + param = NULL;
> > +}
> > +
> > +static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer
> > +user_data) {
> > + struct ofono_packet_service *ps = user_data;
> > + struct packet_service_data *psd =
> ofono_packet_service_get_data(ps);
> > + GAtResultIter iter;
> > + int cid;
> > + const char *pdp_type;
> > + char buf[64];
> > + gboolean found = FALSE;
> > +
> > + if (!ok)
> > + return;
> > +
> > + g_at_result_iter_init(&iter, result);
> > +
> > + while (!found && g_at_result_iter_next(&iter, "+CGDCONT:")) {
> > + if (g_at_result_iter_next_number(&iter, &cid) == FALSE)
> > + return;
> > +
> > + if (psd->default_cid != cid)
> > + continue;
> > +
> > + g_at_result_iter_next_string(&iter, &pdp_type);
> > +
> > + found = TRUE;
> > + }
> > +
> > + if (found == FALSE)
> > + return;
> > +
> > + if (g_str_equal(pdp_type, "IP"))
> > + psd->default_context_type = OFONO_PACKET_PROTO_IP;
> > + else if (g_str_equal(pdp_type, "IPV6"))
> > + psd->default_context_type = OFONO_PACKET_PROTO_IPV6;
> > + else if (g_str_equal(pdp_type, "IPV4V6"))
> > + psd->default_context_type = OFONO_PACKET_PROTO_IPV4V6;
> > +
> > + snprintf(buf, sizeof(buf), "AT+CGCONTRDP=%i", psd->default_cid);
> > +
> > + g_at_chat_send(psd->chat, buf, cgcontrdp_prefix,
> at_cgcontrdp_cb,
> > +
> ps, NULL);
> > +}
> > +
> > static void at_packet_service_registration_status(
> > struct ofono_packet_service *ps,
> >
> ofono_packet_service_status_cb_t cb, @@ -138,6 +273,13 @@ static
> > void at_packet_service_registration_status(
> > break;
> > }
> >
> > + if (ofono_packet_service_get_technology(ps) ==
> > +
> ACCESS_TECHNOLOGY_EUTRAN) {
> > + if (g_at_chat_send(psd->chat, "AT+CEREG?", cereg_prefix,
> > + at_cereg_cb, cbd, g_free) > 0)
> > + return;
> > + }
> > +
> > if (g_at_chat_send(psd->chat, "AT+CGREG?", cgreg_prefix,
> > at_cgreg_cb, cbd, g_free) > 0)
> > return;
>
> This is really just a bad idea. The core needs to understand
> the concept of CEREG properly, not try to hide this in the driver.
>
Intention here is to hide to the core on details of registraion
technology.
If core needs these awareness and want to fire relevent
API/functionality based on current access tech, would bring in new APIs
to driver for 3G registraion status and LTE registraion status.
This will also result in core to base it behaviour depending on acess
technology.
> Regards,
> -Denis
>
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [RFC PATCH 20/20] modem: Add netreg watch for tech switch
2011-04-11 19:57 ` Denis Kenzior
@ 2011-04-12 10:19 ` Vijay.Nayani
2011-04-12 13:58 ` Denis Kenzior
0 siblings, 1 reply; 41+ messages in thread
From: Vijay.Nayani @ 2011-04-12 10:19 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 3160 bytes --]
Hi Denis,
> > + case PREFERRED_UE_MODE_CS_PS_DATA_CENTRIC:
> > + /*
> > + * All atoms needs to be created which is
> > + * already done
> > + */
> > + break;
> > + }
> > + break;
> > + case ACCESS_TECHNOLOGY_GSM:
> > + case ACCESS_TECHNOLOGY_GSM_COMPACT:
> > + case ACCESS_TECHNOLOGY_UTRAN:
> > + case ACCESS_TECHNOLOGY_GSM_EGPRS:
> > + case ACCESS_TECHNOLOGY_UTRAN_HSDPA:
> > + case ACCESS_TECHNOLOGY_UTRAN_HSUPA:
> > + case ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA:
> > + switch(modem->pref_mode) {
> > + case PREFERRED_UE_MODE_PS_VOICE_CENTRIC:
> > + /* Switch to 3G */
> > + break;
> > + case PREFERRED_UE_MODE_CS_PS_VOICE_CENTRIC:
> > + case PREFERRED_UE_MODE_CS_PS_DATA_CENTRIC:
> > + /*
> > + * All atoms needs to be created which
> is already
> > + * done.
> > + */
> > + break;
> > + default:
> > + break;
> > + }
> > + break;
> > + }
> > +}
> > +
>
> So what exactly needs to be done here?
I see this as sort of placeholder for calling enablers for managing
atoms.
Relevent calls can be made considering access tech and modem operational
mode.
This would come into play as a result of acess technology switch (CSFB
to LTE and viceversa).
Regards,
Vijay
> -----Original Message-----
> From: Denis Kenzior [mailto:denkenz(a)gmail.com]
> Sent: 11 April 2011 22:57
> To: ofono(a)ofono.org
> Cc: Nayani Vijay
> Subject: Re: [RFC PATCH 20/20] modem: Add netreg watch for tech switch
>
> Hi Vijay,
>
> > +static void netreg_status_watch(int status, int lac, int
> ci, int tech,
> > + const char *mcc, const
> char *mnc,
> > + void *data)
> > +{
> > + struct ofono_modem *modem = data;
> > +
> > + if (status != NETWORK_REGISTRATION_STATUS_REGISTERED &&
> > + status != NETWORK_REGISTRATION_STATUS_ROAMING)
> > + return;
> > +
> > + switch (tech) {
> > + case ACCESS_TECHNOLOGY_EUTRAN:
> > + switch(modem->pref_mode) {
> > + case PREFERRED_UE_MODE_PS_VOICE_CENTRIC:
> > + case PREFERRED_UE_MODE_PS_DATA_CENTRIC:
> > + /* No need to do any switching */
> > + break;
> > + case PREFERRED_UE_MODE_CS_PS_VOICE_CENTRIC:
> > + case PREFERRED_UE_MODE_CS_PS_DATA_CENTRIC:
> > + /*
> > + * All atoms needs to be created which is
> > + * already done
> > + */
> > + break;
> > + }
> > + break;
> > + case ACCESS_TECHNOLOGY_GSM:
> > + case ACCESS_TECHNOLOGY_GSM_COMPACT:
> > + case ACCESS_TECHNOLOGY_UTRAN:
> > + case ACCESS_TECHNOLOGY_GSM_EGPRS:
> > + case ACCESS_TECHNOLOGY_UTRAN_HSDPA:
> > + case ACCESS_TECHNOLOGY_UTRAN_HSUPA:
> > + case ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA:
> > + switch(modem->pref_mode) {
> > + case PREFERRED_UE_MODE_PS_VOICE_CENTRIC:
> > + /* Switch to 3G */
> > + break;
> > + case PREFERRED_UE_MODE_CS_PS_VOICE_CENTRIC:
> > + case PREFERRED_UE_MODE_CS_PS_DATA_CENTRIC:
> > + /*
> > + * All atoms needs to be created which
> is already
> > + * done.
> > + */
> > + break;
> > + default:
> > + break;
> > + }
> > + break;
> > + }
> > +}
> > +
>
> So what exactly needs to be done here?
>
> Regards,
> -Denis
>
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [RFC PATCH 09/20] modem: add preferred ue mode handling
2011-04-11 19:36 ` Denis Kenzior
@ 2011-04-12 11:42 ` Vijay.Nayani
2011-04-12 13:59 ` Denis Kenzior
0 siblings, 1 reply; 41+ messages in thread
From: Vijay.Nayani @ 2011-04-12 11:42 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1225 bytes --]
Hi Dennis,
> -----Original Message-----
> From: Denis Kenzior [mailto:denkenz(a)gmail.com]
> Sent: 11 April 2011 22:36
> To: ofono(a)ofono.org
> Cc: Nayani Vijay
> Subject: Re: [RFC PATCH 09/20] modem: add preferred ue mode handling
>
> Hi Vijay,
>
> > +static const char *preferred_ue_mode_to_string(int mode) {
> > + switch (mode) {
> > + case PREFERRED_UE_MODE_PS_DATA_CENTRIC:
> > + return "PS mode 2";
> > + case PREFERRED_UE_MODE_CS_PS_VOICE_CENTRIC:
> > + return "PS/CS mode 1";
> > + case PREFERRED_UE_MODE_CS_PS_DATA_CENTRIC:
> > + return "PS/CS mode 2";
> > + case PREFERRED_UE_MODE_PS_VOICE_CENTRIC:
> > + return "PS mode 1";
> > + }
> > +
> > + return "unknown";
> > +}
> > +
>
> These values are really not telling anyone anything. How do
> you envision the upper layers using this information?
>
Current preferred mode would show up as part of modem property for EPS
modem on the similar lines of onlne,powered,lockdown..etc.
And also this property gets signalled if preferred mode changes.This is
currently happening during the enabling modem process.
We currently don't have option to set this from user side.
> Regards,
> -Denis
>
Regards,
Vijay
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [RFC PATCH 10/20] doc: add PreferredMode property to modem
2011-04-11 19:27 ` Denis Kenzior
@ 2011-04-12 11:51 ` Vijay.Nayani
2011-04-12 14:02 ` Denis Kenzior
0 siblings, 1 reply; 41+ messages in thread
From: Vijay.Nayani @ 2011-04-12 11:51 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 2643 bytes --]
Hi Dennis,
> "data centric".
> > + "PS mode 1" UE registers only to EPS
> > + services, and
> UE's usage setting
> > + is "voice centric".
> > +
>
> I don't like that this is being exposed on the modem
> interface. This really belongs on a separate atom. Not all
> modems are going to be LTE enabled yet...
>
Preferred mode is modem property on which mode modem is going to
operate.
Currently we have restricted this to read only for below reasons.
1.No proper business case on why would user needs to play around this.
Unless operator give privilege to user to configure the modem behavior.
2.Setting the preferred mode from user side would bring in new API for
driver essentially.
Regards,
Vijay
> -----Original Message-----
> From: Denis Kenzior [mailto:denkenz(a)gmail.com]
> Sent: 11 April 2011 22:28
> To: ofono(a)ofono.org
> Cc: Nayani Vijay
> Subject: Re: [RFC PATCH 10/20] doc: add PreferredMode
> property to modem
>
> Hi Vijay,
>
> On 04/11/2011 05:20 AM, Vijay Nayani wrote:
> > ---
> > doc/modem-api.txt | 18 ++++++++++++++++++
> > 1 files changed, 18 insertions(+), 0 deletions(-)
> >
> > diff --git a/doc/modem-api.txt b/doc/modem-api.txt index
> > fa400a2..c79bffa 100644
> > --- a/doc/modem-api.txt
> > +++ b/doc/modem-api.txt
> > @@ -54,6 +54,24 @@ Properties boolean Powered [readwrite]
> > modem. The Emergency is true if an
> emergency call or
> > related operation is currently active.
> >
> > + string PreferredMode [readonly, optional]
> > +
> > + Preferred UE mode setting. A UE
> attached for EPS services
> > + shall operate in one of the following
> operation modes:
> > +
> > + "PS mode 2" UE registers only to EPS
> > + services, and
> UE's usage setting
> > + is "data centric".
> > + "CS/PS mode 1" UE registers to
> both EPS and
> > + non-EPS
> services, and UE's usage
> > + setting is
> "voice centric".
> > + "CS/PS mode 2" UE registers to
> both EPS and
> > + non-EPS
> services, and UE's usage
> > + setting is
> "data centric".
> > + "PS mode 1" UE registers only to EPS
> > + services, and
> UE's usage setting
> > + is "voice centric".
> > +
>
> I don't like that this is being exposed on the modem
> interface. This really belongs on a separate atom. Not all
> modems are going to be LTE enabled yet...
>
> Have you looked at the IMS/LTE API proposal from Sjur a while back?
>
> > string Name [readonly, optional]
> >
> > Friendly name of the modem device.
>
> Regards,
> -Denis
>
^ permalink raw reply [flat|nested] 41+ messages in thread
* RE: [RFC PATCH 17/20] atmodem: add lte specific functions
2011-04-12 3:43 ` Marcel Holtmann
@ 2011-04-12 12:48 ` Vijay.Nayani
2011-04-12 14:07 ` Denis Kenzior
0 siblings, 1 reply; 41+ messages in thread
From: Vijay.Nayani @ 2011-04-12 12:48 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 7797 bytes --]
Hi Marcel,
Let me thank for the comments.
I am happy to see default context stuff dominate our discussion which is
kind of my expectation as well.
I agree that these things are not so clear from the spec point of view
and hopeful that they will shape out via for discussion and some support
from modem friends in community.
Any how I would consider all these comments going forward.
More comments in line.
Regards
Vijay
> -----Original Message-----
> From: ofono-bounces(a)ofono.org
> [mailto:ofono-bounces(a)ofono.org] On Behalf Of Marcel Holtmann
> Sent: 12 April 2011 06:44
> To: ofono(a)ofono.org
> Subject: Re: [RFC PATCH 17/20] atmodem: add lte specific functions
>
> Hi Vijay,
>
> > +static void at_cgcontrdp_cb(gboolean ok, GAtResult
> *result, gpointer
> > +user_data) {
> > + struct ofono_packet_service *ps = user_data;
> > + struct packet_service_data *psd =
> ofono_packet_service_get_data(ps);
> > + GAtResultIter iter;
> > + int cid, bearer_id;
> > + const char *apn, *address, *gateway, *dns1, *dns2;
> > + const char *dns[3];
> > + struct ofono_default_context_param *param;
> > +
> > + if (!ok)
> > + return;
> > +
> > + g_at_result_iter_init(&iter, result);
> > +
> > + if (g_at_result_iter_next(&iter, "+CGCONTRDP:") == FALSE)
> > + return;
> > +
> > + if (g_at_result_iter_next_number(&iter, &cid) == FALSE)
> > + return;
> > +
> > + if (g_at_result_iter_next_number(&iter, &bearer_id) == FALSE)
> > + return;
> > +
> > + if (g_at_result_iter_next_string(&iter, &apn) == FALSE)
> > + return;
> > +
> > + if (g_at_result_iter_next_string(&iter, &address) == FALSE)
> > + goto out;
> > +
> > + if (g_at_result_iter_next_string(&iter, &gateway) == FALSE)
> > + goto out;
> > +
> > + if (g_at_result_iter_next_string(&iter, &dns1) == FALSE)
> > + goto out;
> > +
> > + if (g_at_result_iter_next_string(&iter, &dns2) == FALSE)
> > + goto out;
> > +
> > + dns[0] = dns1;
> > + dns[1] = dns2;
> > + dns[2] = 0;
> > +
> > +out:
> > + param = g_new0(struct ofono_default_context_param, 1);
> > + if (param == NULL)
> > + return;
> > +
> > + param->cid = cid;
> > + param->proto = psd->default_context_type;
> > + param->apn = apn;
> > + param->address = address;
> > + param->gateway = gateway;
> > + param->dns = dns;
> > +
> > + ofono_packet_service_default_context_notify(ps, param);
> > +
> > + g_free(param);
> > + param = NULL;
> > +}
> > +
> > +static void at_cgdcont_cb(gboolean ok, GAtResult *result, gpointer
> > +user_data) {
> > + struct ofono_packet_service *ps = user_data;
> > + struct packet_service_data *psd =
> ofono_packet_service_get_data(ps);
> > + GAtResultIter iter;
> > + int cid;
> > + const char *pdp_type;
> > + char buf[64];
> > + gboolean found = FALSE;
> > +
> > + if (!ok)
> > + return;
> > +
> > + g_at_result_iter_init(&iter, result);
> > +
> > + while (!found && g_at_result_iter_next(&iter, "+CGDCONT:")) {
> > + if (g_at_result_iter_next_number(&iter, &cid) == FALSE)
> > + return;
> > +
> > + if (psd->default_cid != cid)
> > + continue;
> > +
> > + g_at_result_iter_next_string(&iter, &pdp_type);
> > +
> > + found = TRUE;
> > + }
> > +
> > + if (found == FALSE)
> > + return;
> > +
> > + if (g_str_equal(pdp_type, "IP"))
> > + psd->default_context_type = OFONO_PACKET_PROTO_IP;
> > + else if (g_str_equal(pdp_type, "IPV6"))
> > + psd->default_context_type = OFONO_PACKET_PROTO_IPV6;
> > + else if (g_str_equal(pdp_type, "IPV4V6"))
> > + psd->default_context_type = OFONO_PACKET_PROTO_IPV4V6;
> > +
> > + snprintf(buf, sizeof(buf), "AT+CGCONTRDP=%i", psd->default_cid);
>
> this looks wrong to me. Reading the CGDCONT information is
> not going to help us. We should just read CGCONTRDP if
> available or CGADDR it not.
>
> If we are a dual stack, then we will see two lines of
> CGCONTRDP, if not then I assume we can tell from the address
> if we are IP or IPV6. Same applies to CGADDR in case
> CGCONTRDP is not available.
>
> And of course we need to keep CGPIAF in mind.
Agreed that we can just do with CGCONTRDP and aviod CGDCONT.
Hope you are saying to differentiate IP and IPV6 based on the address
format.
>
> For me it is also important if <IM_CN_Signalling_Flag> is set
> or not since that tells us that this is the IMS context. And
> I would expect that all networks will use that one as default context.
>
> > + g_at_chat_send(psd->chat, buf, cgcontrdp_prefix,
> at_cgcontrdp_cb,
> > +
> ps, NULL);
> > +}
> > +
> > static void at_packet_service_registration_status(
> > struct ofono_packet_service *ps,
> >
> ofono_packet_service_status_cb_t cb, @@ -138,6 +273,13 @@ static
> > void at_packet_service_registration_status(
> > break;
> > }
> >
> > + if (ofono_packet_service_get_technology(ps) ==
> > +
> ACCESS_TECHNOLOGY_EUTRAN) {
> > + if (g_at_chat_send(psd->chat, "AT+CEREG?", cereg_prefix,
> > + at_cereg_cb, cbd, g_free) > 0)
> > + return;
> > + }
> > +
> > if (g_at_chat_send(psd->chat, "AT+CGREG?", cgreg_prefix,
> > at_cgreg_cb, cbd, g_free) > 0)
> > return;
> > @@ -160,9 +302,23 @@ static void cgreg_notify(GAtResult
> *result, gpointer user_data)
> > ofono_packet_service_status_notify(ps, status); }
> >
> > +static void cereg_notify(GAtResult *result, gpointer user_data) {
> > + struct ofono_packet_service *ps = user_data;
> > + int status;
> > + struct packet_service_data *psd =
> ofono_packet_service_get_data(ps);
> > +
> > + if (at_util_parse_reg_unsolicited(result, "+CEREG:", &status,
> > + NULL, NULL, NULL, psd->vendor) == FALSE)
> > + return;
> > +
> > + ofono_packet_service_status_notify(ps, status); }
> > +
> > static void cgev_notify(GAtResult *result, gpointer user_data) {
> > struct ofono_packet_service *ps = user_data;
> > + struct packet_service_data *psd =
> ofono_packet_service_get_data(ps);
> > GAtResultIter iter;
> > const char *event;
> >
> > @@ -179,6 +335,35 @@ static void cgev_notify(GAtResult
> *result, gpointer user_data)
> > ofono_packet_service_detached_notify(ps);
> > return;
> > }
> > +
> > + if (g_str_has_prefix(event, "ME PDN ACT")) {
> > + /*
> > + * As per 27.007, this even it sent when the
> mobile termination
> > + * has activated a context. The context represents a PDN
> > + * connection in LTE or a Primary PDP context
> in GSM/UMTS.
> > + * The <cid> for this context is provided to
> the TE. This event
> > + * is sent either in result of explicit context
> activation
> > + * request (+CGACT), or in result of implicit
> context activation
> > + * request associated to attach request (+CGATT=1).
> > + */
> > + int cid;
> > +
> > + cid = g_ascii_strtoll(&event[11], NULL, 0);
> > +
> > + /*
> > + * Assumption: context id for default EPS
> context will have
> > + * value outside the ranges indicated in the
> test form of
> > + * the command +CGDCONT.
> > + */
>
> That is still an assumption that needs to be confirmed. So
> does the default context activation from just uses APN == ""
> and then the network picks the APN to activate. Or does it
> just use the APN value from CID 1 for example.
>
At this point , if the returned cid is out of range it is assumed this
would be default context (already activated).
Network has the APN and other required mandatory parameters required for
activation of default context.
This is done part of implicit attach process.
> Regards
>
> Marcel
>
>
> _______________________________________________
> ofono mailing list
> ofono(a)ofono.org
> http://lists.ofono.org/listinfo/ofono
>
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC PATCH 08/20] include: add set preferred ue mode api
2011-04-12 10:10 ` Vijay.Nayani
@ 2011-04-12 13:52 ` Denis Kenzior
0 siblings, 0 replies; 41+ messages in thread
From: Denis Kenzior @ 2011-04-12 13:52 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 664 bytes --]
Hi Vijay,
>>> +void ofono_modem_set_preferred_ue_mode(struct ofono_modem
>> *modem, int
>>> +mode);
>>> +
>>
>> Are you assuming that the UE mode cannot be changed? If so,
>> doesn't this map to +CEMODE AT command? Doesn't it allow a
>> set operation to change the UE mode?
>>
>
> We have made this currently read only as i don't see any usecase of this
> being set from user side(settings or any other).
> If a set provision need arises, this would bring in new API to driver
> side as well to do the job. Also this would be purly apply for LTE.
Then I don't see a need to even tell this information to the core then.
Regards,
-Denis
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC PATCH 17/20] atmodem: add lte specific functions
2011-04-12 10:11 ` Vijay.Nayani
@ 2011-04-12 13:56 ` Denis Kenzior
0 siblings, 0 replies; 41+ messages in thread
From: Denis Kenzior @ 2011-04-12 13:56 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1935 bytes --]
>> This is really not working out, since you still need to get
>> the interface for this context. The fact that a context is
>> active does not necessarily mean that all the resources have
>> been properly allocated.
>> Namely a gprs-context allocated and all the implications
>> (e.g. AT channel dedicated to the gprs-context is taken, ppp
>> / high speed data connection established, etc.)
>>
>> Only the core can do the context allocation, so you still
>> need to let the core decide what to do.
>>
>
> I agree on your comments here.
> Infact have missed out to put a todo here on interface assignment so
> that this can be taken up when we work with real modem.
>
Interface assignment is not going to happen here, please re-think this
entire approach. You really need to let the core allocate a context
properly.
>>> if (g_at_chat_send(psd->chat, "AT+CGREG?", cgreg_prefix,
>>> at_cgreg_cb, cbd, g_free) > 0)
>>> return;
>>
>> This is really just a bad idea. The core needs to understand
>> the concept of CEREG properly, not try to hide this in the driver.
>>
> Intention here is to hide to the core on details of registraion
> technology.
> If core needs these awareness and want to fire relevent
> API/functionality based on current access tech, would bring in new APIs
> to driver for 3G registraion status and LTE registraion status.
> This will also result in core to base it behaviour depending on acess
> technology.
Please get this idea out of your head. The core should know about LTE
specific details. Changing the core is not something to be afraid of.
The driver should not be hiding anything besides manufacturer specific
details. The philosophy behind oFono's drivers has always been to make
them dumb as rocks. If you're trying to make the driver smart, then you
are already breaking one of the primary design principles.
Regards,
-Denis
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC PATCH 20/20] modem: Add netreg watch for tech switch
2011-04-12 10:19 ` Vijay.Nayani
@ 2011-04-12 13:58 ` Denis Kenzior
0 siblings, 0 replies; 41+ messages in thread
From: Denis Kenzior @ 2011-04-12 13:58 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 491 bytes --]
Hi Vijay,
>>
>> So what exactly needs to be done here?
>
> I see this as sort of placeholder for calling enablers for managing
> atoms.
> Relevent calls can be made considering access tech and modem operational
> mode.
> This would come into play as a result of acess technology switch (CSFB
> to LTE and viceversa).
This is really too vague. Do you have an actual usecase in mind here?
Otherwise this code is really not show-casing anything right now.
Regards,
-Denis
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC PATCH 09/20] modem: add preferred ue mode handling
2011-04-12 11:42 ` Vijay.Nayani
@ 2011-04-12 13:59 ` Denis Kenzior
0 siblings, 0 replies; 41+ messages in thread
From: Denis Kenzior @ 2011-04-12 13:59 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 642 bytes --]
Hi Vijay,
>> These values are really not telling anyone anything. How do
>> you envision the upper layers using this information?
>>
>
> Current preferred mode would show up as part of modem property for EPS
> modem on the similar lines of onlne,powered,lockdown..etc.
Yes, I know what a property is ;)
> And also this property gets signalled if preferred mode changes.This is
> currently happening during the enabling modem process.
> We currently don't have option to set this from user side.
You still have not answered the question. How do you envision the UI
actually using this information.
Regards,
-Denis
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC PATCH 10/20] doc: add PreferredMode property to modem
2011-04-12 11:51 ` Vijay.Nayani
@ 2011-04-12 14:02 ` Denis Kenzior
0 siblings, 0 replies; 41+ messages in thread
From: Denis Kenzior @ 2011-04-12 14:02 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1025 bytes --]
Hi Vijay,
>> I don't like that this is being exposed on the modem
>> interface. This really belongs on a separate atom. Not all
>> modems are going to be LTE enabled yet...
>>
> Preferred mode is modem property on which mode modem is going to
> operate.
> Currently we have restricted this to read only for below reasons.
> 1.No proper business case on why would user needs to play around this.
> Unless operator give privilege to user to configure the modem behavior.
> 2.Setting the preferred mode from user side would bring in new API for
> driver essentially.
>
So again, this property is simply not going onto the Modem interface.
It doesn't belong there since not all modems will be LTE enabled. In
particular those pesky CDMA-only modems or 3G/2G GSM modems. You really
need to put this on a separate atom dealing with IMS.
And as mentioned before, I still see no actual use-case for this
property. Until the usecase is presented, this property should be dropped.
Regards,
-Denis
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [RFC PATCH 17/20] atmodem: add lte specific functions
2011-04-12 12:48 ` Vijay.Nayani
@ 2011-04-12 14:07 ` Denis Kenzior
0 siblings, 0 replies; 41+ messages in thread
From: Denis Kenzior @ 2011-04-12 14:07 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 1001 bytes --]
Hi Vijay,
>> That is still an assumption that needs to be confirmed. So
>> does the default context activation from just uses APN == ""
>> and then the network picks the APN to activate. Or does it
>> just use the APN value from CID 1 for example.
>>
>
> At this point , if the returned cid is out of range it is assumed this
> would be default context (already activated).
> Network has the APN and other required mandatory parameters required for
> activation of default context.
> This is done part of implicit attach process.
>
What Marcel is driving at is this comment from 27.007:
"The <cid>s for network-initiated PDP contexts will have values outside
the ranges indicated for the <cid> in the test form of the commands
+CGDCONT and +CGDSCONT."
Please do note that default EPS bearer is not network-initiated. It is
ME-initiated. So I currently see no basis for your assumption. Have
you checked how existing LTE modems actually do this?
Regards,
-Denis
^ permalink raw reply [flat|nested] 41+ messages in thread
end of thread, other threads:[~2011-04-12 14:07 UTC | newest]
Thread overview: 41+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-04-11 10:19 [RFC PATCH 00/20] *** LTE support with CSFB voice solution *** Vijay Nayani
2011-04-11 10:19 ` [RFC PATCH 01/20] include: add generalised packet headers Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 02/20] build: " Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 03/20] gprs: move bearer_to_string to common file Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 04/20] build: add generalised packet files Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 05/20] atmodem: add generalised packet source Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 06/20] phonesim: use generalised packet source files Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 07/20] common: add preferred_ue_mode enum Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 08/20] include: add set preferred ue mode api Vijay Nayani
2011-04-11 19:34 ` Denis Kenzior
2011-04-12 10:10 ` Vijay.Nayani
2011-04-12 13:52 ` Denis Kenzior
2011-04-11 10:20 ` [RFC PATCH 09/20] modem: add preferred ue mode handling Vijay Nayani
2011-04-11 19:36 ` Denis Kenzior
2011-04-12 11:42 ` Vijay.Nayani
2011-04-12 13:59 ` Denis Kenzior
2011-04-11 10:20 ` [RFC PATCH 10/20] doc: add PreferredMode property to modem Vijay Nayani
2011-04-11 19:27 ` Denis Kenzior
2011-04-12 11:51 ` Vijay.Nayani
2011-04-12 14:02 ` Denis Kenzior
2011-04-11 10:20 ` [RFC PATCH 11/20] modem: generalise feature map table Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 12/20] packet: add context type default Vijay Nayani
2011-04-11 19:40 ` Denis Kenzior
2011-04-12 2:49 ` Marcel Holtmann
2011-04-11 10:20 ` [RFC PATCH 13/20] include: add get technology api Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 14/20] packet: add get technology api implementation Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 15/20] include: add default context param and api Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 16/20] packet: add default context implementation Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 17/20] atmodem: add lte specific functions Vijay Nayani
2011-04-11 19:54 ` Denis Kenzior
2011-04-12 10:11 ` Vijay.Nayani
2011-04-12 13:56 ` Denis Kenzior
2011-04-12 3:43 ` Marcel Holtmann
2011-04-12 12:48 ` Vijay.Nayani
2011-04-12 14:07 ` Denis Kenzior
2011-04-11 10:20 ` [RFC PATCH 18/20] phonesim: Add cemode query implementation Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 19/20] phonesim: atoms creation based on UE mode Vijay Nayani
2011-04-11 10:20 ` [RFC PATCH 20/20] modem: Add netreg watch for tech switch Vijay Nayani
2011-04-11 19:57 ` Denis Kenzior
2011-04-12 10:19 ` Vijay.Nayani
2011-04-12 13:58 ` Denis Kenzior
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.