Add nameserver settings to the manual configuration setting
[framework/connectivity/connman.git] / src / network.c
index dcd64f1..74b104b 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  Connection Manager
  *
- *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2007-2010  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
@@ -65,6 +65,13 @@ struct connman_network {
                unsigned short channel;
                char *security;
                char *passphrase;
+               char *eap;
+               char *identity;
+               char *ca_cert_path;
+               char *client_cert_path;
+               char *private_key_path;
+               char *private_key_passphrase;
+               char *phase2_auth;
        } wifi;
 };
 
@@ -84,8 +91,6 @@ static const char *type2string(enum connman_network_type type)
        case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
                return "bluetooth";
        case CONNMAN_NETWORK_TYPE_CELLULAR:
-       case CONNMAN_NETWORK_TYPE_MBM:
-       case CONNMAN_NETWORK_TYPE_HSO:
                return "cellular";
        }
 
@@ -152,10 +157,17 @@ static DBusMessage *get_properties(DBusConnection *conn,
                connman_dbus_dict_append_basic(&dict, "WiFi.Channel",
                                DBUS_TYPE_UINT16, &network->wifi.channel);
 
-       if (network->wifi.security != NULL)
+       if (network->wifi.security != NULL) {
                connman_dbus_dict_append_basic(&dict, "WiFi.Security",
                                DBUS_TYPE_STRING, &network->wifi.security);
 
+               if (g_strcmp0(network->wifi.security, "ieee8021x") == 0 &&
+                                                   network->wifi.eap != NULL)
+                       connman_dbus_dict_append_basic(&dict, "WiFi.EAP",
+                                       DBUS_TYPE_STRING, &network->wifi.eap);
+       }
+
+
        if (network->wifi.passphrase != NULL &&
                        __connman_security_check_privilege(msg,
                                CONNMAN_SECURITY_PRIVILEGE_SECRET) == 0)
@@ -225,7 +237,8 @@ static void unregister_interface(struct connman_element *element)
 
        network->registered = FALSE;
 
-       emit_networks_signal(network->device);
+       if (network->device != NULL)
+               emit_networks_signal(network->device);
 
        g_dbus_unregister_interface(connection, element->path,
                                                CONNMAN_NETWORK_INTERFACE);
@@ -301,6 +314,8 @@ static void network_destruct(struct connman_element *element)
                connman_ipconfig_unref(network->ipconfig);
                network->ipconfig = NULL;
        }
+
+       network->device = NULL;
 }
 
 /**
@@ -431,6 +446,31 @@ const char *connman_network_get_path(struct connman_network *network)
  */
 void connman_network_set_index(struct connman_network *network, int index)
 {
+       struct connman_service *service;
+
+       service = __connman_service_lookup_from_network(network);
+       if (service == NULL)
+               goto done;
+
+       if (network->element.index < 0)
+               /*
+                * This is needed for plugins that havent set their ipconfig
+                * layer yet, due to not being able to get a network index
+                * prior to creating a service.
+                */
+               __connman_service_create_ipconfig(service, index);
+       else {
+               struct connman_ipconfig *ipconfig;
+
+               /* If index changed, the index of ipconfig must be reset. */
+               ipconfig = __connman_service_get_ipconfig(service);
+               if (ipconfig == NULL)
+                       goto done;
+
+               __connman_ipconfig_set_index(ipconfig, index);
+       }
+
+done:
        network->element.index = index;
 }
 
@@ -488,8 +528,6 @@ void connman_network_set_group(struct connman_network *network,
        case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
        case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
        case CONNMAN_NETWORK_TYPE_CELLULAR:
-       case CONNMAN_NETWORK_TYPE_MBM:
-       case CONNMAN_NETWORK_TYPE_HSO:
        case CONNMAN_NETWORK_TYPE_WIFI:
        case CONNMAN_NETWORK_TYPE_WIMAX:
                break;
@@ -541,8 +579,6 @@ connman_bool_t __connman_network_get_weakness(struct connman_network *network)
        case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
        case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
        case CONNMAN_NETWORK_TYPE_CELLULAR:
-       case CONNMAN_NETWORK_TYPE_MBM:
-       case CONNMAN_NETWORK_TYPE_HSO:
        case CONNMAN_NETWORK_TYPE_WIMAX:
                break;
        case CONNMAN_NETWORK_TYPE_WIFI:
@@ -638,13 +674,43 @@ static void set_associate_error(struct connman_network *network)
                                        CONNMAN_SERVICE_STATE_FAILURE);
 }
 
+static void set_configure_error(struct connman_network *network)
+{
+       struct connman_service *service;
+
+       network->connecting = FALSE;
+
+       service = __connman_service_lookup_from_network(network);
+
+       __connman_service_indicate_state(service,
+                                       CONNMAN_SERVICE_STATE_FAILURE);
+}
+
+void connman_network_set_method(struct connman_network *network,
+                                       enum connman_ipconfig_method method)
+{
+       struct connman_service *service;
+       struct connman_ipconfig *ipconfig;
+
+       network->element.ipv4.method = method;
+
+       service = __connman_service_lookup_from_network(network);
+       if (service == NULL)
+               return;
+
+       ipconfig = __connman_service_get_ipconfig(service);
+       if (ipconfig == NULL)
+               return;
+
+       connman_ipconfig_set_method(ipconfig, method);
+}
+
 void connman_network_set_error(struct connman_network *network,
                                        enum connman_network_error error)
 {
        DBG("nework %p, error %d", network, error);
 
        network->connecting = FALSE;
-       network->associating = FALSE;
 
        switch (error) {
        case CONNMAN_NETWORK_ERROR_UNKNOWN:
@@ -652,59 +718,128 @@ void connman_network_set_error(struct connman_network *network,
        case CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL:
                set_associate_error(network);
                break;
+       case CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL:
+               set_configure_error(network);
+               break;
        }
 }
 
-static gboolean set_connected(gpointer user_data)
+static void set_configuration(struct connman_network *network)
+{
+       struct connman_service *service;
+
+       DBG("network %p", network);
+
+       __connman_device_increase_connections(network->device);
+
+       __connman_device_set_network(network->device, network);
+
+       connman_device_set_disconnected(network->device, FALSE);
+
+       service = __connman_service_lookup_from_network(network);
+       __connman_service_indicate_state(service,
+                                       CONNMAN_SERVICE_STATE_CONFIGURATION);
+}
+
+static void set_connected_manual(struct connman_network *network)
 {
-       struct connman_network *network = user_data;
        struct connman_service *service;
+       struct connman_ipconfig *ipconfig;
+       const char *nameserver = NULL;
+       int err;
+
+       DBG("network %p", network);
 
        service = __connman_service_lookup_from_network(network);
 
-       if (network->connected == TRUE) {
-               struct connman_element *element;
-               enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
-
-               switch (network->protocol) {
-               case CONNMAN_NETWORK_PROTOCOL_UNKNOWN:
-                       return 0;
-               case CONNMAN_NETWORK_PROTOCOL_IP:
-                       type = CONNMAN_ELEMENT_TYPE_DHCP;
-                       break;
-               }
+       ipconfig = __connman_service_get_ipconfig(service);
 
-               __connman_device_increase_connections(network->device);
+       set_configuration(network);
 
-               __connman_device_set_network(network->device, network);
+       err = __connman_ipconfig_set_address(ipconfig);
+       if (err < 0) {
+               connman_network_set_error(network,
+                       CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
+               return;
+       }
 
-               connman_device_set_disconnected(network->device, FALSE);
+       connman_element_get_value(&network->element,
+                       CONNMAN_PROPERTY_ID_IPV4_NAMESERVER, &nameserver);
+       if (nameserver != NULL)
+               __connman_service_append_nameserver(service, nameserver);
 
-               if (network->element.ipv4.method ==
-                                       CONNMAN_IPCONFIG_METHOD_MANUAL) {
-                       network->connecting = FALSE;
+       __connman_ipconfig_set_gateway(ipconfig, &network->element);
 
-                       connman_network_set_associating(network, FALSE);
+       network->connecting = FALSE;
 
-                       __connman_service_indicate_state(service,
-                                               CONNMAN_SERVICE_STATE_READY);
+       connman_network_set_associating(network, FALSE);
 
-                       return TRUE;
-               }
+       __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY);
+}
+
+static int set_connected_dhcp(struct connman_network *network)
+{
+       struct connman_element *element;
+       int error;
 
-               element = connman_element_create(NULL);
-               if (element != NULL) {
-                       element->type  = type;
-                       element->index = network->element.index;
+       DBG("network %p", network);
 
-                       if (connman_element_register(element,
-                                               &network->element) < 0)
-                               connman_element_unref(element);
+       if (network->protocol != CONNMAN_NETWORK_PROTOCOL_IP)
+               return -EINVAL;
 
-                       __connman_service_indicate_state(service,
-                                       CONNMAN_SERVICE_STATE_CONFIGURATION);
+       element = connman_element_create(NULL);
+       if (element == NULL)
+               return -ENOMEM;
+
+       element->type  = CONNMAN_ELEMENT_TYPE_DHCP;
+       element->index = network->element.index;
+
+       error = connman_element_register(element, &network->element);
+       if (error < 0) {
+               connman_element_unref(element);
+               return error;
+       }
+
+       set_configuration(network);
+
+       return 0;
+}
+
+static gboolean set_connected(gpointer user_data)
+{
+       struct connman_network *network = user_data;
+       struct connman_service *service;
+       struct connman_ipconfig *ipconfig;
+       enum connman_ipconfig_method method;
+
+       service = __connman_service_lookup_from_network(network);
+
+       ipconfig = __connman_service_get_ipconfig(service);
+
+       method = __connman_ipconfig_get_method(ipconfig);
+
+       DBG("method %d", method);
+
+       if (network->connected == TRUE) {
+               switch (method) {
+               case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
+               case CONNMAN_IPCONFIG_METHOD_OFF:
+                       return FALSE;
+               case CONNMAN_IPCONFIG_METHOD_MANUAL:
+               case CONNMAN_IPCONFIG_METHOD_FIXED:
+                       set_connected_manual(network);
+                       return TRUE;
+               case CONNMAN_IPCONFIG_METHOD_DHCP:
+                       if (set_connected_dhcp(network) < 0) {
+                               connman_network_set_error(network,
+                                       CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
+                               return FALSE;
+                       }
                }
+
        } else {
+               struct connman_service *service;
+
                connman_element_unregister_children(&network->element);
 
                __connman_device_set_network(network->device, NULL);
@@ -712,6 +847,8 @@ static gboolean set_connected(gpointer user_data)
 
                __connman_device_decrease_connections(network->device);
 
+               service = __connman_service_lookup_from_network(network);
+
                __connman_service_indicate_state(service,
                                                CONNMAN_SERVICE_STATE_IDLE);
        }
@@ -815,8 +952,10 @@ int __connman_network_connect(struct connman_network *network)
        if (err < 0) {
                if (err == -EINPROGRESS)
                        connman_network_set_associating(network, TRUE);
-               else
+               else {
+                       network->connecting = FALSE;
                        network->hidden = FALSE;
+               }
 
                return err;
        }
@@ -853,13 +992,129 @@ int __connman_network_disconnect(struct connman_network *network)
 
        err = network->driver->disconnect(network);
        if (err == 0) {
-               network->connected = FALSE;
+               connman_network_set_connected(network, FALSE);
                set_connected(network);
        }
 
        return err;
 }
 
+static int dhcp_start(struct connman_network *network)
+{
+       struct connman_element *element;
+       int error;
+
+       if (network->protocol != CONNMAN_NETWORK_PROTOCOL_IP)
+               return -EINVAL;
+
+       element = connman_element_create(NULL);
+       if (element == NULL)
+               return -ENOMEM;
+
+       element->type  = CONNMAN_ELEMENT_TYPE_DHCP;
+       element->index = network->element.index;
+
+       error = connman_element_register(element, &network->element);
+       if (error < 0) {
+               connman_element_unref(element);
+               return error;
+       }
+
+       return 0;
+}
+
+static int dhcp_stop(struct connman_network *network)
+{
+       if (network->protocol != CONNMAN_NETWORK_PROTOCOL_IP)
+               return -EINVAL;
+
+       connman_element_unregister_children_type(&network->element,
+                                       CONNMAN_ELEMENT_TYPE_CONNECTION);
+       connman_element_unregister_children_type(&network->element,
+                                               CONNMAN_ELEMENT_TYPE_IPV4);
+       connman_element_unregister_children_type(&network->element,
+                                               CONNMAN_ELEMENT_TYPE_DHCP);
+
+       return 0;
+}
+
+static int manual_ipv4_set(struct connman_network *network,
+                               struct connman_ipconfig *ipconfig)
+{
+       struct connman_service *service;
+       int err;
+
+       service = __connman_service_lookup_from_network(network);
+       if (service == NULL)
+               return -EINVAL;
+
+       err = __connman_ipconfig_set_address(ipconfig);
+       if (err < 0) {
+               connman_network_set_error(network,
+                       CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
+               return err;
+       }
+
+       __connman_ipconfig_set_gateway(ipconfig, &network->element);
+
+       __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY);
+
+       return 0;
+}
+
+int __connman_network_clear_ipconfig(struct connman_network *network,
+                                       struct connman_ipconfig *ipconfig)
+{
+       struct connman_service *service;
+       enum connman_ipconfig_method method;
+
+       service = __connman_service_lookup_from_network(network);
+       if (service == NULL)
+               return -EINVAL;
+
+       method = __connman_ipconfig_get_method(ipconfig);
+
+       switch (method) {
+       case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
+       case CONNMAN_IPCONFIG_METHOD_OFF:
+       case CONNMAN_IPCONFIG_METHOD_FIXED:
+               return -EINVAL;
+       case CONNMAN_IPCONFIG_METHOD_MANUAL:
+               connman_element_unregister_children_type(&network->element,
+                                       CONNMAN_ELEMENT_TYPE_CONNECTION);
+               __connman_ipconfig_clear_address(ipconfig);
+               break;
+       case CONNMAN_IPCONFIG_METHOD_DHCP:
+               dhcp_stop(network);
+               break;
+       }
+
+       __connman_service_indicate_state(service,
+                                       CONNMAN_SERVICE_STATE_CONFIGURATION);
+
+       return 0;
+}
+
+int __connman_network_set_ipconfig(struct connman_network *network, struct connman_ipconfig *ipconfig)
+{
+       enum connman_ipconfig_method method;
+
+       method = __connman_ipconfig_get_method(ipconfig);
+
+       switch (method) {
+       case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
+       case CONNMAN_IPCONFIG_METHOD_OFF:
+       case CONNMAN_IPCONFIG_METHOD_FIXED:
+               return -EINVAL;
+       case CONNMAN_IPCONFIG_METHOD_MANUAL:
+               return manual_ipv4_set(network, ipconfig);
+       case CONNMAN_IPCONFIG_METHOD_DHCP:
+               return dhcp_start(network);
+       }
+
+       return 0;
+}
+
 /**
  * connman_network_set_address:
  * @network: network structure
@@ -957,6 +1212,8 @@ int connman_network_set_roaming(struct connman_network *network,
 int connman_network_set_string(struct connman_network *network,
                                        const char *key, const char *value)
 {
+       int err;
+
        DBG("network %p key %s value %s", network, key, value);
 
        if (g_strcmp0(key, "Name") == 0)
@@ -977,9 +1234,40 @@ int connman_network_set_string(struct connman_network *network,
        } else if (g_str_equal(key, "WiFi.Passphrase") == TRUE) {
                g_free(network->wifi.passphrase);
                network->wifi.passphrase = g_strdup(value);
+       } else if (g_str_equal(key, "WiFi.EAP") == TRUE) {
+               g_free(network->wifi.eap);
+               network->wifi.eap = g_strdup(value);
+       } else if (g_str_equal(key, "WiFi.Identity") == TRUE) {
+               g_free(network->wifi.identity);
+               network->wifi.identity = g_strdup(value);
+       } else if (g_str_equal(key, "WiFi.CACertFile") == TRUE) {
+               g_free(network->wifi.ca_cert_path);
+               network->wifi.ca_cert_path = g_strdup(value);
+       } else if (g_str_equal(key, "WiFi.ClientCertFile") == TRUE) {
+               g_free(network->wifi.client_cert_path);
+               network->wifi.client_cert_path = g_strdup(value);
+       } else if (g_str_equal(key, "WiFi.PrivateKeyFile") == TRUE) {
+               g_free(network->wifi.private_key_path);
+               network->wifi.private_key_path = g_strdup(value);
+       } else if (g_str_equal(key, "WiFi.PrivateKeyPassphrase") == TRUE) {
+               g_free(network->wifi.private_key_passphrase);
+               network->wifi.private_key_passphrase = g_strdup(value);
+       } else if (g_str_equal(key, "WiFi.Phase2") == TRUE) {
+               g_free(network->wifi.phase2_auth);
+               network->wifi.phase2_auth = g_strdup(value);
        }
 
-       return connman_element_set_string(&network->element, key, value);
+       err = connman_element_set_string(&network->element, key, value);
+       if (err < 0)
+               return err;
+
+       if (network->driver == NULL)
+               return 0;
+
+       if (network->driver->setup)
+               return network->driver->setup(network, key);
+
+       return 0;
 }
 
 /**
@@ -1006,6 +1294,20 @@ const char *connman_network_get_string(struct connman_network *network,
                return network->wifi.security;
        else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
                return network->wifi.passphrase;
+       else if (g_str_equal(key, "WiFi.EAP") == TRUE)
+               return network->wifi.eap;
+       else if (g_str_equal(key, "WiFi.Identity") == TRUE)
+               return network->wifi.identity;
+       else if (g_str_equal(key, "WiFi.CACertFile") == TRUE)
+               return network->wifi.ca_cert_path;
+       else if (g_str_equal(key, "WiFi.ClientCertFile") == TRUE)
+               return network->wifi.client_cert_path;
+       else if (g_str_equal(key, "WiFi.PrivateKeyFile") == TRUE)
+               return network->wifi.private_key_path;
+       else if (g_str_equal(key, "WiFi.PrivateKeyPassphrase") == TRUE)
+               return network->wifi.private_key_passphrase;
+       else if (g_str_equal(key, "WiFi.Phase2") == TRUE)
+               return network->wifi.phase2_auth;
 
        return connman_element_get_string(&network->element, key);
 }
@@ -1270,8 +1572,6 @@ static int network_probe(struct connman_element *element)
        case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
        case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
        case CONNMAN_NETWORK_TYPE_CELLULAR:
-       case CONNMAN_NETWORK_TYPE_MBM:
-       case CONNMAN_NETWORK_TYPE_HSO:
        case CONNMAN_NETWORK_TYPE_WIFI:
        case CONNMAN_NETWORK_TYPE_WIMAX:
                if (network->group != NULL)
@@ -1302,8 +1602,6 @@ static void network_remove(struct connman_element *element)
        case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
        case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
        case CONNMAN_NETWORK_TYPE_CELLULAR:
-       case CONNMAN_NETWORK_TYPE_MBM:
-       case CONNMAN_NETWORK_TYPE_HSO:
        case CONNMAN_NETWORK_TYPE_WIFI:
        case CONNMAN_NETWORK_TYPE_WIMAX:
                if (network->group != NULL) {