void vpn_died(struct connman_task *task, int exit_code, void *user_data) { struct vpn_provider *provider = user_data; struct vpn_data *data = vpn_provider_get_data(provider); int state = VPN_STATE_FAILURE; enum vpn_provider_error ret; DBG("provider %p data %p", provider, data); if (!data) goto vpn_exit; state = data->state; stop_vpn(provider); vpn_provider_set_data(provider, NULL); if (data->watch != 0) { vpn_rtnl_remove_watch(data->watch); data->watch = 0; vpn_provider_unref(provider); } vpn_exit: if (state != VPN_STATE_READY && state != VPN_STATE_DISCONNECT) { const char *name; struct vpn_driver_data *vpn_data = NULL; name = vpn_provider_get_driver_name(provider); if (name) vpn_data = g_hash_table_lookup(driver_hash, name); if (vpn_data && vpn_data->vpn_driver->error_code) ret = vpn_data->vpn_driver->error_code(provider, exit_code); else ret = VPN_PROVIDER_ERROR_UNKNOWN; vpn_provider_indicate_error(provider, ret); } else vpn_provider_set_state(provider, VPN_PROVIDER_STATE_IDLE); vpn_provider_set_index(provider, -1); if (data) { vpn_provider_unref(data->provider); g_free(data->if_name); g_free(data); } connman_task_destroy(task); }
static int vpn_disconnect(struct vpn_provider *provider) { struct vpn_data *data = vpn_provider_get_data(provider); struct vpn_driver_data *vpn_driver_data; const char *name; DBG("disconnect provider %p:", provider); if (!data) return 0; name = vpn_provider_get_driver_name(provider); if (!name) return 0; vpn_driver_data = g_hash_table_lookup(driver_hash, name); if (vpn_driver_data->vpn_driver->disconnect) vpn_driver_data->vpn_driver->disconnect(provider); if (data->watch != 0) { vpn_provider_unref(provider); vpn_rtnl_remove_watch(data->watch); data->watch = 0; } data->state = VPN_STATE_DISCONNECT; connman_task_stop(data->task); return 0; }
static void resolv_result(GResolvResultStatus status, char **results, gpointer user_data) { struct vpn_provider *provider = user_data; DBG("status %d", status); if (status == G_RESOLV_RESULT_STATUS_SUCCESS && results != NULL && g_strv_length(results) > 0) provider->host_ip = g_strdupv(results); vpn_provider_unref(provider); }
static int vpn_remove(struct vpn_provider *provider) { struct vpn_data *data; data = vpn_provider_get_data(provider); if (!data) return 0; if (data->watch != 0) { vpn_provider_unref(provider); vpn_rtnl_remove_watch(data->watch); data->watch = 0; } connman_task_stop(data->task); g_usleep(G_USEC_PER_SEC); stop_vpn(provider); return 0; }
static int vpn_connect(struct vpn_provider *provider, vpn_provider_connect_cb_t cb, const char *dbus_sender, void *user_data) { struct vpn_data *data = vpn_provider_get_data(provider); struct vpn_driver_data *vpn_driver_data; const char *name; int ret = 0; enum vpn_state state = VPN_STATE_UNKNOWN; if (data) state = data->state; DBG("data %p state %d", data, state); switch (state) { case VPN_STATE_UNKNOWN: data = g_try_new0(struct vpn_data, 1); if (!data) return -ENOMEM; data->provider = vpn_provider_ref(provider); data->watch = 0; data->flags = 0; data->task = NULL; vpn_provider_set_data(provider, data); /* fall through */ case VPN_STATE_DISCONNECT: case VPN_STATE_IDLE: case VPN_STATE_FAILURE: case VPN_STATE_AUTH_FAILURE: data->state = VPN_STATE_IDLE; break; case VPN_STATE_CONNECT: return -EINPROGRESS; case VPN_STATE_READY: return -EISCONN; } name = vpn_provider_get_driver_name(provider); if (!name) return -EINVAL; vpn_driver_data = g_hash_table_lookup(driver_hash, name); if (!vpn_driver_data || !vpn_driver_data->vpn_driver) { ret = -EINVAL; goto exist_err; } if (vpn_driver_data->vpn_driver->flags != VPN_FLAG_NO_TUN) { ret = vpn_create_tun(provider); if (ret < 0) goto exist_err; } data->task = connman_task_create(vpn_driver_data->program); if (!data->task) { ret = -ENOMEM; stop_vpn(provider); goto exist_err; } if (connman_task_set_notify(data->task, "notify", vpn_notify, provider)) { ret = -ENOMEM; stop_vpn(provider); connman_task_destroy(data->task); data->task = NULL; goto exist_err; } ret = vpn_driver_data->vpn_driver->connect(provider, data->task, data->if_name, cb, dbus_sender, user_data); if (ret < 0 && ret != -EINPROGRESS) { stop_vpn(provider); connman_task_destroy(data->task); data->task = NULL; goto exist_err; } DBG("%s started with dev %s", vpn_driver_data->provider_driver.name, data->if_name); data->state = VPN_STATE_CONNECT; return -EINPROGRESS; exist_err: vpn_provider_set_index(provider, -1); vpn_provider_set_data(provider, NULL); vpn_provider_unref(data->provider); g_free(data->if_name); g_free(data); return ret; }