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 617ed05..eabc825 100644 --- a/src/gprs.c +++ b/src/gprs.c @@ -51,6 +51,10 @@ #define MAX_CONTEXTS 256 #define SUSPEND_TIMEOUT 8 +#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; @@ -96,6 +100,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 { @@ -128,6 +135,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) { @@ -464,17 +472,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)); /* @@ -1564,12 +1579,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; } @@ -1613,6 +1651,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) { @@ -1670,12 +1885,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; } @@ -1862,6 +2086,8 @@ static void gprs_unregister(struct ofono_atom *atom) gprs->dun = NULL; } + ofono_gprs_remove_sources(gprs); + ofono_modem_remove_interface(modem, OFONO_CONNECTION_MANAGER_INTERFACE); g_dbus_unregister_interface(conn, path, -- 1.7.0.4 _______________________________________________ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono