X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fnetwork.c;h=6fe1d9c5e586c1d35b12fc6239d10d0c988e1914;hb=b93f2462a3dc6cc00810ed28b87a5c05516c0921;hp=10a78ae25823af9b4b68635d10eee7fefc58e993;hpb=f18278f58d3099b732995daa19202317eed8e6cc;p=framework%2Fconnectivity%2Fconnman.git diff --git a/src/network.c b/src/network.c index 10a78ae..6fe1d9c 100644 --- a/src/network.c +++ b/src/network.c @@ -2,7 +2,7 @@ * * Connection Manager * - * Copyright (C) 2007-2009 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 @@ -26,33 +26,44 @@ #include #include -#include - #include "connman.h" -static unsigned int hidden_counter = 0; +/* + * How many times to send RS with the purpose of + * refreshing RDNSS entries before they actually expire. + * With a value of 1, one RS will be sent, with no retries. + */ +#define RS_REFRESH_COUNT 1 + +/* + * Value in seconds to wait for RA after RS was sent. + * After this time elapsed, we can send another RS. + */ +#define RS_REFRESH_TIMEOUT 3 + +static GSList *network_list = NULL; +static GSList *driver_list = NULL; struct connman_network { - struct connman_element element; + int refcount; enum connman_network_type type; - enum connman_network_protocol protocol; connman_bool_t available; connman_bool_t connected; connman_bool_t roaming; - connman_bool_t hidden; connman_uint8_t strength; connman_uint16_t frequency; char *identifier; - char *address; char *name; char *node; char *group; - struct connman_ipconfig *ipconfig; + char *path; + int index; + int router_solicit_count; + int router_solicit_refresh_count; struct connman_network_driver *driver; void *driver_data; - connman_bool_t registered; connman_bool_t connecting; connman_bool_t associating; @@ -65,7 +76,24 @@ struct connman_network { unsigned short channel; char *security; char *passphrase; + char *agent_passphrase; + char *eap; + char *identity; + char *agent_identity; + char *ca_cert_path; + char *client_cert_path; + char *private_key_path; + char *private_key_passphrase; + char *phase2_auth; + connman_bool_t wps; + connman_bool_t use_wps; + char *pin_wps; } wifi; + + struct { + char *nsp_name; + int nsp_name_len; + } wimax; }; static const char *type2string(enum connman_network_type type) @@ -84,185 +112,159 @@ 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"; } return NULL; } -static DBusMessage *get_properties(DBusConnection *conn, - DBusMessage *msg, void *data) +static gboolean match_driver(struct connman_network *network, + struct connman_network_driver *driver) { - struct connman_network *network = data; - DBusMessage *reply; - DBusMessageIter array, dict; - - DBG("conn %p", conn); - - if (__connman_security_check_privilege(msg, - CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0) - return __connman_error_permission_denied(msg); - - reply = dbus_message_new_method_return(msg); - if (reply == NULL) - return NULL; - - dbus_message_iter_init_append(reply, &array); - - connman_dbus_dict_open(&array, &dict); + if (network->type == driver->type || + driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN) + return TRUE; - if (network->device) { - const char *path = connman_device_get_path(network->device); - if (path != NULL) - connman_dbus_dict_append_variant(&dict, "Device", - DBUS_TYPE_OBJECT_PATH, &path); - } + return FALSE; +} - if (network->address != NULL) - connman_dbus_dict_append_variant(&dict, "Address", - DBUS_TYPE_STRING, &network->address); +static int network_probe(struct connman_network *network) +{ + GSList *list; + struct connman_network_driver *driver = NULL; - if (network->name != NULL) - connman_dbus_dict_append_variant(&dict, "Name", - DBUS_TYPE_STRING, &network->name); + DBG("network %p name %s", network, network->name); - connman_dbus_dict_append_variant(&dict, "Connected", - DBUS_TYPE_BOOLEAN, &network->connected); + if (network->driver != NULL) + return -EALREADY; - if (network->strength > 0) - connman_dbus_dict_append_variant(&dict, "Strength", - DBUS_TYPE_BYTE, &network->strength); + for (list = driver_list; list; list = list->next) { + driver = list->data; - if (network->frequency > 0) - connman_dbus_dict_append_variant(&dict, "Frequency", - DBUS_TYPE_UINT16, &network->frequency); + if (match_driver(network, driver) == FALSE) + continue; - if (network->wifi.ssid != NULL && network->wifi.ssid_len > 0) - connman_dbus_dict_append_fixed_array(&dict, "WiFi.SSID", - DBUS_TYPE_BYTE, &network->wifi.ssid, - network->wifi.ssid_len); + DBG("driver %p name %s", driver, driver->name); - if (network->wifi.mode != NULL) - connman_dbus_dict_append_variant(&dict, "WiFi.Mode", - DBUS_TYPE_STRING, &network->wifi.mode); + if (driver->probe(network) == 0) + break; - if (network->wifi.channel > 0) - connman_dbus_dict_append_variant(&dict, "WiFi.Channel", - DBUS_TYPE_UINT16, &network->wifi.channel); + driver = NULL; + } - if (network->wifi.security != NULL) - connman_dbus_dict_append_variant(&dict, "WiFi.Security", - DBUS_TYPE_STRING, &network->wifi.security); + if (driver == NULL) + return -ENODEV; - if (network->wifi.passphrase != NULL && - __connman_security_check_privilege(msg, - CONNMAN_SECURITY_PRIVILEGE_SECRET) == 0) - connman_dbus_dict_append_variant(&dict, "WiFi.Passphrase", - DBUS_TYPE_STRING, &network->wifi.passphrase); + if (network->group == NULL) + return -EINVAL; - connman_dbus_dict_close(&array, &dict); + switch (network->type) { + case CONNMAN_NETWORK_TYPE_UNKNOWN: + case CONNMAN_NETWORK_TYPE_VENDOR: + return 0; + case CONNMAN_NETWORK_TYPE_ETHERNET: + case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN: + case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN: + case CONNMAN_NETWORK_TYPE_CELLULAR: + case CONNMAN_NETWORK_TYPE_WIFI: + case CONNMAN_NETWORK_TYPE_WIMAX: + network->driver = driver; + if (__connman_service_create_from_network(network) == NULL) { + network->driver = NULL; + return -EINVAL; + } + } - return reply; + return 0; } -static GDBusMethodTable network_methods[] = { - { "GetProperties", "", "a{sv}", get_properties }, - { }, -}; - -static GDBusSignalTable network_signals[] = { - { "PropertyChanged", "sv" }, - { }, -}; +static void network_remove(struct connman_network *network) +{ + DBG("network %p name %s", network, network->name); -static DBusConnection *connection; + if (network->driver == NULL) + return; -static void append_networks(struct connman_device *device, - DBusMessageIter *entry) -{ - DBusMessageIter value, iter; - const char *key = "Networks"; + connman_network_set_connected(network, FALSE); - dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key); + switch (network->type) { + case CONNMAN_NETWORK_TYPE_UNKNOWN: + case CONNMAN_NETWORK_TYPE_VENDOR: + break; + case CONNMAN_NETWORK_TYPE_ETHERNET: + case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN: + case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN: + case CONNMAN_NETWORK_TYPE_CELLULAR: + case CONNMAN_NETWORK_TYPE_WIFI: + case CONNMAN_NETWORK_TYPE_WIMAX: + if (network->group != NULL) { + __connman_service_remove_from_network(network); - dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, - DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING, - &value); + g_free(network->group); + network->group = NULL; + } + break; + } - dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, - DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter); - __connman_element_list((struct connman_element *) device, - CONNMAN_ELEMENT_TYPE_NETWORK, &iter); - dbus_message_iter_close_container(&value, &iter); + if (network->driver->remove) + network->driver->remove(network); - dbus_message_iter_close_container(entry, &value); + network->driver = NULL; } -static void emit_networks_signal(struct connman_device *device) +static void network_change(struct connman_network *network) { - const char *path = connman_device_get_path(device); - DBusMessage *signal; - DBusMessageIter entry; + DBG("network %p name %s", network, network->name); - signal = dbus_message_new_signal(path, - CONNMAN_DEVICE_INTERFACE, "PropertyChanged"); - if (signal == NULL) + if (network->connected == FALSE) return; - dbus_message_iter_init_append(signal, &entry); + connman_device_set_disconnected(network->device, TRUE); - append_networks(device, &entry); + if (network->driver && network->driver->disconnect) { + network->driver->disconnect(network); + return; + } - g_dbus_send_message(connection, signal); + network->connected = FALSE; } -static int register_interface(struct connman_element *element) +static void probe_driver(struct connman_network_driver *driver) { - struct connman_network *network = element->network; + GSList *list; - DBG("element %p name %s", element, element->name); + DBG("driver %p name %s", driver, driver->name); - if (g_dbus_register_interface(connection, element->path, - CONNMAN_NETWORK_INTERFACE, - network_methods, network_signals, - NULL, network, NULL) == FALSE) { - connman_error("Failed to register %s network", element->path); - return -EIO; - } + for (list = network_list; list != NULL; list = list->next) { + struct connman_network *network = list->data; - network->registered = TRUE; + if (network->driver != NULL) + continue; - emit_networks_signal(network->device); + if (driver->type != network->type) + continue; - return 0; + if (driver->probe(network) < 0) + continue; + + network->driver = driver; + } } -static void unregister_interface(struct connman_element *element) +static void remove_driver(struct connman_network_driver *driver) { - struct connman_network * network = element->network; - - DBG("element %p name %s", element, element->name); - - network->registered = FALSE; - - emit_networks_signal(network->device); + GSList *list; - g_dbus_unregister_interface(connection, element->path, - CONNMAN_NETWORK_INTERFACE); -} + DBG("driver %p name %s", driver, driver->name); -connman_bool_t __connman_network_has_driver(struct connman_network *network) -{ - if (network == NULL || network->driver == NULL) - return FALSE; + for (list = network_list; list != NULL; list = list->next) { + struct connman_network *network = list->data; - return network->registered; + if (network->driver == driver) + network_remove(network); + } } -static GSList *driver_list = NULL; - static gint compare_priority(gconstpointer a, gconstpointer b) { const struct connman_network_driver *driver1 = a; @@ -281,11 +283,23 @@ static gint compare_priority(gconstpointer a, gconstpointer b) */ int connman_network_driver_register(struct connman_network_driver *driver) { + GSList *list; + DBG("driver %p name %s", driver, driver->name); + for (list = driver_list; list; list = list->next) { + struct connman_network_driver *tmp = list->data; + + if (tmp->type == driver->type) + return -EALREADY; + + } + driver_list = g_slist_insert_sorted(driver_list, driver, compare_priority); + probe_driver(driver); + return 0; } @@ -300,29 +314,38 @@ void connman_network_driver_unregister(struct connman_network_driver *driver) DBG("driver %p name %s", driver, driver->name); driver_list = g_slist_remove(driver_list, driver); + + remove_driver(driver); } -static void network_destruct(struct connman_element *element) +static void network_destruct(struct connman_network *network) { - struct connman_network *network = element->network; - - DBG("element %p name %s", element, element->name); + DBG("network %p name %s", network, network->name); g_free(network->wifi.ssid); g_free(network->wifi.mode); g_free(network->wifi.security); g_free(network->wifi.passphrase); - + g_free(network->wifi.agent_passphrase); + g_free(network->wifi.eap); + g_free(network->wifi.identity); + g_free(network->wifi.agent_identity); + g_free(network->wifi.ca_cert_path); + g_free(network->wifi.client_cert_path); + g_free(network->wifi.private_key_path); + g_free(network->wifi.private_key_passphrase); + g_free(network->wifi.phase2_auth); + g_free(network->wifi.pin_wps); + + g_free(network->path); g_free(network->group); g_free(network->node); g_free(network->name); - g_free(network->address); g_free(network->identifier); - if (network->ipconfig) { - connman_ipconfig_unref(network->ipconfig); - network->ipconfig = NULL; - } + network->device = NULL; + + g_free(network); } /** @@ -337,9 +360,7 @@ struct connman_network *connman_network_create(const char *identifier, enum connman_network_type type) { struct connman_network *network; - connman_uint8_t strength = 0; - const char *str; - char *temp; + char *ident; DBG("identifier %s type %d", identifier, type); @@ -349,34 +370,19 @@ struct connman_network *connman_network_create(const char *identifier, DBG("network %p", network); - __connman_element_initialize(&network->element); + network->refcount = 1; - //temp = connman_dbus_encode_string(identifier); - if (identifier == NULL) { - temp = g_strdup_printf("hidden_%d", hidden_counter++); - network->hidden = TRUE; - } else - temp = g_strdup(identifier); + ident = g_strdup(identifier); - if (temp == NULL) { + if (ident == NULL) { g_free(network); return NULL; } - network->element.name = temp; - network->element.type = CONNMAN_ELEMENT_TYPE_NETWORK; - - network->element.network = network; - network->element.destruct = network_destruct; - - str = type2string(type); - if (str != NULL) - connman_element_set_string(&network->element, "Type", str); - - connman_element_set_uint8(&network->element, "Strength", strength); - network->type = type; - network->identifier = g_strdup(temp); + network->identifier = ident; + + network_list = g_slist_append(network_list, network); return network; } @@ -387,10 +393,14 @@ struct connman_network *connman_network_create(const char *identifier, * * Increase reference counter of network */ -struct connman_network *connman_network_ref(struct connman_network *network) +struct connman_network * +connman_network_ref_debug(struct connman_network *network, + const char *file, int line, const char *caller) { - if (connman_element_ref(&network->element) == NULL) - return NULL; + DBG("%p name %s ref %d by %s:%d:%s()", network, network->name, + network->refcount + 1, file, line, caller); + + __sync_fetch_and_add(&network->refcount, 1); return network; } @@ -401,9 +411,18 @@ struct connman_network *connman_network_ref(struct connman_network *network) * * Decrease reference counter of network */ -void connman_network_unref(struct connman_network *network) +void connman_network_unref_debug(struct connman_network *network, + const char *file, int line, const char *caller) { - connman_element_unref(&network->element); + DBG("%p name %s ref %d by %s:%d:%s()", network, network->name, + network->refcount - 1, file, line, caller); + + if (__sync_fetch_and_sub(&network->refcount, 1) != 1) + return; + + network_list = g_slist_remove(network_list, network); + + network_destruct(network); } const char *__connman_network_get_type(struct connman_network *network) @@ -434,17 +453,6 @@ const char *connman_network_get_identifier(struct connman_network *network) } /** - * connman_network_get_path: - * @network: network structure - * - * Get path name of network - */ -const char *connman_network_get_path(struct connman_network *network) -{ - return network->element.path; -} - -/** * connman_network_set_index: * @network: network structure * @index: index number @@ -453,7 +461,41 @@ const char *connman_network_get_path(struct connman_network *network) */ void connman_network_set_index(struct connman_network *network, int index) { - network->element.index = index; + struct connman_service *service; + struct connman_ipconfig *ipconfig; + + service = __connman_service_lookup_from_network(network); + if (service == NULL) + goto done; + + ipconfig = __connman_service_get_ip4config(service); + + DBG("index %d service %p ip4config %p", network->index, + service, ipconfig); + + if (network->index < 0 && ipconfig == NULL) { + + ipconfig = __connman_service_get_ip4config(service); + if (ipconfig == NULL) + /* + * 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_ip4config(service, index); + else + __connman_ipconfig_set_index(ipconfig, index); + + } else { + /* If index changed, the index of ipconfig must be reset. */ + if (ipconfig == NULL) + goto done; + + __connman_ipconfig_set_index(ipconfig, index); + } + +done: + network->index = index; } /** @@ -464,32 +506,7 @@ void connman_network_set_index(struct connman_network *network, int index) */ int connman_network_get_index(struct connman_network *network) { - return network->element.index; -} - -/** - * connman_network_get_element: - * @network: network structure - * - * Get connman_element of network - */ -struct connman_element *connman_network_get_element( - struct connman_network *network) -{ - return &network->element; -} - -/** - * connman_network_set_protocol: - * @network: network structure - * @protocol: network protocol - * - * Change protocol of network - */ -void connman_network_set_protocol(struct connman_network *network, - enum connman_network_protocol protocol) -{ - network->protocol = protocol; + return network->index; } /** @@ -510,8 +527,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; @@ -519,12 +534,12 @@ void connman_network_set_group(struct connman_network *network, if (g_strcmp0(network->group, group) == 0) { if (group != NULL) - __connman_profile_update_network(network); + __connman_service_update_from_network(network); return; } if (network->group != NULL) { - __connman_profile_remove_network(network); + __connman_service_remove_from_network(network); g_free(network->group); } @@ -532,7 +547,7 @@ void connman_network_set_group(struct connman_network *network, network->group = g_strdup(group); if (network->group != NULL) - __connman_profile_add_network(network); + network_probe(network); } /** @@ -551,7 +566,7 @@ const char *__connman_network_get_ident(struct connman_network *network) if (network->device == NULL) return NULL; - return __connman_device_get_ident(network->device); + return connman_device_get_ident(network->device); } connman_bool_t __connman_network_get_weakness(struct connman_network *network) @@ -563,11 +578,11 @@ 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: + if (g_strcmp0(network->wifi.mode, "adhoc") == 0) + return TRUE; if (network->strength > 0 && network->strength < 20) return TRUE; break; @@ -576,7 +591,7 @@ connman_bool_t __connman_network_get_weakness(struct connman_network *network) return FALSE; } -connman_bool_t __connman_network_get_connecting(struct connman_network *network) +connman_bool_t connman_network_get_connecting(struct connman_network *network) { return network->connecting; } @@ -609,9 +624,6 @@ int connman_network_set_available(struct connman_network *network, */ connman_bool_t connman_network_get_available(struct connman_network *network) { - if (network->hidden == TRUE) - return TRUE; - return network->available; } @@ -636,8 +648,12 @@ int connman_network_set_associating(struct connman_network *network, struct connman_service *service; service = __connman_service_lookup_from_network(network); - __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_ASSOCIATION); + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_ASSOCIATION, + CONNMAN_IPCONFIG_TYPE_IPV4); + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_ASSOCIATION, + CONNMAN_IPCONFIG_TYPE_IPV6); } return 0; @@ -647,15 +663,74 @@ static void set_associate_error(struct connman_network *network) { struct connman_service *service; - if (network->associating == FALSE) - return ; + service = __connman_service_lookup_from_network(network); + + __connman_service_indicate_error(service, + CONNMAN_SERVICE_ERROR_CONNECT_FAILED); +} - network->associating = FALSE; +static void set_configure_error(struct connman_network *network) +{ + struct connman_service *service; + + service = __connman_service_lookup_from_network(network); + + __connman_service_indicate_error(service, + CONNMAN_SERVICE_ERROR_CONNECT_FAILED); +} + +static void set_invalid_key_error(struct connman_network *network) +{ + struct connman_service *service; + + service = __connman_service_lookup_from_network(network); + + __connman_service_indicate_error(service, + CONNMAN_SERVICE_ERROR_INVALID_KEY); +} + +static void set_connect_error(struct connman_network *network) +{ + struct connman_service *service; + + service = __connman_service_lookup_from_network(network); + + __connman_service_indicate_error(service, + CONNMAN_SERVICE_ERROR_CONNECT_FAILED); +} + +void connman_network_set_ipv4_method(struct connman_network *network, + enum connman_ipconfig_method method) +{ + struct connman_service *service; + struct connman_ipconfig *ipconfig; + + service = __connman_service_lookup_from_network(network); + if (service == NULL) + return; + + ipconfig = __connman_service_get_ip4config(service); + if (ipconfig == NULL) + return; + + __connman_ipconfig_set_method(ipconfig, method); +} + +void connman_network_set_ipv6_method(struct connman_network *network, + enum connman_ipconfig_method method) +{ + struct connman_service *service; + struct connman_ipconfig *ipconfig; service = __connman_service_lookup_from_network(network); + if (service == NULL) + return; + + ipconfig = __connman_service_get_ip6config(service); + if (ipconfig == NULL) + return; - __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_FAILURE); + __connman_ipconfig_set_method(ipconfig, method); } void connman_network_set_error(struct connman_network *network, @@ -672,122 +747,688 @@ 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; + case CONNMAN_NETWORK_ERROR_INVALID_KEY: + set_invalid_key_error(network); + break; + case CONNMAN_NETWORK_ERROR_CONNECT_FAIL: + set_connect_error(network); + break; } + + network_change(network); } -static gboolean set_connected(gpointer user_data) +void connman_network_clear_error(struct connman_network *network) { - struct connman_network *network = user_data; struct connman_service *service; + DBG("network %p", network); + + if (network == NULL) + return; + + if (network->connecting == TRUE || network->associating == TRUE) + return; + service = __connman_service_lookup_from_network(network); + __connman_service_clear_error(service); +} - if (network->connected == TRUE) { - struct connman_element *element; - enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN; +static void set_configuration(struct connman_network *network, + enum connman_ipconfig_type type) +{ + struct connman_service *service; - switch (network->protocol) { - case CONNMAN_NETWORK_PROTOCOL_UNKNOWN: - return 0; - case CONNMAN_NETWORK_PROTOCOL_IP: - type = CONNMAN_ELEMENT_TYPE_DHCP; - break; - } + DBG("network %p", network); - __connman_device_increase_connections(network->device); + if (network->device == NULL) + return; - __connman_device_set_network(network->device, network); + __connman_device_set_network(network->device, network); - connman_device_set_disconnected(network->device, FALSE); + connman_device_set_disconnected(network->device, FALSE); - if (network->element.ipv4.method == - CONNMAN_IPCONFIG_METHOD_STATIC) { + service = __connman_service_lookup_from_network(network); + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_CONFIGURATION, + type); +} - network->connecting = FALSE; +static void dhcp_success(struct connman_network *network) +{ + struct connman_service *service; + struct connman_ipconfig *ipconfig_ipv4; + int err; - connman_network_set_associating(network, FALSE); + service = __connman_service_lookup_from_network(network); + if (service == NULL) + goto err; - __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_READY); + connman_network_set_associating(network, FALSE); - return TRUE; - } + network->connecting = FALSE; - element = connman_element_create(NULL); - if (element != NULL) { - element->type = type; - element->index = network->element.index; + ipconfig_ipv4 = __connman_service_get_ip4config(service); + err = __connman_ipconfig_address_add(ipconfig_ipv4); + if (err < 0) + goto err; - if (connman_element_register(element, - &network->element) < 0) - connman_element_unref(element); + err = __connman_ipconfig_gateway_add(ipconfig_ipv4); + if (err < 0) + goto err; - __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_CONFIGURATION); - } - } else { - connman_element_unregister_children(&network->element); + return; - __connman_device_set_network(network->device, NULL); - network->hidden = FALSE; +err: + connman_network_set_error(network, + CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL); +} - __connman_device_decrease_connections(network->device); +static void dhcp_failure(struct connman_network *network) +{ + struct connman_service *service; - __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_IDLE); - } + service = __connman_service_lookup_from_network(network); + if (service == NULL) + return; - network->connecting = FALSE; + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV4); +} - connman_network_set_associating(network, FALSE); +static void dhcp_callback(struct connman_network *network, + connman_bool_t success) +{ + DBG("success %d", success); - return FALSE; + if (success == TRUE) + dhcp_success(network); + else + dhcp_failure(network); } -/** - * connman_network_set_connected: - * @network: network structure - * @connected: connected state - * - * Change connected state of network +static int set_connected_fixed(struct connman_network *network) +{ + struct connman_service *service; + struct connman_ipconfig *ipconfig_ipv4; + int err; + + DBG(""); + + service = __connman_service_lookup_from_network(network); + + ipconfig_ipv4 = __connman_service_get_ip4config(service); + + set_configuration(network, CONNMAN_IPCONFIG_TYPE_IPV4); + + network->connecting = FALSE; + + connman_network_set_associating(network, FALSE); + + err = __connman_ipconfig_address_add(ipconfig_ipv4); + if (err < 0) + goto err; + + err = __connman_ipconfig_gateway_add(ipconfig_ipv4); + if (err < 0) + goto err; + + return 0; + +err: + connman_network_set_error(network, + CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL); + + return err; +} + +static void set_connected_manual(struct connman_network *network) +{ + struct connman_service *service; + struct connman_ipconfig *ipconfig; + int err; + + DBG("network %p", network); + + service = __connman_service_lookup_from_network(network); + + ipconfig = __connman_service_get_ip4config(service); + + if (__connman_ipconfig_get_local(ipconfig) == NULL) + __connman_service_read_ip4config(service); + + set_configuration(network, CONNMAN_IPCONFIG_TYPE_IPV4); + + err = __connman_ipconfig_address_add(ipconfig); + if (err < 0) + goto err; + + err = __connman_ipconfig_gateway_add(ipconfig); + if (err < 0) + goto err; + + network->connecting = FALSE; + + connman_network_set_associating(network, FALSE); + + return; + +err: + connman_network_set_error(network, + CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL); + return; +} + +static int set_connected_dhcp(struct connman_network *network) +{ + int err; + + DBG("network %p", network); + + set_configuration(network, CONNMAN_IPCONFIG_TYPE_IPV4); + + err = __connman_dhcp_start(network, dhcp_callback); + if (err < 0) { + connman_error("Can not request DHCP lease"); + return err; + } + + return 0; +} + +static int manual_ipv6_set(struct connman_network *network, + struct connman_ipconfig *ipconfig_ipv6) +{ + struct connman_service *service; + int err; + + DBG("network %p ipv6 %p", network, ipconfig_ipv6); + + service = __connman_service_lookup_from_network(network); + if (service == NULL) + return -EINVAL; + + if (__connman_ipconfig_get_local(ipconfig_ipv6) == NULL) + __connman_service_read_ip6config(service); + + err = __connman_ipconfig_address_add(ipconfig_ipv6); + if (err < 0) { + connman_network_set_error(network, + CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL); + return err; + } + + err = __connman_ipconfig_gateway_add(ipconfig_ipv6); + if (err < 0) + return err; + + __connman_connection_gateway_activate(service, + CONNMAN_IPCONFIG_TYPE_IPV6); + + __connman_device_set_network(network->device, network); + + connman_device_set_disconnected(network->device, FALSE); + + network->connecting = FALSE; + + return 0; +} + +static void stop_dhcpv6(struct connman_network *network) +{ + __connman_dhcpv6_stop(network); +} + +static void dhcpv6_release_callback(struct connman_network *network, + connman_bool_t success) +{ + DBG("success %d", success); + + stop_dhcpv6(network); +} + +static void release_dhcpv6(struct connman_network *network) +{ + __connman_dhcpv6_start_release(network, dhcpv6_release_callback); + stop_dhcpv6(network); +} + +static void dhcpv6_info_callback(struct connman_network *network, + connman_bool_t success) +{ + DBG("success %d", success); + + stop_dhcpv6(network); +} + +static gboolean dhcpv6_set_addresses(struct connman_network *network) +{ + struct connman_service *service; + struct connman_ipconfig *ipconfig_ipv6; + int err = -EINVAL; + + service = __connman_service_lookup_from_network(network); + if (service == NULL) + goto err; + + connman_network_set_associating(network, FALSE); + + network->connecting = FALSE; + + ipconfig_ipv6 = __connman_service_get_ip6config(service); + err = __connman_ipconfig_address_add(ipconfig_ipv6); + if (err < 0) + goto err; + + err = __connman_ipconfig_gateway_add(ipconfig_ipv6); + if (err < 0) + goto err; + + return 0; + +err: + connman_network_set_error(network, + CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL); + return err; +} + +static void autoconf_ipv6_set(struct connman_network *network); +static void dhcpv6_callback(struct connman_network *network, + connman_bool_t success); + +/* + * Have a separate callback for renew so that we do not do autoconf + * in wrong phase as the dhcpv6_callback() is also called when doing + * DHCPv6 solicitation. */ -int connman_network_set_connected(struct connman_network *network, - connman_bool_t connected) +static void dhcpv6_renew_callback(struct connman_network *network, + connman_bool_t success) { - DBusMessage *signal; - DBusMessageIter iter; + if (success == TRUE) + dhcpv6_callback(network, success); + else { + stop_dhcpv6(network); - DBG("network %p connected %d", network, connected); + /* restart and do solicit again. */ + autoconf_ipv6_set(network); + } +} - if ((network->connecting == TRUE || network->associating == TRUE) && - connected == FALSE) { - connman_element_set_error(&network->element, - CONNMAN_ELEMENT_ERROR_CONNECT_FAILED); - __connman_network_disconnect(network); +static void dhcpv6_callback(struct connman_network *network, + connman_bool_t success) +{ + DBG("success %d", success); + + /* Start the renew process if necessary */ + if (success == TRUE) { + + if (dhcpv6_set_addresses(network) < 0) { + stop_dhcpv6(network); + return; + } + + if (__connman_dhcpv6_start_renew(network, + dhcpv6_renew_callback) == -ETIMEDOUT) + dhcpv6_renew_callback(network, FALSE); + } else + stop_dhcpv6(network); +} + +static void check_dhcpv6(struct nd_router_advert *reply, + unsigned int length, void *user_data) +{ + struct connman_network *network = user_data; + GSList *prefixes; + + DBG("reply %p", reply); + + if (reply == NULL) { + /* + * Router solicitation message seem to get lost easily so + * try to send it again. + */ + if (network->router_solicit_count > 0) { + DBG("re-send router solicitation %d", + network->router_solicit_count); + network->router_solicit_count--; + __connman_inet_ipv6_send_rs(network->index, 1, + check_dhcpv6, network); + return; + } + connman_network_unref(network); + return; } - if (network->connected == connected) - return -EALREADY; + network->router_solicit_count = 0; - network->connected = connected; + /* + * If we were disconnected while waiting router advertisement, + * we just quit and do not start DHCPv6 + */ + if (network->connected == FALSE) { + connman_network_unref(network); + return; + } - if (network->registered == FALSE) { - g_idle_add(set_connected, network); - return 0; + prefixes = __connman_inet_ipv6_get_prefixes(reply, length); + + /* + * We do stateful/stateless DHCPv6 if router advertisement says so. + */ + if (reply->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) + __connman_dhcpv6_start(network, prefixes, dhcpv6_callback); + else if (reply->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) + __connman_dhcpv6_start_info(network, dhcpv6_info_callback); + + connman_network_unref(network); +} + +static void receive_refresh_rs_reply(struct nd_router_advert *reply, + unsigned int length, void *user_data) +{ + struct connman_network *network = user_data; + + DBG("reply %p", reply); + + if (reply == NULL) { + /* + * Router solicitation message seem to get lost easily so + * try to send it again. + */ + if (network->router_solicit_refresh_count > 1) { + network->router_solicit_refresh_count--; + DBG("re-send router solicitation %d", + network->router_solicit_refresh_count); + __connman_inet_ipv6_send_rs(network->index, + RS_REFRESH_TIMEOUT, + receive_refresh_rs_reply, + network); + return; + } } - signal = dbus_message_new_signal(network->element.path, - CONNMAN_NETWORK_INTERFACE, "PropertyChanged"); - if (signal == NULL) + /* RS refresh not in progress anymore */ + network->router_solicit_refresh_count = 0; + + connman_network_unref(network); + return; +} + +int __connman_refresh_rs_ipv6(struct connman_network *network, int index) +{ + int ret = 0; + + DBG("network %p index %d", network, index); + + /* Send only one RS for all RDNSS entries which are about to expire */ + if (network->router_solicit_refresh_count > 0) { + DBG("RS refresh already started"); return 0; + } - dbus_message_iter_init_append(signal, &iter); - connman_dbus_property_append_variant(&iter, "Connected", - DBUS_TYPE_BOOLEAN, &connected); + network->router_solicit_refresh_count = RS_REFRESH_COUNT; - g_dbus_send_message(connection, signal); + connman_network_ref(network); - set_connected(network); + ret = __connman_inet_ipv6_send_rs(index, RS_REFRESH_TIMEOUT, + receive_refresh_rs_reply, network); + return ret; +} + +static void autoconf_ipv6_set(struct connman_network *network) +{ + struct connman_service *service; + struct connman_ipconfig *ipconfig; + int index; + + DBG("network %p", network); + + if (network->router_solicit_count > 0) { + /* + * The autoconfiguration is already pending and we have sent + * router solicitation messages and are now waiting answers. + * There is no need to continue any further. + */ + DBG("autoconfiguration already started"); + return; + } + + __connman_device_set_network(network->device, network); + + connman_device_set_disconnected(network->device, FALSE); + + network->connecting = FALSE; + + service = __connman_service_lookup_from_network(network); + if (service == NULL) + return; + + ipconfig = __connman_service_get_ip6config(service); + if (ipconfig == NULL) + return; + + index = __connman_ipconfig_get_index(ipconfig); + + connman_network_ref(network); + + /* Try to get stateless DHCPv6 information, RFC 3736 */ + network->router_solicit_count = 3; + __connman_inet_ipv6_send_rs(index, 1, check_dhcpv6, network); +} + +static void set_connected(struct connman_network *network) +{ + struct connman_ipconfig *ipconfig_ipv4, *ipconfig_ipv6; + enum connman_ipconfig_method ipv4_method, ipv6_method; + struct connman_service *service; + int ret; + + if (network->connected == TRUE) + return; + + network->connected = TRUE; + + service = __connman_service_lookup_from_network(network); + + ipconfig_ipv4 = __connman_service_get_ip4config(service); + ipconfig_ipv6 = __connman_service_get_ip6config(service); + + DBG("service %p ipv4 %p ipv6 %p", service, ipconfig_ipv4, + ipconfig_ipv6); + + ipv4_method = __connman_ipconfig_get_method(ipconfig_ipv4); + ipv6_method = __connman_ipconfig_get_method(ipconfig_ipv6); + + DBG("method ipv4 %d ipv6 %d", ipv4_method, ipv6_method); + + switch (ipv6_method) { + case CONNMAN_IPCONFIG_METHOD_UNKNOWN: + case CONNMAN_IPCONFIG_METHOD_OFF: + break; + case CONNMAN_IPCONFIG_METHOD_DHCP: + case CONNMAN_IPCONFIG_METHOD_AUTO: + autoconf_ipv6_set(network); + break; + case CONNMAN_IPCONFIG_METHOD_FIXED: + case CONNMAN_IPCONFIG_METHOD_MANUAL: + ret = manual_ipv6_set(network, ipconfig_ipv6); + if (ret != 0) { + connman_network_set_error(network, + CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); + return; + } + break; + } + + switch (ipv4_method) { + case CONNMAN_IPCONFIG_METHOD_UNKNOWN: + case CONNMAN_IPCONFIG_METHOD_OFF: + case CONNMAN_IPCONFIG_METHOD_AUTO: + return; + case CONNMAN_IPCONFIG_METHOD_FIXED: + if (set_connected_fixed(network) < 0) { + connman_network_set_error(network, + CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); + return; + } + return; + case CONNMAN_IPCONFIG_METHOD_MANUAL: + set_connected_manual(network); + return; + case CONNMAN_IPCONFIG_METHOD_DHCP: + if (set_connected_dhcp(network) < 0) { + connman_network_set_error(network, + CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); + return; + } + } + + network->connecting = FALSE; + + connman_network_set_associating(network, FALSE); +} + +static void set_disconnected(struct connman_network *network) +{ + struct connman_ipconfig *ipconfig_ipv4, *ipconfig_ipv6; + enum connman_ipconfig_method ipv4_method, ipv6_method; + enum connman_service_state state; + struct connman_service *service; + + if (network->connected == FALSE) + return; + + network->connected = FALSE; + + service = __connman_service_lookup_from_network(network); + + ipconfig_ipv4 = __connman_service_get_ip4config(service); + ipconfig_ipv6 = __connman_service_get_ip6config(service); + + DBG("service %p ipv4 %p ipv6 %p", service, ipconfig_ipv4, + ipconfig_ipv6); + + ipv4_method = __connman_ipconfig_get_method(ipconfig_ipv4); + ipv6_method = __connman_ipconfig_get_method(ipconfig_ipv6); + + DBG("method ipv4 %d ipv6 %d", ipv4_method, ipv6_method); + + /* + * Resetting solicit count here will prevent the RS resend loop + * from sending packets in check_dhcpv6() + */ + network->router_solicit_count = 0; + + __connman_device_set_network(network->device, NULL); + + switch (ipv6_method) { + case CONNMAN_IPCONFIG_METHOD_UNKNOWN: + case CONNMAN_IPCONFIG_METHOD_OFF: + case CONNMAN_IPCONFIG_METHOD_FIXED: + case CONNMAN_IPCONFIG_METHOD_MANUAL: + break; + case CONNMAN_IPCONFIG_METHOD_DHCP: + case CONNMAN_IPCONFIG_METHOD_AUTO: + release_dhcpv6(network); + break; + } + + switch (ipv4_method) { + case CONNMAN_IPCONFIG_METHOD_UNKNOWN: + case CONNMAN_IPCONFIG_METHOD_OFF: + case CONNMAN_IPCONFIG_METHOD_AUTO: + case CONNMAN_IPCONFIG_METHOD_FIXED: + case CONNMAN_IPCONFIG_METHOD_MANUAL: + break; + case CONNMAN_IPCONFIG_METHOD_DHCP: + __connman_dhcp_stop(network); + break; + } + + /* + * We only set the disconnect state if we were not in idle + * or in failure. It does not make sense to go to disconnect + * state if we were not connected. + */ + state = __connman_service_ipconfig_get_state(service, + CONNMAN_IPCONFIG_TYPE_IPV4); + if (state != CONNMAN_SERVICE_STATE_IDLE && + state != CONNMAN_SERVICE_STATE_FAILURE) + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_DISCONNECT, + CONNMAN_IPCONFIG_TYPE_IPV4); + + state = __connman_service_ipconfig_get_state(service, + CONNMAN_IPCONFIG_TYPE_IPV6); + if (state != CONNMAN_SERVICE_STATE_IDLE && + state != CONNMAN_SERVICE_STATE_FAILURE) + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_DISCONNECT, + CONNMAN_IPCONFIG_TYPE_IPV6); + + __connman_connection_gateway_remove(service, + CONNMAN_IPCONFIG_TYPE_ALL); + + __connman_ipconfig_address_unset(ipconfig_ipv4); + __connman_ipconfig_address_unset(ipconfig_ipv6); + + /* + * Special handling for IPv6 autoconfigured address. + * The simplest way to remove autoconfigured routes is to + * disable IPv6 temporarily so that kernel will do the cleanup + * automagically. + */ + if (ipv6_method == CONNMAN_IPCONFIG_METHOD_AUTO) { + __connman_ipconfig_disable_ipv6(ipconfig_ipv6); + __connman_ipconfig_enable_ipv6(ipconfig_ipv6); + } + + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV4); + + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV6); + + network->connecting = FALSE; + + connman_network_set_associating(network, FALSE); +} + +/** + * connman_network_set_connected: + * @network: network structure + * @connected: connected state + * + * Change connected state of network + */ +int connman_network_set_connected(struct connman_network *network, + connman_bool_t connected) +{ + DBG("network %p connected %d/%d connecting %d associating %d", + network, network->connected, connected, network->connecting, + network->associating); + + if ((network->connecting == TRUE || network->associating == TRUE) && + connected == FALSE) { + connman_network_set_error(network, + CONNMAN_NETWORK_ERROR_CONNECT_FAIL); + if (__connman_network_disconnect(network) == 0) + return 0; + } + + if (network->connected == connected) + return -EALREADY; + + if (connected == FALSE) + set_disconnected(network); + else + set_connected(network); return 0; } @@ -814,6 +1455,35 @@ connman_bool_t connman_network_get_associating(struct connman_network *network) return network->associating; } +int connman_network_connect_hidden(struct connman_network *network, + char *identity, char* passphrase) +{ + int err = 0; + struct connman_service *service; + + DBG(""); + + service = __connman_service_lookup_from_network(network); + if (service == NULL) + return -EINVAL; + + if (identity != NULL) + __connman_service_set_agent_identity(service, identity); + + if (passphrase != NULL) + err = __connman_service_add_passphrase(service, passphrase); + + if (err == -ENOKEY) { + __connman_service_indicate_error(service, + CONNMAN_SERVICE_ERROR_INVALID_KEY); + return err; + } else { + __connman_service_set_hidden(service); + __connman_service_set_userconnect(service, TRUE); + return __connman_service_connect(service); + } +} + /** * __connman_network_connect: * @network: network structure @@ -824,103 +1494,258 @@ int __connman_network_connect(struct connman_network *network) { int err; - DBG("network %p", network); + DBG("network %p", network); + + if (network->connected == TRUE) + return -EISCONN; + + if (network->connecting == TRUE || network->associating == TRUE) + return -EALREADY; + + if (network->driver == NULL) + return -EUNATCH; + + if (network->driver->connect == NULL) + return -ENOSYS; + + if (network->device == NULL) + return -ENODEV; + + network->connecting = TRUE; + + __connman_device_disconnect(network->device); + + err = network->driver->connect(network); + if (err < 0) { + if (err == -EINPROGRESS) + connman_network_set_associating(network, TRUE); + else { + network->connecting = FALSE; + } + + return err; + } + + set_connected(network); + + return err; +} + +/** + * __connman_network_disconnect: + * @network: network structure + * + * Disconnect network + */ +int __connman_network_disconnect(struct connman_network *network) +{ + int err; + + DBG("network %p", network); + + if (network->connected == FALSE && network->connecting == FALSE && + network->associating == FALSE) + return -ENOTCONN; + + if (network->driver == NULL) + return -EUNATCH; + + if (network->driver->disconnect == NULL) + return -ENOSYS; + + network->connecting = FALSE; + + err = network->driver->disconnect(network); + if (err == 0) + set_disconnected(network); + + return err; +} + +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_address_add(ipconfig); + if (err < 0) { + connman_network_set_error(network, + CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL); + return err; + } + + return __connman_ipconfig_gateway_add(ipconfig); +} + +int __connman_network_clear_ipconfig(struct connman_network *network, + struct connman_ipconfig *ipconfig) +{ + struct connman_service *service; + enum connman_ipconfig_method method; + enum connman_ipconfig_type type; + + service = __connman_service_lookup_from_network(network); + if (service == NULL) + return -EINVAL; + + method = __connman_ipconfig_get_method(ipconfig); + type = __connman_ipconfig_get_config_type(ipconfig); + + switch (method) { + case CONNMAN_IPCONFIG_METHOD_UNKNOWN: + case CONNMAN_IPCONFIG_METHOD_OFF: + case CONNMAN_IPCONFIG_METHOD_FIXED: + return -EINVAL; + case CONNMAN_IPCONFIG_METHOD_AUTO: + release_dhcpv6(network); + break; + case CONNMAN_IPCONFIG_METHOD_MANUAL: + __connman_ipconfig_address_remove(ipconfig); + break; + case CONNMAN_IPCONFIG_METHOD_DHCP: + __connman_dhcp_stop(network); + break; + } + + if (type == CONNMAN_IPCONFIG_TYPE_IPV6) + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_CONFIGURATION, + CONNMAN_IPCONFIG_TYPE_IPV6); + else if (type == CONNMAN_IPCONFIG_TYPE_IPV4) + __connman_service_ipconfig_indicate_state(service, + CONNMAN_SERVICE_STATE_CONFIGURATION, + CONNMAN_IPCONFIG_TYPE_IPV4); + + return 0; +} + +int __connman_network_set_ipconfig(struct connman_network *network, + struct connman_ipconfig *ipconfig_ipv4, + struct connman_ipconfig *ipconfig_ipv6) +{ + enum connman_ipconfig_method method; + int ret; + + if (network == NULL) + return -EINVAL; - if (network->connected == TRUE) - return -EISCONN; + if (ipconfig_ipv6) { + method = __connman_ipconfig_get_method(ipconfig_ipv6); - if (network->connecting == TRUE || network->associating == TRUE) - return -EALREADY; + switch (method) { + case CONNMAN_IPCONFIG_METHOD_UNKNOWN: + case CONNMAN_IPCONFIG_METHOD_OFF: + break; + case CONNMAN_IPCONFIG_METHOD_AUTO: + autoconf_ipv6_set(network); + break; + case CONNMAN_IPCONFIG_METHOD_FIXED: + case CONNMAN_IPCONFIG_METHOD_MANUAL: + ret = manual_ipv6_set(network, ipconfig_ipv6); + if (ret != 0) { + connman_network_set_error(network, + CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL); + return ret; + } + break; + case CONNMAN_IPCONFIG_METHOD_DHCP: + break; + } + } - if (network->driver == NULL) - return -EUNATCH; + if (ipconfig_ipv4) { + method = __connman_ipconfig_get_method(ipconfig_ipv4); + + switch (method) { + case CONNMAN_IPCONFIG_METHOD_UNKNOWN: + case CONNMAN_IPCONFIG_METHOD_OFF: + case CONNMAN_IPCONFIG_METHOD_FIXED: + case CONNMAN_IPCONFIG_METHOD_AUTO: + return -EINVAL; + case CONNMAN_IPCONFIG_METHOD_MANUAL: + return manual_ipv4_set(network, ipconfig_ipv4); + case CONNMAN_IPCONFIG_METHOD_DHCP: + return __connman_dhcp_start(network, dhcp_callback); + } + } - if (network->driver->connect == NULL) - return -ENOSYS; + return 0; +} - __connman_device_disconnect(network->device); +int connman_network_set_ipaddress(struct connman_network *network, + struct connman_ipaddress *ipaddress) +{ + struct connman_service *service; + struct connman_ipconfig *ipconfig = NULL; - network->connecting = TRUE; + DBG("network %p", network); - err = network->driver->connect(network); - if (err < 0) { - if (err == -EINPROGRESS) - connman_network_set_associating(network, TRUE); - else - network->hidden = FALSE; + service = __connman_service_lookup_from_network(network); + if (service == NULL) + return -EINVAL; - return err; - } + ipconfig = __connman_service_get_ipconfig(service, ipaddress->family); + if (ipconfig == NULL) + return -EINVAL; - network->connected = TRUE; - set_connected(network); + __connman_ipconfig_set_local(ipconfig, ipaddress->local); + __connman_ipconfig_set_peer(ipconfig, ipaddress->peer); + __connman_ipconfig_set_broadcast(ipconfig, ipaddress->broadcast); + __connman_ipconfig_set_prefixlen(ipconfig, ipaddress->prefixlen); + __connman_ipconfig_set_gateway(ipconfig, ipaddress->gateway); - return err; + return 0; } -/** - * __connman_network_disconnect: - * @network: network structure - * - * Disconnect network - */ -int __connman_network_disconnect(struct connman_network *network) +int connman_network_set_nameservers(struct connman_network *network, + const char *nameservers) { - int err; + struct connman_service *service; + char **nameservers_array; + int i; - DBG("network %p", network); + DBG("network %p nameservers %s", network, nameservers); - if (network->connected == FALSE && network->connecting == FALSE && - network->associating == FALSE) - return -ENOTCONN; + service = __connman_service_lookup_from_network(network); + if (service == NULL) + return -EINVAL; - if (network->driver == NULL) - return -EUNATCH; + __connman_service_nameserver_clear(service); - if (network->driver->disconnect == NULL) - return -ENOSYS; + if (nameservers == NULL) + return 0; - network->connecting = FALSE; + nameservers_array = g_strsplit(nameservers, " ", 0); - err = network->driver->disconnect(network); - if (err == 0) { - network->connected = FALSE; - set_connected(network); + for (i = 0; nameservers_array[i] != NULL; i++) { + __connman_service_nameserver_append(service, + nameservers_array[i], FALSE); } - return err; + g_strfreev(nameservers_array); + + return 0; } -/** - * connman_network_set_address: - * @network: network structure - * @address: binary address value - * @size: binary address length - * - * Set unique address value for network - */ -int connman_network_set_address(struct connman_network *network, - const void *address, unsigned int size) +int connman_network_set_domain(struct connman_network *network, + const char *domain) { - const unsigned char *addr_octet = address; - char *str; + struct connman_service *service; - DBG("network %p size %d", network, size); + DBG("network %p domain %s", network, domain); - if (size != 6) + service = __connman_service_lookup_from_network(network); + if (service == NULL) return -EINVAL; - str = g_strdup_printf("%02X:%02X:%02X:%02X:%02X:%02X", - addr_octet[0], addr_octet[1], addr_octet[2], - addr_octet[3], addr_octet[4], addr_octet[5]); - if (str == NULL) - return -ENOMEM; + __connman_service_set_domainname(service, domain); - g_free(network->address); - network->address = str; - - return connman_element_set_string(&network->element, - "Address", network->address); + return 0; } /** @@ -938,7 +1763,7 @@ int connman_network_set_name(struct connman_network *network, g_free(network->name); network->name = g_strdup(name); - return connman_element_set_string(&network->element, "Name", name); + return 0; } /** @@ -948,6 +1773,7 @@ int connman_network_set_name(struct connman_network *network, * * Set signal strength value for network */ + int connman_network_set_strength(struct connman_network *network, connman_uint8_t strength) { @@ -955,26 +1781,42 @@ int connman_network_set_strength(struct connman_network *network, network->strength = strength; - return connman_element_set_uint8(&network->element, - "Strength", strength); + return 0; } -/** - * connman_network_set_roaming: - * @network: network structure - * @roaming: roaming state - * - * Set roaming state for network - */ -int connman_network_set_roaming(struct connman_network *network, - connman_bool_t roaming) +connman_uint8_t connman_network_get_strength(struct connman_network *network) +{ + return network->strength; +} + +int connman_network_set_frequency(struct connman_network *network, + connman_uint16_t frequency) +{ + DBG("network %p frequency %d", network, frequency); + + network->frequency = frequency; + + return 0; +} + +connman_uint16_t connman_network_get_frequency(struct connman_network *network) +{ + return network->frequency; +} + +int connman_network_set_wifi_channel(struct connman_network *network, + connman_uint16_t channel) { - DBG("network %p roaming %d", network, roaming); + DBG("network %p wifi channel %d", network, channel); + + network->wifi.channel = channel; - network->roaming = roaming; + return 0; +} - return connman_element_set_bool(&network->element, - "Roaming", roaming); +connman_uint16_t connman_network_get_wifi_channel(struct connman_network *network) +{ + return network->wifi.channel; } /** @@ -993,9 +1835,9 @@ int connman_network_set_string(struct connman_network *network, if (g_strcmp0(key, "Name") == 0) return connman_network_set_name(network, value); - if (g_str_equal(key, "Address") == TRUE) { - g_free(network->address); - network->address = g_strdup(value); + if (g_str_equal(key, "Path") == TRUE) { + g_free(network->path); + network->path = g_strdup(value); } else if (g_str_equal(key, "Node") == TRUE) { g_free(network->node); network->node = g_strdup(value); @@ -1008,9 +1850,41 @@ 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.AgentPassphrase") == TRUE) { + g_free(network->wifi.agent_passphrase); + network->wifi.agent_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.AgentIdentity") == TRUE) { + g_free(network->wifi.agent_identity); + network->wifi.agent_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); + } else if (g_str_equal(key, "WiFi.PinWPS") == TRUE) { + g_free(network->wifi.pin_wps); + network->wifi.pin_wps = g_strdup(value); + } else { + return -EINVAL; } - return connman_element_set_string(&network->element, key, value); + return 0; } /** @@ -1025,8 +1899,8 @@ const char *connman_network_get_string(struct connman_network *network, { DBG("network %p key %s", network, key); - if (g_str_equal(key, "Address") == TRUE) - return network->address; + if (g_str_equal(key, "Path") == TRUE) + return network->path; else if (g_str_equal(key, "Name") == TRUE) return network->name; else if (g_str_equal(key, "Node") == TRUE) @@ -1037,8 +1911,28 @@ 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.AgentPassphrase") == TRUE) + return network->wifi.agent_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.AgentIdentity") == TRUE) + return network->wifi.agent_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; + else if (g_str_equal(key, "WiFi.PinWPS") == TRUE) + return network->wifi.pin_wps; - return connman_element_get_string(&network->element, key); + return NULL; } /** @@ -1055,9 +1949,13 @@ int connman_network_set_bool(struct connman_network *network, DBG("network %p key %s value %d", network, key, value); if (g_strcmp0(key, "Roaming") == 0) - return connman_network_set_roaming(network, value); + network->roaming = value; + else if (g_strcmp0(key, "WiFi.WPS") == 0) + network->wifi.wps = value; + else if (g_strcmp0(key, "WiFi.UseWPS") == 0) + network->wifi.use_wps = value; - return connman_element_set_bool(&network->element, key, value); + return -EINVAL; } /** @@ -1074,86 +1972,12 @@ connman_bool_t connman_network_get_bool(struct connman_network *network, if (g_str_equal(key, "Roaming") == TRUE) return network->roaming; + else if (g_str_equal(key, "WiFi.WPS") == TRUE) + return network->wifi.wps; + else if (g_str_equal(key, "WiFi.UseWPS") == TRUE) + return network->wifi.use_wps; - return connman_element_get_bool(&network->element, key); -} - -/** - * connman_network_set_uint8: - * @network: network structure - * @key: unique identifier - * @value: integer value - * - * Set integer value for specific key - */ -int connman_network_set_uint8(struct connman_network *network, - const char *key, connman_uint8_t value) -{ - DBG("network %p key %s value %d", network, key, value); - - if (g_strcmp0(key, "Strength") == 0) - return connman_network_set_strength(network, value); - - return connman_element_set_uint8(&network->element, key, value); -} - -/** - * connman_network_get_uint8: - * @network: network structure - * @key: unique identifier - * - * Get integer value for specific key - */ -connman_uint8_t connman_network_get_uint8(struct connman_network *network, - const char *key) -{ - DBG("network %p key %s", network, key); - - if (g_str_equal(key, "Strength") == TRUE) - return network->strength; - - return connman_element_get_uint8(&network->element, key); -} - -/** - * connman_network_set_uint16: - * @network: network structure - * @key: unique identifier - * @value: integer value - * - * Set integer value for specific key - */ -int connman_network_set_uint16(struct connman_network *network, - const char *key, connman_uint16_t value) -{ - DBG("network %p key %s value %d", network, key, value); - - if (g_str_equal(key, "Frequency") == TRUE) - network->frequency = value; - else if (g_str_equal(key, "WiFi.Channel") == TRUE) - network->wifi.channel = value; - - return -EINVAL; -} - -/** - * connman_network_get_uint16: - * @network: network structure - * @key: unique identifier - * - * Get integer value for specific key - */ -connman_uint16_t connman_network_get_uint16(struct connman_network *network, - const char *key) -{ - DBG("network %p key %s", network, key); - - if (g_str_equal(key, "Frequency") == TRUE) - return network->frequency; - else if (g_str_equal(key, "WiFi.Channel") == TRUE) - return network->wifi.channel; - - return 0; + return FALSE; } /** @@ -1170,9 +1994,6 @@ int connman_network_set_blob(struct connman_network *network, { DBG("network %p key %s size %d", network, key, size); - if (g_strcmp0(key, "Address") == 0) - return connman_network_set_address(network, data, size); - if (g_str_equal(key, "WiFi.SSID") == TRUE) { g_free(network->wifi.ssid); network->wifi.ssid = g_try_malloc(size); @@ -1181,9 +2002,11 @@ int connman_network_set_blob(struct connman_network *network, network->wifi.ssid_len = size; } else network->wifi.ssid_len = 0; + } else { + return -EINVAL; } - return connman_element_set_blob(&network->element, key, data, size); + return 0; } /** @@ -1205,13 +2028,22 @@ const void *connman_network_get_blob(struct connman_network *network, return network->wifi.ssid; } - return connman_element_get_blob(&network->element, key, size); + return NULL; } void __connman_network_set_device(struct connman_network *network, struct connman_device *device) { + if (network->device == device) + return; + + if (network->device != NULL) + network_remove(network); + network->device = device; + + if (network->device != NULL) + network_probe(network); } /** @@ -1248,160 +2080,33 @@ void connman_network_set_data(struct connman_network *network, void *data) network->driver_data = data; } -static gboolean match_driver(struct connman_network *network, - struct connman_network_driver *driver) -{ - if (network->type == driver->type || - driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN) - return TRUE; - - return FALSE; -} - -static int network_probe(struct connman_element *element) +void connman_network_update(struct connman_network *network) { - struct connman_network *network = element->network; - GSList *list; - int err; - - DBG("element %p name %s", element, element->name); - - if (network == NULL) - return -ENODEV; - - for (list = driver_list; list; list = list->next) { - struct connman_network_driver *driver = list->data; - - if (match_driver(network, driver) == FALSE) - continue; - - DBG("driver %p name %s", driver, driver->name); - - if (driver->probe(network) == 0) { - network->driver = driver; - break; - } - } - - if (network->driver == NULL) - return -ENODEV; - - err = register_interface(element); - if (err < 0) { - if (network->driver->remove) - network->driver->remove(network); - return err; - } - switch (network->type) { case CONNMAN_NETWORK_TYPE_UNKNOWN: case CONNMAN_NETWORK_TYPE_VENDOR: - break; - case CONNMAN_NETWORK_TYPE_ETHERNET: - 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) - __connman_profile_add_network(network); - break; - } - - return 0; -} - -static void network_remove(struct connman_element *element) -{ - struct connman_network *network = element->network; - - DBG("element %p name %s", element, element->name); - - if (network == NULL) return; - - if (network->driver == NULL) - return; - - switch (network->type) { - case CONNMAN_NETWORK_TYPE_UNKNOWN: - case CONNMAN_NETWORK_TYPE_VENDOR: - break; case CONNMAN_NETWORK_TYPE_ETHERNET: 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) { - __connman_profile_remove_network(network); - - g_free(network->group); - network->group = NULL; - } break; } - unregister_interface(element); - - if (network->driver->remove) - network->driver->remove(network); -} - -static void network_change(struct connman_element *element) -{ - struct connman_network *network = element->network; - - DBG("element %p name %s", element, element->name); - - if (element->state != CONNMAN_ELEMENT_STATE_ERROR) - return; - - if (element->error != CONNMAN_ELEMENT_ERROR_DHCP_FAILED) - return; - - if (network->connected == FALSE) - return; - - connman_element_unregister_children(element); - - connman_device_set_disconnected(network->device, TRUE); - - if (network->driver && network->driver->disconnect) { - network->driver->disconnect(network); - return; - } - - network->connected = FALSE; + if (network->group != NULL) + __connman_service_update_from_network(network); } -static struct connman_driver network_driver = { - .name = "network", - .type = CONNMAN_ELEMENT_TYPE_NETWORK, - .priority = CONNMAN_DRIVER_PRIORITY_LOW, - .probe = network_probe, - .remove = network_remove, - .change = network_change, -}; - int __connman_network_init(void) { DBG(""); - connection = connman_dbus_get_connection(); - - return connman_driver_register(&network_driver); + return 0; } void __connman_network_cleanup(void) { DBG(""); - - connman_driver_unregister(&network_driver); - - dbus_connection_unref(connection); }