X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fnetwork.c;h=bf017676498d80eadda82a75870ac14d1c7876d2;hb=c189a9ab8a085447b775c7fbeb0a8050751b7f84;hp=b58409f2e7d1f5a00cd0e3eacc401fdd6851d87e;hpb=602aec9684a3121adbf39d5b8f4c4105b7f89ec3;p=framework%2Fconnectivity%2Fconnman.git diff --git a/src/network.c b/src/network.c index b58409f..bf01767 100644 --- a/src/network.c +++ b/src/network.c @@ -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 @@ -28,11 +28,24 @@ #include "connman.h" +/* + * 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 { - gint refcount; + int refcount; enum connman_network_type type; connman_bool_t available; connman_bool_t connected; @@ -45,6 +58,8 @@ struct connman_network { char *group; char *path; int index; + int router_solicit_count; + int router_solicit_refresh_count; struct connman_network_driver *driver; void *driver_data; @@ -103,14 +118,6 @@ static const char *type2string(enum connman_network_type type) return NULL; } -connman_bool_t __connman_network_has_driver(struct connman_network *network) -{ - if (network == NULL || network->driver == NULL) - return FALSE; - - return TRUE; -} - static gboolean match_driver(struct connman_network *network, struct connman_network_driver *driver) { @@ -178,6 +185,8 @@ static void network_remove(struct connman_network *network) if (network->driver == NULL) return; + connman_network_set_connected(network, FALSE); + switch (network->type) { case CONNMAN_NETWORK_TYPE_UNKNOWN: case CONNMAN_NETWORK_TYPE_VENDOR: @@ -384,12 +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) { - DBG("network %p name %s refcount %d", network, network->name, - g_atomic_int_get(&network->refcount) + 1); + DBG("%p name %s ref %d by %s:%d:%s()", network, network->name, + network->refcount + 1, file, line, caller); - g_atomic_int_inc(&network->refcount); + __sync_fetch_and_add(&network->refcount, 1); return network; } @@ -400,12 +411,13 @@ 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) { - DBG("network %p name %s refcount %d", network, network->name, - g_atomic_int_get(&network->refcount) - 1); + DBG("%p name %s ref %d by %s:%d:%s()", network, network->name, + network->refcount - 1, file, line, caller); - if (g_atomic_int_dec_and_test(&network->refcount) == FALSE) + if (__sync_fetch_and_sub(&network->refcount, 1) != 1) return; network_list = g_slist_remove(network_list, network); @@ -651,29 +663,20 @@ static void set_associate_error(struct connman_network *network) { struct connman_service *service; - if (network->associating == FALSE) - return ; - - network->associating = FALSE; - service = __connman_service_lookup_from_network(network); - __connman_service_ipconfig_indicate_state(service, - CONNMAN_SERVICE_STATE_FAILURE, - CONNMAN_IPCONFIG_TYPE_IPV4); + __connman_service_indicate_error(service, + CONNMAN_SERVICE_ERROR_CONNECT_FAILED); } 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_ipconfig_indicate_state(service, - CONNMAN_SERVICE_STATE_FAILURE, - CONNMAN_IPCONFIG_TYPE_IPV4); + __connman_service_indicate_error(service, + CONNMAN_SERVICE_ERROR_CONNECT_FAILED); } static void set_invalid_key_error(struct connman_network *network) @@ -710,7 +713,7 @@ void connman_network_set_ipv4_method(struct connman_network *network, if (ipconfig == NULL) return; - connman_ipconfig_set_method(ipconfig, method); + __connman_ipconfig_set_method(ipconfig, method); } void connman_network_set_ipv6_method(struct connman_network *network, @@ -727,7 +730,7 @@ void connman_network_set_ipv6_method(struct connman_network *network, if (ipconfig == NULL) return; - connman_ipconfig_set_method(ipconfig, method); + __connman_ipconfig_set_method(ipconfig, method); } void connman_network_set_error(struct connman_network *network, @@ -736,6 +739,7 @@ void connman_network_set_error(struct connman_network *network, DBG("nework %p, error %d", network, error); network->connecting = FALSE; + network->associating = FALSE; switch (error) { case CONNMAN_NETWORK_ERROR_UNKNOWN: @@ -773,12 +777,16 @@ void connman_network_clear_error(struct connman_network *network) __connman_service_clear_error(service); } -static void set_configuration(struct connman_network *network) +static void set_configuration(struct connman_network *network, + enum connman_ipconfig_type type) { struct connman_service *service; DBG("network %p", network); + if (network->device == NULL) + return; + __connman_device_set_network(network->device, network); connman_device_set_disconnected(network->device, FALSE); @@ -786,7 +794,7 @@ static void set_configuration(struct connman_network *network) service = __connman_service_lookup_from_network(network); __connman_service_ipconfig_indicate_state(service, CONNMAN_SERVICE_STATE_CONFIGURATION, - CONNMAN_IPCONFIG_TYPE_IPV4); + type); } static void dhcp_success(struct connman_network *network) @@ -855,7 +863,7 @@ static int set_connected_fixed(struct connman_network *network) ipconfig_ipv4 = __connman_service_get_ip4config(service); - set_configuration(network); + set_configuration(network, CONNMAN_IPCONFIG_TYPE_IPV4); network->connecting = FALSE; @@ -893,7 +901,7 @@ static void set_connected_manual(struct connman_network *network) if (__connman_ipconfig_get_local(ipconfig) == NULL) __connman_service_read_ip4config(service); - set_configuration(network); + set_configuration(network, CONNMAN_IPCONFIG_TYPE_IPV4); err = __connman_ipconfig_address_add(ipconfig); if (err < 0) @@ -921,7 +929,7 @@ static int set_connected_dhcp(struct connman_network *network) DBG("network %p", network); - set_configuration(network); + set_configuration(network, CONNMAN_IPCONFIG_TYPE_IPV4); err = __connman_dhcp_start(network, dhcp_callback); if (err < 0) { @@ -970,25 +978,259 @@ static int manual_ipv6_set(struct connman_network *network, 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. + */ +static void dhcpv6_renew_callback(struct connman_network *network, + connman_bool_t success) +{ + if (success == TRUE) + dhcpv6_callback(network, success); + else { + stop_dhcpv6(network); + + /* restart and do solicit again. */ + autoconf_ipv6_set(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; + } + + network->router_solicit_count = 0; + + /* + * 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; + } + + 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; + } + } + + /* 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; + } + + network->router_solicit_refresh_count = RS_REFRESH_COUNT; + + connman_network_ref(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); - /* XXX: Append IPv6 nameservers here */ - 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 gboolean set_connected(gpointer user_data) +static void set_connected(struct connman_network *network) { - struct connman_network *network = user_data; - struct connman_service *service; 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); @@ -1002,123 +1244,160 @@ static gboolean set_connected(gpointer user_data) ipv6_method = __connman_ipconfig_get_method(ipconfig_ipv6); DBG("method ipv4 %d ipv6 %d", ipv4_method, ipv6_method); - DBG("network connected %d", network->connected); - - if (network->connected == TRUE) { - int ret; - switch (ipv6_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, + 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 FALSE; - } - break; - case CONNMAN_IPCONFIG_METHOD_DHCP: - break; + return; } + break; + } - switch (ipv4_method) { - case CONNMAN_IPCONFIG_METHOD_UNKNOWN: - case CONNMAN_IPCONFIG_METHOD_OFF: - case CONNMAN_IPCONFIG_METHOD_AUTO: - return FALSE; - case CONNMAN_IPCONFIG_METHOD_FIXED: - if (set_connected_fixed(network) < 0) { - connman_network_set_error(network, + 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 FALSE; - } - return TRUE; - case CONNMAN_IPCONFIG_METHOD_MANUAL: - set_connected_manual(network); - return TRUE; - case CONNMAN_IPCONFIG_METHOD_DHCP: - if (set_connected_dhcp(network) < 0) { - connman_network_set_error(network, + 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 FALSE; - } + return; } + } - } else { - enum connman_service_state state; + network->connecting = FALSE; - __connman_device_set_network(network->device, NULL); + connman_network_set_associating(network, FALSE); +} - 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; - } +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; - /* - * 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); + if (network->connected == FALSE) + return; - 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); + network->connected = FALSE; - __connman_connection_gateway_remove(service, - CONNMAN_IPCONFIG_TYPE_ALL); + service = __connman_service_lookup_from_network(network); - __connman_ipconfig_address_unset(ipconfig_ipv4); - __connman_ipconfig_address_unset(ipconfig_ipv6); + ipconfig_ipv4 = __connman_service_get_ip4config(service); + ipconfig_ipv6 = __connman_service_get_ip6config(service); - /* - * 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); - } + 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_IDLE, + 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_IDLE, + 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); - - return FALSE; } /** @@ -1131,21 +1410,25 @@ static gboolean set_connected(gpointer user_data) int connman_network_set_connected(struct connman_network *network, connman_bool_t connected) { - DBG("network %p connected %d", network, 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); - __connman_network_disconnect(network); + if (__connman_network_disconnect(network) == 0) + return 0; } if (network->connected == connected) return -EALREADY; - network->connected = connected; - - set_connected(network); + if (connected == FALSE) + set_disconnected(network); + else + set_connected(network); return 0; } @@ -1172,6 +1455,59 @@ connman_bool_t connman_network_get_associating(struct connman_network *network) return network->associating; } +void connman_network_clear_hidden(void *user_data) +{ + if (user_data == NULL) + return; + + DBG("user_data %p", user_data); + + /* + * Hidden service does not have a connect timeout so + * we do not need to remove it. We can just return + * error to the caller telling that we could not find + * any network that we could connect to. + */ + __connman_service_reply_dbus_pending(user_data, EIO); +} + +int connman_network_connect_hidden(struct connman_network *network, + char *identity, char* passphrase, void *user_data) +{ + int err = 0; + struct connman_service *service; + + service = __connman_service_lookup_from_network(network); + + DBG("network %p service %p user_data %p", network, service, user_data); + + if (service == NULL) { + err = -EINVAL; + goto out; + } + + 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); + goto out; + } else { + __connman_service_set_hidden(service); + __connman_service_set_userconnect(service, TRUE); + __connman_service_set_hidden_data(service, user_data); + return __connman_service_connect(service); + } + +out: + __connman_service_return_error(service, -err, user_data); + return err; +} + /** * __connman_network_connect: * @network: network structure @@ -1214,7 +1550,6 @@ int __connman_network_connect(struct connman_network *network) return err; } - network->connected = TRUE; set_connected(network); return err; @@ -1245,10 +1580,8 @@ int __connman_network_disconnect(struct connman_network *network) network->connecting = FALSE; err = network->driver->disconnect(network); - if (err == 0) { - connman_network_set_connected(network, FALSE); - set_connected(network); - } + if (err == 0) + set_disconnected(network); return err; } @@ -1291,8 +1624,10 @@ int __connman_network_clear_ipconfig(struct connman_network *network, 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_AUTO: + release_dhcpv6(network); + break; case CONNMAN_IPCONFIG_METHOD_MANUAL: __connman_ipconfig_address_remove(ipconfig); break; @@ -1395,7 +1730,7 @@ int connman_network_set_nameservers(struct connman_network *network, const char *nameservers) { struct connman_service *service; - char **nameservers_array = NULL; + char **nameservers_array; int i; DBG("network %p nameservers %s", network, nameservers); @@ -1406,12 +1741,14 @@ int connman_network_set_nameservers(struct connman_network *network, __connman_service_nameserver_clear(service); - if (nameservers != NULL) - nameservers_array = g_strsplit(nameservers, " ", 0); + if (nameservers == NULL) + return 0; + + nameservers_array = g_strsplit(nameservers, " ", 0); for (i = 0; nameservers_array[i] != NULL; i++) { __connman_service_nameserver_append(service, - nameservers_array[i]); + nameservers_array[i], FALSE); } g_strfreev(nameservers_array); @@ -1507,23 +1844,6 @@ connman_uint16_t connman_network_get_wifi_channel(struct connman_network *networ } /** - * 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) -{ - DBG("network %p roaming %d", network, roaming); - - network->roaming = roaming; - - return 0; -} - -/** * connman_network_set_string: * @network: network structure * @key: unique identifier @@ -1653,7 +1973,7 @@ 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)