static void provider_resolv_host_addr(struct vpn_provider *provider) { if (provider->host == NULL) return; if (connman_inet_check_ipaddress(provider->host) > 0) return; if (provider->host_ip != NULL) return; /* * If the hostname is not numeric, try to resolv it. We do not wait * the result as it might take some time. We will get the result * before VPN will feed routes to us because VPN client will need * the IP address also before VPN connection can be established. */ provider->resolv = g_resolv_new(0); if (provider->resolv == NULL) { DBG("Cannot resolv %s", provider->host); return; } DBG("Trying to resolv %s", provider->host); vpn_provider_ref(provider); g_resolv_lookup_hostname(provider->resolv, provider->host, resolv_result, provider); }
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; }
static DBusMessage *vpn_notify(struct connman_task *task, DBusMessage *msg, void *user_data) { struct vpn_provider *provider = user_data; struct vpn_data *data; struct vpn_driver_data *vpn_driver_data; const char *name; int state, index, err; data = vpn_provider_get_data(provider); name = vpn_provider_get_driver_name(provider); if (!name) { DBG("Cannot find VPN driver for provider %p", provider); vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE); return NULL; } vpn_driver_data = g_hash_table_lookup(driver_hash, name); if (!vpn_driver_data) { DBG("Cannot find VPN driver data for name %s", name); vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE); return NULL; } state = vpn_driver_data->vpn_driver->notify(msg, provider); DBG("provider %p driver %s state %d", provider, name, state); switch (state) { case VPN_STATE_CONNECT: case VPN_STATE_READY: if (data->state == VPN_STATE_READY) { /* * This is the restart case, in which case we must * just set the IP address. * * We need to remove first the old address, just * replacing the old address will not work as expected * because the old address will linger in the interface * and not disapper so the clearing is needed here. * * Also the state must change, otherwise the routes * will not be set properly. */ vpn_provider_set_state(provider, VPN_PROVIDER_STATE_CONNECT); vpn_provider_clear_address(provider, AF_INET); vpn_provider_clear_address(provider, AF_INET6); vpn_provider_change_address(provider); vpn_provider_set_state(provider, VPN_PROVIDER_STATE_READY); break; } index = vpn_provider_get_index(provider); vpn_provider_ref(provider); data->watch = vpn_rtnl_add_newlink_watch(index, vpn_newlink, provider); err = connman_inet_ifup(index); if (err < 0) { if (err == -EALREADY) /* * So the interface is up already, that is just * great. Unfortunately in this case the * newlink watch might not have been called at * all. We must manually call it here so that * the provider can go to ready state and the * routes are setup properly. */ vpn_newlink(IFF_UP, 0, provider); else DBG("Cannot take interface %d up err %d/%s", index, -err, strerror(-err)); } break; case VPN_STATE_UNKNOWN: case VPN_STATE_IDLE: case VPN_STATE_DISCONNECT: case VPN_STATE_FAILURE: vpn_provider_set_state(provider, VPN_PROVIDER_STATE_DISCONNECT); break; case VPN_STATE_AUTH_FAILURE: vpn_provider_indicate_error(provider, VPN_PROVIDER_ERROR_AUTH_FAILED); break; } return NULL; }