dnsproxy: Only one copy of the relevant buffers will be made to a TCP request
[framework/connectivity/connman.git] / src / provider.c
index 0a1e9ad..3f4bb1c 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  Connection Manager
  *
- *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2007-2012  Intel Corporation. All rights reserved.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
@@ -113,15 +113,25 @@ static void set_user_networks(struct connman_provider *provider,
 
        while (networks[i] != NULL) {
                char **elems = g_strsplit(networks[i], "/", 0);
-               char *network, *netmask = NULL;
+               char *network, *netmask;
                int family = PF_UNSPEC, ret;
 
                if (elems == NULL)
                        break;
 
                network = elems[0];
-               if (elems[1] != NULL)
-                       netmask = elems[1];
+               if (network == NULL || *network == '\0') {
+                       DBG("no network/netmask set");
+                       g_strfreev(elems);
+                       break;
+               }
+
+               netmask = elems[1];
+               if (netmask != NULL && *netmask == '\0') {
+                       DBG("no netmask set");
+                       g_strfreev(elems);
+                       break;
+               }
 
                if (g_strrstr(network, ":") != NULL)
                        family = AF_INET6;
@@ -132,7 +142,10 @@ static void set_user_networks(struct connman_provider *provider,
                                /* We have netmask length */
                                in_addr_t addr;
                                struct in_addr netmask_in;
-                               unsigned char prefix_len = atoi(netmask);
+                               unsigned char prefix_len = 32;
+
+                               if (netmask != NULL)
+                                       prefix_len = atoi(netmask);
 
                                addr = 0xffffffff << (32 - prefix_len);
                                netmask_in.s_addr = htonl(addr);
@@ -746,14 +759,52 @@ static void provider_create_all_from_type(const char *provider_type)
        g_strfreev(providers);
 }
 
+static char **get_user_networks(DBusMessageIter *array, int *count)
+{
+       DBusMessageIter entry;
+       char **networks = NULL;
+       GSList *list = NULL, *l;
+       int len;
+
+       dbus_message_iter_recurse(array, &entry);
+
+       while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
+               const char *val;
+               dbus_message_iter_get_basic(&entry, &val);
+
+               list = g_slist_prepend(list, g_strdup(val));
+               dbus_message_iter_next(&entry);
+       }
+
+       len = g_slist_length(list);
+       if (len == 0)
+               goto out;
+
+       networks = g_try_new(char *, len + 1);
+       if (networks == NULL)
+               goto out;
+
+       *count = len;
+       networks[len] = 0;
+
+       for (l = list; l != NULL; l = g_slist_next(l))
+               networks[--len] = l->data;
+
+out:
+       g_slist_free(list);
+
+       return networks;
+}
+
 int __connman_provider_create_and_connect(DBusMessage *msg)
 {
        struct connman_provider *provider;
        DBusMessageIter iter, array;
        const char *type = NULL, *name = NULL, *service_path;
        const char *host = NULL, *domain = NULL;
+       char **networks = NULL;
        char *ident;
-       int err;
+       int err, count = 0;
 
        dbus_message_iter_init(msg, &iter);
        dbus_message_iter_recurse(&iter, &array);
@@ -779,6 +830,10 @@ int __connman_provider_create_and_connect(DBusMessage *msg)
                        else if (g_str_equal(key, "VPN.Domain") == TRUE)
                                dbus_message_iter_get_basic(&value, &domain);
                        break;
+               case DBUS_TYPE_ARRAY:
+                       if (g_str_equal(key, "Networks") == TRUE)
+                               networks = get_user_networks(&value, &count);
+                       break;
                }
 
                dbus_message_iter_next(&array);
@@ -787,7 +842,7 @@ int __connman_provider_create_and_connect(DBusMessage *msg)
        if (host == NULL || domain == NULL)
                return -EINVAL;
 
-       DBG("Type %s name %s", type, name);
+       DBG("Type %s name %s networks %p", type, name, networks);
 
        if (type == NULL || name == NULL)
                return -EOPNOTSUPP;
@@ -815,6 +870,13 @@ int __connman_provider_create_and_connect(DBusMessage *msg)
                        connman_provider_load(provider);
        }
 
+       if (networks != NULL) {
+               g_strfreev(provider->user_networks);
+               provider->user_networks = networks;
+               provider->num_user_networks = count;
+               set_user_networks(provider, provider->user_networks);
+       }
+
        dbus_message_iter_init(msg, &iter);
        dbus_message_iter_recurse(&iter, &array);
 
@@ -921,6 +983,23 @@ const char *connman_provider_get_string(struct connman_provider *provider,
        return g_hash_table_lookup(provider->setting_strings, key);
 }
 
+connman_bool_t
+__connman_provider_check_routes(struct connman_provider *provider)
+{
+       if (provider == NULL)
+               return FALSE;
+
+       if (provider->user_routes != NULL &&
+                       g_hash_table_size(provider->user_routes) > 0)
+               return TRUE;
+
+       if (provider->routes != NULL &&
+                       g_hash_table_size(provider->routes) > 0)
+               return TRUE;
+
+       return FALSE;
+}
+
 void *connman_provider_get_data(struct connman_provider *provider)
 {
        return provider->driver_data;
@@ -1215,9 +1294,71 @@ static void provider_offline_mode(connman_bool_t enabled)
 
 }
 
+static struct connman_provider *provider_get(int index)
+{
+       GHashTableIter iter;
+       gpointer value, key;
+
+       g_hash_table_iter_init(&iter, provider_hash);
+
+       while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
+               struct connman_provider *provider = value;
+
+               if (provider->index == index)
+                       return provider;
+       }
+
+       return NULL;
+}
+
+static void provider_service_changed(struct connman_service *service,
+                               enum connman_service_state state)
+{
+       struct connman_provider *provider;
+       int vpn_index, service_index;
+
+       if (service == NULL)
+               return;
+
+       switch (state) {
+       case CONNMAN_SERVICE_STATE_UNKNOWN:
+       case CONNMAN_SERVICE_STATE_IDLE:
+       case CONNMAN_SERVICE_STATE_ASSOCIATION:
+       case CONNMAN_SERVICE_STATE_CONFIGURATION:
+       case CONNMAN_SERVICE_STATE_READY:
+       case CONNMAN_SERVICE_STATE_ONLINE:
+               return;
+       case CONNMAN_SERVICE_STATE_DISCONNECT:
+       case CONNMAN_SERVICE_STATE_FAILURE:
+               break;
+       }
+
+       service_index = __connman_service_get_index(service);
+
+       vpn_index = __connman_connection_get_vpn_index(service_index);
+
+       DBG("service %p %s state %d index %d/%d", service,
+               __connman_service_get_ident(service),
+               state, service_index, vpn_index);
+
+       if (vpn_index < 0)
+               return;
+
+       provider = provider_get(vpn_index);
+       if (provider == NULL)
+               return;
+
+       DBG("disconnect %p index %d", provider, vpn_index);
+
+       __connman_provider_disconnect(provider);
+
+       return;
+}
+
 static struct connman_notifier provider_notifier = {
        .name                   = "provider",
        .offline_mode           = provider_offline_mode,
+       .service_state_changed  = provider_service_changed,
 };
 
 int __connman_provider_init(void)