provider: Factorize VPN routing environment variables parsing
authorSamuel Ortiz <sameo@linux.intel.com>
Wed, 26 Jan 2011 23:05:10 +0000 (00:05 +0100)
committerSamuel Ortiz <sameo@linux.intel.com>
Wed, 26 Jan 2011 23:05:10 +0000 (00:05 +0100)
include/provider.h
plugins/openconnect.c
plugins/openvpn.c
src/provider.c

index 085bda3..b46033f 100644 (file)
@@ -84,9 +84,7 @@ void connman_provider_set_domain(struct connman_provider *provider,
                                                        const char *domain);
 
 int connman_provider_append_route(struct connman_provider *provider,
-                                       int family, const char *host,
-                                       const char *netmask,
-                                       const char *gateway);
+                                       const char *key, const char *value);
 
 const char *connman_provider_get_driver_name(struct connman_provider *provider);
 
index 6181046..cc8b51b 100644 (file)
@@ -27,6 +27,8 @@
 #include <errno.h>
 #include <unistd.h>
 
+#include <glib.h>
+
 #define CONNMAN_API_SUBJECT_TO_CHANGE
 #include <connman/plugin.h>
 #include <connman/provider.h>
@@ -87,6 +89,10 @@ static int oc_notify(DBusMessage *msg, struct connman_provider *provider)
                if (domain == NULL && !strcmp(key, "CISCO_DEF_DOMAIN"))
                        domain = value;
 
+               if (g_str_has_prefix(key, "CISCO_SPLIT_INC") == TRUE ||
+                       g_str_has_prefix(key, "CISCO_IPV6_SPLIT_INC") == TRUE)
+                       connman_provider_append_route(provider, key, value);
+
                dbus_message_iter_next(&dict);
        }
 
index 410cfbd..6083874 100644 (file)
 
 static DBusConnection *connection;
 
-struct ov_route {
-       int family;
-       char *host;
-       char *netmask;
-       char *gateway;
-};
-
-static void destroy_route(gpointer user_data)
-{
-       struct ov_route *route = user_data;
-
-       g_free(route->host);
-       g_free(route->netmask);
-       g_free(route->gateway);
-       g_free(route);
-}
-
-static void ov_provider_append_routes(gpointer key, gpointer value,
-                                       gpointer user_data)
-{
-       struct ov_route *route = value;
-       struct connman_provider *provider = user_data;
-
-       connman_provider_append_route(provider, route->family, route->host,
-                                       route->netmask, route->gateway);
-}
-
-static struct ov_route *ov_route_lookup(const char *key, const char *prefix_key,
-                                       GHashTable *routes)
-{
-       unsigned long idx;
-       const char *start;
-       char *end;
-       struct ov_route *route;
-
-       if (g_str_has_prefix(key, prefix_key) == FALSE)
-               return NULL;
-
-       start = key + strlen(prefix_key);
-       idx = g_ascii_strtoull(start, &end, 10);
-
-       if (idx == 0 && start == end) {
-               connman_error("string conversion failed %s", start);
-               return NULL;
-       }
-
-       route = g_hash_table_lookup(routes, GINT_TO_POINTER(idx));
-       if (route == NULL) {
-               route = g_try_new0(struct ov_route, 1);
-               if (route == NULL) {
-                       connman_error("out of memory");
-                       return NULL;
-               }
-
-               route->family = AF_INET;
-
-               g_hash_table_replace(routes, GINT_TO_POINTER(idx),
-                                               route);
-       }
-
-       return  route;
-}
-
-static void ov_append_route(const char *key, const char *value, GHashTable *routes)
-{
-       struct ov_route *route;
-
-       /*
-        * OpenVPN pushes routing tupples (host, nw, gw) as several
-        * environment values, e.g.
-        *
-        * route_gateway_2 = 10.242.2.13
-        * route_netmask_2 = 255.255.0.0
-        * route_network_2 = 192.168.0.0
-        * route_gateway_1 = 10.242.2.13
-        * route_netmask_1 = 255.255.255.255
-        * route_network_1 = 10.242.2.1
-        *
-        * The hash table is used to group the separate environment
-        * variables together. It also makes sure all tupples are
-        * complete even when OpenVPN pushes the information in a
-        * wrong order (unlikely).
-        */
-
-       route = ov_route_lookup(key, "route_network_", routes);
-       if (route != NULL) {
-               route->host = g_strdup(value);
-               return;
-       }
-
-       route = ov_route_lookup(key, "route_netmask_", routes);
-       if (route != NULL) {
-               route->netmask = g_strdup(value);
-               return;
-       }
-
-       route = ov_route_lookup(key, "route_gateway_", routes);
-       if (route != NULL)
-               route->gateway = g_strdup(value);
-}
-
 static void ov_append_dns_entries(const char *key, const char *value,
                                        char **dns_entries)
 {
@@ -179,7 +78,6 @@ static int ov_notify(DBusMessage *msg, struct connman_provider *provider)
        const char *reason, *key, *value;
        const char *domain = NULL;
        char *dns_entries = NULL;
-       GHashTable *routes;
 
        dbus_message_iter_init(msg, &iter);
 
@@ -198,9 +96,6 @@ static int ov_notify(DBusMessage *msg, struct connman_provider *provider)
 
        dbus_message_iter_recurse(&iter, &dict);
 
-       routes = g_hash_table_new_full(g_direct_hash, g_direct_equal,
-                                       NULL, destroy_route);
-
        while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
                DBusMessageIter entry;
 
@@ -220,7 +115,8 @@ static int ov_notify(DBusMessage *msg, struct connman_provider *provider)
                if (!strcmp(key, "ifconfig_remote"))
                        connman_provider_set_string(provider, "Peer", value);
 
-               ov_append_route(key, value, routes);
+               if (g_str_has_prefix(key, "network_") == TRUE)
+                       connman_provider_append_route(provider, key, value);
 
                ov_append_dns_entries(key, value, &dns_entries);
 
@@ -232,10 +128,6 @@ static int ov_notify(DBusMessage *msg, struct connman_provider *provider)
                g_free(dns_entries);
        }
 
-       g_hash_table_foreach(routes, ov_provider_append_routes, provider);
-
-       g_hash_table_destroy(routes);
-
        return VPN_STATE_CONNECT;
 }
 
index b7cba23..279cec3 100644 (file)
@@ -52,7 +52,7 @@ struct connman_provider {
        char *host;
        char *dns;
        char *domain;
-       GSList *route_list;
+       GHashTable *routes;
        struct connman_provider_driver *driver;
        void *driver_data;
 };
@@ -256,6 +256,26 @@ int __connman_provider_remove(const char *path)
        return -ENXIO;
 }
 
+static void provider_append_routes(gpointer key, gpointer value,
+                                       gpointer user_data)
+{
+       struct connman_route *route = value;
+       struct connman_provider *provider = user_data;
+       int index = provider->element.index;
+
+       if (route->family == AF_INET6) {
+               unsigned char prefix_len = atoi(route->netmask);
+
+               connman_inet_add_ipv6_network_route(index, route->host,
+                                                       route->gateway,
+                                                       prefix_len);
+       } else {
+               connman_inet_add_network_route(index, route->host,
+                                               route->gateway,
+                                               route->netmask);
+       }
+}
+
 static void provider_set_nameservers(struct connman_provider *provider)
 {
        struct connman_service *service = provider->vpn_service;
@@ -304,7 +324,6 @@ static int set_connected(struct connman_provider *provider,
        if (connected == TRUE) {
                enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
                struct connman_element *element;
-               GSList *list;
                int err;
 
                __connman_service_indicate_state(provider->vpn_service,
@@ -336,24 +355,8 @@ static int set_connected(struct connman_provider *provider,
 
                provider_set_nameservers(provider);
 
-               for (list = provider->route_list; list; list = list->next) {
-                       struct connman_route *route = list->data;
-                       int index = provider->element.index;
-
-                       if (route->family == AF_INET6) {
-                               unsigned char prefix_len = atoi(route->netmask);
-
-                               connman_inet_add_ipv6_network_route(index,
-                                                               route->host,
-                                                               route->gateway,
-                                                               prefix_len);
-                       } else {
-                               connman_inet_add_network_route(index,
-                                                       route->host,
-                                                       route->gateway,
-                                                       route->netmask);
-                       }
-               }
+               g_hash_table_foreach(provider->routes, provider_append_routes,
+                                       provider);
        } else {
                connman_element_unregister_children(&provider->element);
                __connman_service_indicate_state(service,
@@ -407,7 +410,6 @@ static void unregister_provider(gpointer data)
 static void provider_destruct(struct connman_element *element)
 {
        struct connman_provider *provider = element->private;
-       GSList *list;
 
        DBG("provider %p", provider);
 
@@ -416,15 +418,17 @@ static void provider_destruct(struct connman_element *element)
        g_free(provider->domain);
        g_free(provider->identifier);
        g_free(provider->dns);
+       g_hash_table_destroy(provider->routes);
+}
 
-       for (list = provider->route_list; list; list = list->next) {
-               struct connman_route *route = list->data;
+static void destroy_route(gpointer user_data)
+{
+       struct connman_route *route = user_data;
 
-               g_free(route->host);
-               g_free(route->netmask);
-               g_free(route->gateway);
-       }
-       g_slist_free(provider->route_list);
+       g_free(route->host);
+       g_free(route->netmask);
+       g_free(route->gateway);
+       g_free(route);
 }
 
 static void provider_initialize(struct connman_provider *provider)
@@ -447,7 +451,8 @@ static void provider_initialize(struct connman_provider *provider)
        provider->dns = NULL;
        provider->domain = NULL;
        provider->identifier = NULL;
-       provider->route_list = NULL;
+       provider->routes = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                                       NULL, destroy_route);
 }
 
 static struct connman_provider *connman_provider_new(void)
@@ -762,28 +767,109 @@ int connman_provider_get_index(struct connman_provider *provider)
        return provider->element.index;
 }
 
+enum provider_route_type {
+       PROVIDER_ROUTE_TYPE_NONE = 0,
+       PROVIDER_ROUTE_TYPE_MASK = 1,
+       PROVIDER_ROUTE_TYPE_ADDR = 2,
+       PROVIDER_ROUTE_TYPE_GW   = 3,
+};
+
+static int route_env_parse(struct connman_provider *provider, const char *key,
+                               int *family, unsigned long *idx,
+                               enum provider_route_type *type)
+{
+       char *end;
+       const char *start;
+
+       DBG("name %s", provider->name);
+
+       if (!strcmp(provider->name, "openvpn")) {
+               if (g_str_has_prefix(key, "route_network_") == TRUE) {
+                       start = key + strlen("route_network_");
+                       *type = PROVIDER_ROUTE_TYPE_ADDR;
+               } else if (g_str_has_prefix(key, "route_netmask_") == TRUE) {
+                       start = key + strlen("route_netmask_");
+                       *type = PROVIDER_ROUTE_TYPE_MASK;
+               } else if (g_str_has_prefix(key, "route_gateway_") == TRUE) {
+                       start = key + strlen("route_gateway_");
+                       *type = PROVIDER_ROUTE_TYPE_GW;
+               } else
+                       return -EINVAL;
+
+               *family = AF_INET;
+               *idx = g_ascii_strtoull(start, &end, 10);
+
+       } else if (!strcmp(provider->name, "openconnect")) {
+               if (g_str_has_prefix(key, "CISCO_SPLIT_INC_") == TRUE) {
+                       *family = AF_INET;
+                       start = key + strlen("CISCO_SPLIT_INC_");
+               } else if (g_str_has_prefix(key, "CISCO_IPV6_SPLIT_INC_") == TRUE) {
+                       *family = AF_INET6;
+                       start = key + strlen("CISCO_IPV6_SPLIT_INC_");
+               } else
+                       return -EINVAL;
+
+               *idx = g_ascii_strtoull(start, &end, 10);
+
+               if (strncmp(end, "_ADDR", 5) == 0)
+                       *type = PROVIDER_ROUTE_TYPE_ADDR;
+               else if (strncmp(end, "_MASK", 5) == 0)
+                       *type = PROVIDER_ROUTE_TYPE_MASK;
+               else if (strncmp(end, "_MASKLEN", 8) == 0 &&
+                               *family == AF_INET6) {
+                       *type = PROVIDER_ROUTE_TYPE_MASK;
+               } else
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
 int connman_provider_append_route(struct connman_provider *provider,
-                                       int family, const char *host,
-                                       const char *netmask,
-                                       const char *gateway)
+                                       const char *key, const char *value)
 {
        struct connman_route *route;
+       int ret, family = 0;
+       unsigned long idx = 0;
+       enum provider_route_type type = PROVIDER_ROUTE_TYPE_NONE;
 
-       if (family != AF_INET && family != AF_INET6)
-               return -EINVAL;
+       DBG("key %s value %s", key, value);
 
-       route = g_try_new0(struct connman_route, 1);
-       if (route == NULL)
-               return -ENOMEM;
+       ret = route_env_parse(provider, key, &family, &idx, &type);
+       if (ret < 0)
+               return ret;
 
-       route->family = family;
-       route->host = g_strdup(host);
-       route->netmask = g_strdup(netmask);
-       route->gateway = g_strdup(gateway);
+       DBG("idx %lu family %d type %d", idx, family, type);
 
-       provider->route_list = g_slist_append(provider->route_list, route);
+       route = g_hash_table_lookup(provider->routes, GINT_TO_POINTER(idx));
+       if (route == NULL) {
+               route = g_try_new0(struct connman_route, 1);
+               if (route == NULL) {
+                       connman_error("out of memory");
+                       return -ENOMEM;
+               }
+
+               route->family = family;
+
+               g_hash_table_replace(provider->routes, GINT_TO_POINTER(idx),
+                                               route);
+       }
+
+       switch (type) {
+       case PROVIDER_ROUTE_TYPE_NONE:
+               break;
+       case PROVIDER_ROUTE_TYPE_MASK:
+               route->netmask = g_strdup(value);
+               break;
+       case PROVIDER_ROUTE_TYPE_ADDR:
+               route->host = g_strdup(value);
+               break;
+       case PROVIDER_ROUTE_TYPE_GW:
+               route->gateway = g_strdup(value);
+               break;
+       }
 
-       return TRUE;
+       return 0;
 }
 
 const char *connman_provider_get_driver_name(struct connman_provider *provider)