Implement dial up networking in GPRS atom.
---
src/gprs.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 229 insertions(+), 3 deletions(-)
diff --git a/src/gprs.c b/src/gprs.c
index 2313f52..95f7ab2 100644
--- a/src/gprs.c
+++ b/src/gprs.c
@@ -49,6 +49,10 @@
#define MAX_CONTEXT_NAME_LENGTH 127
#define MAX_CONTEXTS 256
+#define DUN_LOCAL "192.168.1.1"
+#define DUN_PEER "192.168.1.2"
+#define DUN_CONNECT_TIMEOUT 20
+
static GSList *g_drivers = NULL;
static GSList *g_context_drivers = NULL;
@@ -92,6 +96,9 @@ struct ofono_gprs {
unsigned int dun_watch;
unsigned int dun_status_watch;
struct gprs_dun_data dun_data;
+ int attach_source;
+ int context_source;
+ int timeout_source;
};
struct ofono_gprs_context {
@@ -124,6 +131,7 @@ struct pri_context {
};
static void gprs_netreg_update(struct ofono_gprs *gprs);
+static gboolean dun_connect_remove(gpointer user_data);
static const char *gprs_context_type_to_string(int type)
{
@@ -453,17 +461,24 @@ static void pri_activate_callback(const struct ofono_error *error,
if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
DBG("Activating context failed with error: %s",
telephony_error_to_str(error));
- __ofono_dbus_pending_reply(&gc->pending,
+
+ if (gc->pending)
+ __ofono_dbus_pending_reply(&gc->pending,
__ofono_error_failed(gc->pending));
gprs_cid_release(ctx->gprs, ctx->context.cid);
ctx->context.cid = 0;
+ if (ctx->gprs->dun)
+ dun_connect_remove(ctx->gprs);
+
return;
}
ctx->active = TRUE;
- __ofono_dbus_pending_reply(&gc->pending,
+
+ if (gc->pending)
+ __ofono_dbus_pending_reply(&gc->pending,
dbus_message_new_method_return(gc->pending));
/* If we don't have the interface, don't bother emitting any settings,
@@ -1488,12 +1503,35 @@ void ofono_gprs_set_cid_range(struct ofono_gprs *gprs,
gprs->cid_map = idmap_new_from_range(min, max);
}
+static void ofono_gprs_remove_sources(struct ofono_gprs *gprs)
+{
+ if (gprs == NULL)
+ return;
+
+ if (gprs->timeout_source) {
+ g_source_remove(gprs->timeout_source);
+ gprs->timeout_source = 0;
+ }
+
+ if (gprs->attach_source) {
+ g_source_remove(gprs->attach_source);
+ gprs->attach_source = 0;
+ }
+
+ if (gprs->context_source) {
+ g_source_remove(gprs->context_source);
+ gprs->context_source = 0;
+ }
+}
+
static void gprs_context_unregister(struct ofono_atom *atom)
{
struct ofono_gprs_context *gc = __ofono_atom_get_data(atom);
- if (gc->gprs)
+ if (gc->gprs) {
gc->gprs->context_driver = NULL;
+ ofono_gprs_remove_sources(gc->gprs);
+ }
gc->gprs = NULL;
}
@@ -1538,6 +1576,183 @@ void ofono_gprs_context_deactivated(struct ofono_gprs_context
*gc,
}
}
+static ofono_bool_t set_primary_context_powered(struct pri_context *ctx,
+ ofono_bool_t value)
+{
+ struct ofono_gprs_context *gc = ctx->gprs->context_driver;
+
+ if (gc == NULL || gc->driver->activate_primary == NULL ||
+ gc->driver->deactivate_primary == NULL ||
+ ctx->gprs->cid_map == NULL)
+ return FALSE;
+
+ if (gc->pending)
+ return FALSE;
+
+ if (ctx->active == value)
+ return FALSE;
+
+ if (value && !ctx->gprs->attached)
+ return FALSE;
+
+ if (ctx->gprs->flags & GPRS_FLAG_ATTACHING)
+ return FALSE;
+
+ if (value) {
+ ctx->context.cid = gprs_cid_alloc(ctx->gprs);
+
+ if (ctx->context.cid == 0)
+ return FALSE;
+
+ if (ctx->context.cid !=
+ idmap_get_min(ctx->gprs->cid_map)) {
+ ofono_error("Multiple active contexts are"
+ " not yet supported");
+
+ gprs_cid_release(ctx->gprs, ctx->context.cid);
+ ctx->context.cid = 0;
+
+ return FALSE;
+ }
+ }
+
+ if (value)
+ gc->driver->activate_primary(gc, &ctx->context,
+ pri_activate_callback, ctx);
+ else
+ gc->driver->deactivate_primary(gc, ctx->context.cid,
+ pri_deactivate_callback, ctx);
+
+ return TRUE;
+}
+
+static void ofono_gprs_dun_disconnect(struct ofono_gprs *gprs,
+ struct ofono_emulator_req *req)
+{
+ struct pri_context *context = gprs->dun_data.context;
+
+ ofono_gprs_remove_sources(gprs);
+
+ if (context->active) {
+ struct ofono_gprs_context *gc = gprs->context_driver;
+
+ gc->driver->deactivate_primary(gc, context->context.cid,
+ gprs_deactivate_for_remove, context);
+ } else
+ remove_context(context);
+}
+
+static gboolean dun_connect_remove(gpointer user_data)
+{
+ struct ofono_gprs *gprs = user_data;
+ struct gprs_dun_data *data = &gprs->dun_data;
+ struct ofono_error error;
+
+ ofono_gprs_remove_sources(gprs);
+ remove_context(data->context);
+
+ error.type = OFONO_ERROR_TYPE_FAILURE;
+ data->cb(&error, NULL, NULL, NULL, NULL, data->cb_data);
+
+ data->cb = NULL;
+ data->cb_data = NULL;
+ data->context = NULL;
+ data->dun = NULL;
+
+ return FALSE;
+}
+
+static gboolean pri_context_update(gpointer user_data)
+{
+ struct ofono_gprs *gprs = user_data;
+ struct gprs_dun_data *data = &gprs->dun_data;
+ struct pri_context *context = data->context;
+ struct context_settings *settings = context->settings;
+ struct ofono_error error;
+
+ DBG("active %d\n", context->active);
+
+ if (context->active != TRUE)
+ return TRUE;
+
+ gprs->context_source = 0;
+ g_source_remove(gprs->timeout_source);
+
+ error.type = OFONO_ERROR_TYPE_NO_ERROR;
+
+ data->cb(&error, settings->interface, DUN_LOCAL, DUN_PEER,
+ (const char **)settings->dns,
+ data->cb_data);
+
+ return FALSE;
+}
+
+static gboolean gprs_attach_update(gpointer user_data)
+{
+ struct ofono_gprs *gprs = user_data;
+ struct gprs_dun_data *data = &gprs->dun_data;
+ struct pri_context *context = data->context;
+
+ DBG("attached %d driver attached %d\n", gprs->attached,
+ gprs->driver_attached);
+
+ if (gprs->attached != TRUE || gprs->driver_attached != TRUE)
+ return TRUE;
+
+ gprs->attach_source = 0;
+
+ if (context->active != TRUE) {
+ set_primary_context_powered(context, TRUE);
+
+ /* wait until the primary context is actived */
+ gprs->context_source = g_timeout_add_seconds(1,
+ pri_context_update, gprs);
+ return FALSE;
+ }
+
+ pri_context_update(gprs);
+
+ return FALSE;
+}
+
+static void ofono_gprs_dun_connect(struct ofono_gprs *gprs,
+ struct ofono_emulator_gprs_connect_req *req)
+{
+ const char *dial_str = req->dial_str;
+ struct gprs_dun_data *data = &gprs->dun_data;
+ struct ofono_error error;
+
+ DBG("%s", dial_str);
+
+ if (data->context == NULL)
+ goto error;
+
+ data->cb = req->cb;
+ data->cb_data = req->cb_data;
+
+ gprs->timeout_source = g_timeout_add_seconds(DUN_CONNECT_TIMEOUT,
+ dun_connect_remove, gprs);
+
+ /* check gprs attaching status */
+ if (!gprs->powered || !gprs->attached || !gprs->driver_attached) {
+ gprs->powered = TRUE;
+
+ gprs_netreg_update(gprs);
+
+ /* wait until GPRS is attached */
+ gprs->attach_source = g_timeout_add_seconds(1,
+ gprs_attach_update, gprs);
+ return;
+ }
+
+ gprs_attach_update(gprs);
+
+ return;
+error:
+ error.type = OFONO_ERROR_TYPE_FAILURE;
+ req->cb(&error, NULL, NULL, NULL, NULL, req->cb_data);
+}
+
static void ofono_gprs_set_cgatt(struct ofono_gprs *gprs,
struct ofono_emulator_req *req)
{
@@ -1602,12 +1817,21 @@ static void dun_status_watch(struct ofono_emulator *e,
return;
switch (status) {
+ case OFONO_EMULATOR_STATUS_DUN_CONNECT:
+ ofono_gprs_dun_connect(gprs, data);
+ break;
+ case OFONO_EMULATOR_STATUS_DUN_DISCONNECTED:
+ ofono_gprs_dun_disconnect(gprs, data);
+ break;
case OFONO_EMULATOR_STATUS_SET_CGATT:
ofono_gprs_set_cgatt(gprs, data);
break;
case OFONO_EMULATOR_STATUS_SET_CGDCONT:
ofono_gprs_set_cgdcont(gprs, data);
break;
+ case OFONO_EMULATOR_STATUS_DESTROY:
+ ofono_gprs_remove_sources(gprs);
+ break;
default:
break;
}
@@ -1794,6 +2018,8 @@ static void gprs_unregister(struct ofono_atom *atom)
gprs->dun = NULL;
}
+ ofono_gprs_remove_sources(gprs);
+
ofono_modem_remove_interface(modem,
OFONO_DATA_CONNECTION_MANAGER_INTERFACE);
g_dbus_unregister_interface(conn, path,
--
1.7.0.4