+static const char *get_string(GHashTable *settings, const char *key)
+{
+ DBG("settings %p key %s", settings, key);
+
+ return g_hash_table_lookup(settings, key);
+}
+
+static GSList *parse_user_networks(const char *network_str)
+{
+ GSList *networks = NULL;
+ char **elems;
+ int i = 0;
+
+ if (!network_str)
+ return NULL;
+
+ elems = g_strsplit(network_str, ",", 0);
+ if (!elems)
+ return NULL;
+
+ while (elems[i]) {
+ struct vpn_route *vpn_route;
+ char *network, *netmask, *gateway;
+ int family;
+ char **route;
+
+ route = g_strsplit(elems[i], "/", 0);
+ if (!route)
+ goto next;
+
+ network = route[0];
+ if (!network || network[0] == '\0')
+ goto next;
+
+ family = connman_inet_check_ipaddress(network);
+ if (family < 0) {
+ DBG("Cannot get address family of %s (%d/%s)", network,
+ family, gai_strerror(family));
+
+ goto next;
+ }
+
+ switch (family) {
+ case AF_INET:
+ break;
+ case AF_INET6:
+ break;
+ default:
+ DBG("Unsupported address family %d", family);
+ goto next;
+ }
+
+ netmask = route[1];
+ if (!netmask || netmask[0] == '\0')
+ goto next;
+
+ gateway = route[2];
+
+ vpn_route = g_try_new0(struct vpn_route, 1);
+ if (!vpn_route) {
+ g_strfreev(route);
+ break;
+ }
+
+ vpn_route->family = family;
+ vpn_route->network = g_strdup(network);
+ vpn_route->netmask = g_strdup(netmask);
+ vpn_route->gateway = g_strdup(gateway);
+
+ DBG("route %s/%s%s%s", network, netmask,
+ gateway ? " via " : "", gateway ? gateway : "");
+
+ networks = g_slist_prepend(networks, vpn_route);
+
+ next:
+ g_strfreev(route);
+ i++;
+ }
+
+ g_strfreev(elems);
+
+ return g_slist_reverse(networks);
+}
+
+int __vpn_provider_create_from_config(GHashTable *settings,
+ const char *config_ident,
+ const char *config_entry)
+{
+ struct vpn_provider *provider;
+ const char *type, *name, *host, *domain, *networks_str;
+ GSList *networks;
+ char *ident = NULL;
+ GHashTableIter hash;
+ gpointer value, key;
+ int err;
+
+ type = get_string(settings, "Type");
+ name = get_string(settings, "Name");
+ host = get_string(settings, "Host");
+ domain = get_string(settings, "Domain");
+ networks_str = get_string(settings, "Networks");
+ networks = parse_user_networks(networks_str);
+
+ if (!host || !domain) {
+ err = -EINVAL;
+ goto fail;
+ }
+
+ DBG("type %s name %s networks %s", type, name, networks_str);
+
+ if (!type || !name) {
+ err = -EOPNOTSUPP;
+ goto fail;
+ }
+
+ ident = __vpn_provider_create_identifier(host, domain);
+ DBG("ident %s", ident);
+
+ provider = __vpn_provider_lookup(ident);
+ if (!provider) {
+ provider = vpn_provider_get(ident);
+ if (!provider) {
+ DBG("can not create provider");
+ err = -EOPNOTSUPP;
+ goto fail;
+ }
+
+ provider->host = g_strdup(host);
+ provider->domain = g_strdup(domain);
+ provider->name = g_strdup(name);
+ provider->type = g_ascii_strdown(type, -1);
+
+ provider->config_file = g_strdup(config_ident);
+ provider->config_entry = g_strdup(config_entry);
+
+ provider_register(provider);
+
+ provider_resolv_host_addr(provider);
+ }
+
+ if (networks) {
+ g_slist_free_full(provider->user_networks, free_route);
+ provider->user_networks = networks;
+ set_user_networks(provider, provider->user_networks);
+ }
+
+ g_hash_table_iter_init(&hash, settings);
+
+ while (g_hash_table_iter_next(&hash, &key, &value))
+ __vpn_provider_set_string_immutable(provider, key, value);
+
+ provider->immutable = true;
+
+ vpn_provider_save(provider);
+
+ err = provider_register(provider);
+ if (err != 0 && err != -EALREADY)
+ goto fail;
+
+ connection_register(provider);
+
+ DBG("provider %p index %d path %s", provider, provider->index,
+ provider->path);
+
+ connection_added_signal(provider);
+
+ g_free(ident);
+
+ return 0;
+
+fail:
+ g_free(ident);
+ g_slist_free_full(networks, free_route);
+
+ return err;
+}
+