diff options
author | Tobias Brunner <tobias@strongswan.org> | 2010-09-30 13:46:50 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2010-10-14 17:36:19 +0200 |
commit | ef247379eaf9b8341d7c2e902c083eb1f1008535 (patch) | |
tree | b1efdf98a03dc1595ed9758ea286c85a2c775cf5 /src/libcharon/plugins/maemo/maemo_service.c | |
parent | 6f599713713813cb7636f3b43c88484660f8eef0 (diff) | |
download | strongswan-ef247379eaf9b8341d7c2e902c083eb1f1008535.tar.bz2 strongswan-ef247379eaf9b8341d7c2e902c083eb1f1008535.tar.xz |
Maemo: Track the status of the current SA and send changes to the frontend.
Diffstat (limited to 'src/libcharon/plugins/maemo/maemo_service.c')
-rw-r--r-- | src/libcharon/plugins/maemo/maemo_service.c | 128 |
1 files changed, 97 insertions, 31 deletions
diff --git a/src/libcharon/plugins/maemo/maemo_service.c b/src/libcharon/plugins/maemo/maemo_service.c index 3dc61292e..fb28a8fba 100644 --- a/src/libcharon/plugins/maemo/maemo_service.c +++ b/src/libcharon/plugins/maemo/maemo_service.c @@ -32,6 +32,14 @@ #define OSSO_CHARON_OBJECT "/org/strongswan/"OSSO_CHARON_NAME #define OSSO_CHARON_IFACE "org.strongswan."OSSO_CHARON_NAME +typedef enum { + VPN_STATUS_DISCONNECTED, + VPN_STATUS_CONNECTING, + VPN_STATUS_CONNECTED, + VPN_STATUS_AUTH_FAILED, + VPN_STATUS_CONNECTION_FAILED, +} vpn_status_t; + typedef struct private_maemo_service_t private_maemo_service_t; /** @@ -60,11 +68,16 @@ struct private_maemo_service_t { osso_context_t *context; /** - * current IKE_SA + * Current IKE_SA */ ike_sa_t *ike_sa; /** + * Status of the current connection + */ + vpn_status_t status; + + /** * Name of the current connection */ gchar *current; @@ -75,6 +88,7 @@ static gint change_status(private_maemo_service_t *this, int status) { osso_rpc_t retval; gint res; + this->status = status; res = osso_rpc_run (this->context, OSSO_STATUS_SERVICE, OSSO_STATUS_OBJECT, OSSO_STATUS_IFACE, "StatusChanged", &retval, DBUS_TYPE_INT32, status, @@ -85,6 +99,13 @@ static gint change_status(private_maemo_service_t *this, int status) METHOD(listener_t, ike_updown, bool, private_maemo_service_t *this, ike_sa_t *ike_sa, bool up) { + /* this callback is only registered during initiation, so if the IKE_SA + * goes down we assume an authentication error */ + if (this->ike_sa == ike_sa && !up) + { + change_status(this, VPN_STATUS_AUTH_FAILED); + return FALSE; + } return TRUE; } @@ -92,6 +113,12 @@ METHOD(listener_t, child_state_change, bool, private_maemo_service_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, child_sa_state_t state) { + /* this call back is only registered during initiation */ + if (this->ike_sa == ike_sa && state == CHILD_DESTROYING) + { + change_status(this, VPN_STATUS_CONNECTION_FAILED); + return FALSE; + } return TRUE; } @@ -99,6 +126,21 @@ METHOD(listener_t, child_updown, bool, private_maemo_service_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, bool up) { + if (this->ike_sa == ike_sa) + { + if (up) + { + /* disable hooks registered to catch initiation failures */ + this->public.listener.ike_updown = NULL; + this->public.listener.child_state_change = NULL; + change_status(this, VPN_STATUS_CONNECTED); + } + else + { + change_status(this, VPN_STATUS_CONNECTION_FAILED); + return FALSE; + } + } return TRUE; } @@ -112,12 +154,39 @@ METHOD(listener_t, ike_rekey, bool, return TRUE; } +static void disconnect(private_maemo_service_t *this) +{ + ike_sa_t *ike_sa; + u_int id; + + if (!this->current) + { + return; + } + + /* avoid status updates, as this is called from the Glib main loop */ + charon->bus->remove_listener(charon->bus, &this->public.listener); + + ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager, + this->current, FALSE); + if (ike_sa) + { + id = ike_sa->get_unique_id(ike_sa); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + charon->controller->terminate_ike(charon->controller, id, + NULL, NULL); + } + this->current = (g_free(this->current), NULL); + this->status = VPN_STATUS_DISCONNECTED; +} + static gboolean initiate_connection(private_maemo_service_t *this, GArray *arguments) { gint i; gchar *hostname = NULL, *cacert = NULL, *username = NULL, *password = NULL; identification_t *gateway = NULL, *user = NULL; + ike_sa_t *ike_sa; ike_cfg_t *ike_cfg; peer_cfg_t *peer_cfg; child_cfg_t *child_cfg; @@ -132,11 +201,12 @@ static gboolean initiate_connection(private_maemo_service_t *this, } }; - if (this->current) + if (this->status == VPN_STATUS_CONNECTED || + this->status == VPN_STATUS_CONNECTING) { - DBG1(DBG_CFG, "currently connected to '%s', disconnect first", + DBG1(DBG_CFG, "currently connected to '%s', disconnecting first", this->current); - return FALSE; + disconnect (this); } if (arguments->len != 5) @@ -151,12 +221,12 @@ static gboolean initiate_connection(private_maemo_service_t *this, if (arg->type != DBUS_TYPE_STRING) { DBG1(DBG_CFG, "invalid argument [%d]: %d", i, arg->type); - this->current = (g_free(this->current), NULL); return FALSE; } switch (i) { case 0: /* name */ + this->current = (g_free(this->current), NULL); this->current = g_strdup(arg->value.s); break; case 1: /* hostname */ @@ -236,36 +306,33 @@ static gboolean initiate_connection(private_maemo_service_t *this, /* get an additional reference because initiate consumes one */ child_cfg->get_ref(child_cfg); - if (charon->controller->initiate(charon->controller, peer_cfg, child_cfg, - controller_cb_empty, NULL) != SUCCESS) + /* get us an IKE_SA */ + ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, + peer_cfg); + if (!ike_sa->get_peer_cfg(ike_sa)) { - DBG1(DBG_CFG, "failed to initiate tunnel"); - this->current = (g_free(this->current), NULL); - return FALSE; + ike_sa->set_peer_cfg(ike_sa, peer_cfg); } - return TRUE; -} + peer_cfg->destroy(peer_cfg); -static void disconnect(private_maemo_service_t *this) -{ - ike_sa_t *ike_sa; - u_int id; - - if (!this->current) - { - return; - } + /* store the IKE_SA, so we can track its progress */ + this->ike_sa = ike_sa; + this->status = VPN_STATUS_CONNECTING; + this->public.listener.ike_updown = _ike_updown; + this->public.listener.child_state_change = _child_state_change; + charon->bus->add_listener(charon->bus, &this->public.listener); - ike_sa = charon->ike_sa_manager->checkout_by_name(charon->ike_sa_manager, - this->current, FALSE); - if (ike_sa) + if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS) { - id = ike_sa->get_unique_id(ike_sa); - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - charon->controller->terminate_ike(charon->controller, id, - NULL, NULL); + DBG1(DBG_CFG, "failed to initiate tunnel"); + charon->bus->remove_listener(charon->bus, &this->public.listener); + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, + ike_sa); + this->status = VPN_STATUS_CONNECTION_FAILED; + return FALSE; } - this->current = (g_free(this->current), NULL); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + return TRUE; } /** @@ -329,6 +396,7 @@ METHOD(maemo_service_t, destroy, void, charon->bus->remove_listener(charon->bus, &this->public.listener); lib->credmgr->remove_set(lib->credmgr, &this->creds->set); this->creds->destroy(this->creds); + this->current = (g_free(this->current), NULL); free(this); } @@ -382,8 +450,6 @@ maemo_service_t *maemo_service_create() g_thread_init(NULL); } - charon->bus->add_listener(charon->bus, &this->public.listener); - lib->processor->queue_job(lib->processor, (job_t*)callback_job_create((callback_job_cb_t)run, this, NULL, NULL)); |