From 84c2a9510cb6606dcdceea55b8250e96954bfe96 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 10 Feb 2011 17:52:13 +0200 Subject: [PATCH] service: Split service state to IPv4 and IPv6 parts --- src/connection.c | 6 +- src/connman.h | 3 +- src/location.c | 3 +- src/network.c | 24 ++-- src/provider.c | 27 ++-- src/service.c | 312 +++++++++++++++++++++++++++++++++++++++-------- 6 files changed, 303 insertions(+), 72 deletions(-) diff --git a/src/connection.c b/src/connection.c index 789a242f..7e517fa7 100644 --- a/src/connection.c +++ b/src/connection.c @@ -332,7 +332,8 @@ static int connection_probe(struct connman_element *element) new_gateway->ipv4_gateway); __connman_service_set_domainname(service, domainname); - __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY); + __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY, + CONNMAN_IPCONFIG_TYPE_IPV4); if (service == NULL) { new_gateway->vpn = TRUE; @@ -376,7 +377,8 @@ static void connection_remove(struct connman_element *element) service = __connman_element_get_service(element); __connman_service_nameserver_del_routes(service); __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_DISCONNECT); + CONNMAN_SERVICE_STATE_DISCONNECT, + CONNMAN_IPCONFIG_TYPE_IPV4); connman_element_set_enabled(element, FALSE); diff --git a/src/connman.h b/src/connman.h index 7f18ff4f..6202db31 100644 --- a/src/connman.h +++ b/src/connman.h @@ -478,7 +478,8 @@ int __connman_service_set_immutable(struct connman_service *service, void __connman_service_set_string(struct connman_service *service, const char *key, const char *value); int __connman_service_indicate_state(struct connman_service *service, - enum connman_service_state state); + enum connman_service_state new_state, + enum connman_ipconfig_type type); int __connman_service_indicate_error(struct connman_service *service, enum connman_service_error error); int __connman_service_clear_error(struct connman_service *service); diff --git a/src/location.c b/src/location.c index 820011f2..ccfb2ed3 100644 --- a/src/location.c +++ b/src/location.c @@ -191,7 +191,8 @@ void connman_location_report_result(struct connman_location *location, break; case CONNMAN_LOCATION_RESULT_ONLINE: __connman_service_indicate_state(location->service, - CONNMAN_SERVICE_STATE_ONLINE); + CONNMAN_SERVICE_STATE_ONLINE, + CONNMAN_IPCONFIG_TYPE_IPV4); break; } } diff --git a/src/network.c b/src/network.c index 09d4d2b9..c3febd3d 100644 --- a/src/network.c +++ b/src/network.c @@ -501,7 +501,8 @@ int connman_network_set_associating(struct connman_network *network, service = __connman_service_lookup_from_network(network); __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_ASSOCIATION); + CONNMAN_SERVICE_STATE_ASSOCIATION, + CONNMAN_IPCONFIG_TYPE_IPV4); } return 0; @@ -519,7 +520,8 @@ static void set_associate_error(struct connman_network *network) service = __connman_service_lookup_from_network(network); __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_FAILURE); + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_IPCONFIG_TYPE_IPV4); } static void set_configure_error(struct connman_network *network) @@ -531,7 +533,8 @@ static void set_configure_error(struct connman_network *network) service = __connman_service_lookup_from_network(network); __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_FAILURE); + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_IPCONFIG_TYPE_IPV4); } static void set_invalid_key_error(struct connman_network *network) @@ -634,7 +637,8 @@ static void set_configuration(struct connman_network *network) service = __connman_service_lookup_from_network(network); __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_CONFIGURATION); + CONNMAN_SERVICE_STATE_CONFIGURATION, + CONNMAN_IPCONFIG_TYPE_IPV4); } static int set_connected_fixed(struct connman_network *network) @@ -710,7 +714,8 @@ static void set_connected_manual(struct connman_network *network) connman_network_set_associating(network, FALSE); - __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY); + __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY, + CONNMAN_IPCONFIG_TYPE_IPV4); } static int set_connected_dhcp(struct connman_network *network) @@ -839,7 +844,8 @@ static gboolean set_connected(gpointer user_data) service = __connman_service_lookup_from_network(network); __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_IDLE); + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV4); } network->connecting = FALSE; @@ -1040,7 +1046,8 @@ static int manual_ipv4_set(struct connman_network *network, __connman_ipconfig_set_gateway(ipconfig, &network->element); - __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY); + __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY, + CONNMAN_IPCONFIG_TYPE_IPV4); return 0; } @@ -1074,7 +1081,8 @@ int __connman_network_clear_ipconfig(struct connman_network *network, } __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_CONFIGURATION); + CONNMAN_SERVICE_STATE_CONFIGURATION, + CONNMAN_IPCONFIG_TYPE_IPV4); return 0; } diff --git a/src/provider.c b/src/provider.c index 6bd2df52..150a7ca3 100644 --- a/src/provider.c +++ b/src/provider.c @@ -179,7 +179,8 @@ int __connman_provider_disconnect(struct connman_provider *provider) if (provider->vpn_service != NULL) __connman_service_indicate_state(provider->vpn_service, - CONNMAN_SERVICE_STATE_DISCONNECT); + CONNMAN_SERVICE_STATE_DISCONNECT, + CONNMAN_IPCONFIG_TYPE_IPV4); if (err < 0) { if (err != -EINPROGRESS) return err; @@ -220,7 +221,8 @@ int __connman_provider_connect(struct connman_provider *provider) return err; __connman_service_indicate_state(provider->vpn_service, - CONNMAN_SERVICE_STATE_ASSOCIATION); + CONNMAN_SERVICE_STATE_ASSOCIATION, + CONNMAN_IPCONFIG_TYPE_IPV4); return -EINPROGRESS; } @@ -327,7 +329,8 @@ static int set_connected(struct connman_provider *provider, int err; __connman_service_indicate_state(provider->vpn_service, - CONNMAN_SERVICE_STATE_CONFIGURATION); + CONNMAN_SERVICE_STATE_CONFIGURATION, + CONNMAN_IPCONFIG_TYPE_IPV4); type = CONNMAN_ELEMENT_TYPE_IPV4; @@ -343,13 +346,15 @@ static int set_connected(struct connman_provider *provider, connman_element_unref(element); __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_FAILURE); + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_IPCONFIG_TYPE_IPV4); return err; } __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_READY); + CONNMAN_SERVICE_STATE_READY, + CONNMAN_IPCONFIG_TYPE_IPV4); __connman_service_set_domainname(service, provider->domain); @@ -360,7 +365,8 @@ static int set_connected(struct connman_provider *provider, } else { connman_element_unregister_children(&provider->element); __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_IDLE); + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV4); } return 0; @@ -379,15 +385,18 @@ int connman_provider_set_state(struct connman_provider *provider, return set_connected(provider, FALSE); case CONNMAN_PROVIDER_STATE_CONNECT: return __connman_service_indicate_state(provider->vpn_service, - CONNMAN_SERVICE_STATE_ASSOCIATION); + CONNMAN_SERVICE_STATE_ASSOCIATION, + CONNMAN_IPCONFIG_TYPE_IPV4); case CONNMAN_PROVIDER_STATE_READY: return set_connected(provider, TRUE); case CONNMAN_PROVIDER_STATE_DISCONNECT: return __connman_service_indicate_state(provider->vpn_service, - CONNMAN_SERVICE_STATE_DISCONNECT); + CONNMAN_SERVICE_STATE_DISCONNECT, + CONNMAN_IPCONFIG_TYPE_IPV4); case CONNMAN_PROVIDER_STATE_FAILURE: return __connman_service_indicate_state(provider->vpn_service, - CONNMAN_SERVICE_STATE_FAILURE); + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_IPCONFIG_TYPE_IPV4); } return -EINVAL; diff --git a/src/service.c b/src/service.c index 4c9fad96..5db3baee 100644 --- a/src/service.c +++ b/src/service.c @@ -58,7 +58,8 @@ struct connman_service { enum connman_service_type type; enum connman_service_mode mode; enum connman_service_security security; - enum connman_service_state state; + enum connman_service_state state_ipv4; + enum connman_service_state state_ipv6; enum connman_service_error error; connman_uint8_t strength; connman_bool_t favorite; @@ -312,9 +313,121 @@ static enum connman_service_proxy_method string2proxymethod(const char *method) return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN; } -static connman_bool_t is_connecting(struct connman_service *service) +static enum connman_service_state combine_state( + enum connman_service_state state_a, + enum connman_service_state state_b) { - switch (service->state) { + enum connman_service_state result; + + if (state_a == state_b) { + result = state_a; + goto done; + } + + if (state_a == CONNMAN_SERVICE_STATE_UNKNOWN) { + result = state_b; + goto done; + } + + if (state_b == CONNMAN_SERVICE_STATE_UNKNOWN) { + result = state_a; + goto done; + } + + if (state_a == CONNMAN_SERVICE_STATE_IDLE) { + result = state_b; + goto done; + } + + if (state_b == CONNMAN_SERVICE_STATE_IDLE) { + result = state_a; + goto done; + } + + if (state_a == CONNMAN_SERVICE_STATE_ASSOCIATION) { + if (state_b == CONNMAN_SERVICE_STATE_CONFIGURATION || + state_b == CONNMAN_SERVICE_STATE_ONLINE || + state_b == CONNMAN_SERVICE_STATE_READY) + result = state_b; + else + result = state_a; + goto done; + } + + if (state_b == CONNMAN_SERVICE_STATE_ASSOCIATION) { + if (state_a == CONNMAN_SERVICE_STATE_CONFIGURATION || + state_a == CONNMAN_SERVICE_STATE_ONLINE || + state_a == CONNMAN_SERVICE_STATE_READY) + result = state_a; + else + result = state_b; + goto done; + } + + if (state_a == CONNMAN_SERVICE_STATE_CONFIGURATION) { + if (state_b == CONNMAN_SERVICE_STATE_ONLINE || + state_b == CONNMAN_SERVICE_STATE_READY) + result = state_b; + else + result = state_a; + goto done; + } + + if (state_b == CONNMAN_SERVICE_STATE_CONFIGURATION) { + if (state_a == CONNMAN_SERVICE_STATE_ONLINE || + state_a == CONNMAN_SERVICE_STATE_READY) + result = state_a; + else + result = state_b; + goto done; + } + + if (state_a == CONNMAN_SERVICE_STATE_READY) { + if (state_b == CONNMAN_SERVICE_STATE_ONLINE) + result = state_b; + else + result = state_a; + goto done; + } + + if (state_b == CONNMAN_SERVICE_STATE_READY) { + if (state_a == CONNMAN_SERVICE_STATE_ONLINE) + result = state_a; + else + result = state_b; + goto done; + } + + if (state_a == CONNMAN_SERVICE_STATE_ONLINE) { + result = state_a; + goto done; + } + + if (state_b == CONNMAN_SERVICE_STATE_ONLINE) { + result = state_b; + goto done; + } + + if (state_a == CONNMAN_SERVICE_STATE_DISCONNECT) { + result = state_b; + goto done; + } + + if (state_b == CONNMAN_SERVICE_STATE_DISCONNECT) { + result = state_a; + goto done; + } + + result = CONNMAN_SERVICE_STATE_FAILURE; + +done: + return result; +} + +static connman_bool_t is_connecting_state(struct connman_service *service, + enum connman_service_state state) +{ + switch (state) { case CONNMAN_SERVICE_STATE_UNKNOWN: case CONNMAN_SERVICE_STATE_IDLE: case CONNMAN_SERVICE_STATE_FAILURE: @@ -333,9 +446,10 @@ static connman_bool_t is_connecting(struct connman_service *service) return FALSE; } -static connman_bool_t is_connected(const struct connman_service *service) +static connman_bool_t is_connected_state(const struct connman_service *service, + enum connman_service_state state) { - switch (service->state) { + switch (state) { case CONNMAN_SERVICE_STATE_UNKNOWN: case CONNMAN_SERVICE_STATE_IDLE: case CONNMAN_SERVICE_STATE_ASSOCIATION: @@ -351,6 +465,24 @@ static connman_bool_t is_connected(const struct connman_service *service) return FALSE; } +static connman_bool_t is_connecting(struct connman_service *service) +{ + enum connman_service_state state; + + state = combine_state(service->state_ipv4, service->state_ipv6); + + return is_connecting_state(service, state); +} + +static connman_bool_t is_connected(struct connman_service *service) +{ + enum connman_service_state state; + + state = combine_state(service->state_ipv4, service->state_ipv6); + + return is_connected_state(service, state); +} + static void update_nameservers(struct connman_service *service) { const char *ifname; @@ -365,7 +497,7 @@ static void update_nameservers(struct connman_service *service) if (ifname == NULL) return; - switch (service->state) { + switch (combine_state(service->state_ipv4, service->state_ipv6)) { case CONNMAN_SERVICE_STATE_UNKNOWN: case CONNMAN_SERVICE_STATE_IDLE: case CONNMAN_SERVICE_STATE_ASSOCIATION: @@ -628,7 +760,8 @@ static void state_changed(struct connman_service *service) { const char *str; - str = state2string(service->state); + str = state2string(combine_state(service->state_ipv4, + service->state_ipv6)); if (str == NULL) return; @@ -797,7 +930,10 @@ static void append_ipv4(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; - if (is_connected(service) == FALSE) + DBG("ipv4 %p state %s", service->ipconfig_ipv4, + state2string(service->state_ipv4)); + + if (is_connected_state(service, service->state_ipv4) == FALSE) return; if (service->ipconfig_ipv4 != NULL) @@ -808,7 +944,10 @@ static void append_ipv6(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; - if (is_connected(service) == FALSE) + DBG("ipv6 %p state %s", service->ipconfig_ipv6, + state2string(service->state_ipv6)); + + if (is_connected_state(service, service->state_ipv6) == FALSE) return; if (service->ipconfig_ipv6 != NULL) @@ -874,7 +1013,8 @@ static void append_domain(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; - if (is_connected(service) == FALSE && is_connecting(service) == FALSE) + if (is_connected(service) == FALSE && + is_connecting(service) == FALSE) return; if (service->domainname == NULL) @@ -1369,7 +1509,8 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited, connman_dbus_dict_append_array(dict, "Security", DBUS_TYPE_STRING, append_security, service); - str = state2string(service->state); + str = state2string(combine_state(service->state_ipv4, + service->state_ipv6)); if (str != NULL) connman_dbus_dict_append_basic(dict, "State", DBUS_TYPE_STRING, &str); @@ -2090,6 +2231,8 @@ static DBusMessage *set_property(DBusConnection *conn, g_str_equal(name, "IPv6.Configuration")) { struct connman_ipconfig *ipv4 = NULL, *ipv6 = NULL; + enum connman_service_state state = + CONNMAN_SERVICE_STATE_UNKNOWN; int err = 0; DBG("%s", name); @@ -2099,7 +2242,9 @@ static DBusMessage *set_property(DBusConnection *conn, return __connman_error_invalid_property(msg); if (g_str_equal(name, "IPv4.Configuration") == TRUE) { - if (is_connecting(service) || is_connected(service)) + state = service->state_ipv4; + if (is_connecting_state(service, state) || + is_connected_state(service, state)) __connman_network_clear_ipconfig( service->network, service->ipconfig_ipv4); @@ -2108,7 +2253,9 @@ static DBusMessage *set_property(DBusConnection *conn, err = __connman_ipconfig_set_config(ipv4, &value); } else if (g_str_equal(name, "IPv6.Configuration") == TRUE) { - if (is_connecting(service) || is_connected(service)) + state = service->state_ipv6; + if (is_connecting_state(service, state) || + is_connected_state(service, state)) __connman_network_clear_ipconfig( service->network, service->ipconfig_ipv6); @@ -2118,7 +2265,8 @@ static DBusMessage *set_property(DBusConnection *conn, } if (err < 0) { - if (is_connected(service) || is_connecting(service)) + if (is_connected_state(service, state) || + is_connecting_state(service, state)) __connman_network_set_ipconfig(service->network, ipv4, ipv6); return __connman_error_failed(msg, -err); @@ -2142,7 +2290,7 @@ static DBusMessage *set_property(DBusConnection *conn, static void set_idle(struct connman_service *service) { - service->state = CONNMAN_SERVICE_STATE_IDLE; + service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE; service->error = CONNMAN_SERVICE_ERROR_UNKNOWN; state_changed(service); } @@ -2190,7 +2338,8 @@ static connman_bool_t is_ignore(struct connman_service *service) if (service->ignore == TRUE) return TRUE; - if (service->state == CONNMAN_SERVICE_STATE_FAILURE) + if (combine_state(service->state_ipv4, service->state_ipv6) == + CONNMAN_SERVICE_STATE_FAILURE) return TRUE; return FALSE; @@ -2221,7 +2370,9 @@ void __connman_service_auto_connect(void) return; if (is_ignore(service) == FALSE && - service->state == CONNMAN_SERVICE_STATE_IDLE) + combine_state(service->state_ipv4, + service->state_ipv6) == + CONNMAN_SERVICE_STATE_IDLE) break; service = NULL; @@ -2294,7 +2445,11 @@ static gboolean connect_timeout(gpointer user_data) autoconnect = TRUE; __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_FAILURE); + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_IPCONFIG_TYPE_IPV4); + __connman_service_indicate_state(service, + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_IPCONFIG_TYPE_IPV6); if (autoconnect == TRUE && service->userconnect == FALSE) __connman_service_auto_connect(); @@ -2423,8 +2578,7 @@ static DBusMessage *connect_service(DBusConnection *conn, while (g_sequence_iter_is_end(iter) == FALSE) { struct connman_service *temp = g_sequence_get(iter); - if (service->type == temp->type && - is_connecting(temp) == TRUE) + if (service->type == temp->type && is_connecting(temp) == TRUE) return __connman_error_in_progress(msg); iter = g_sequence_iter_next(iter); @@ -2502,7 +2656,8 @@ static DBusMessage *remove_service(DBusConnection *conn, return __connman_error_not_supported(msg); if (service->favorite == FALSE && - service->state != CONNMAN_SERVICE_STATE_FAILURE) + combine_state(service->state_ipv4, service->state_ipv6) != + CONNMAN_SERVICE_STATE_FAILURE) return __connman_error_not_supported(msg); if (service->network != NULL) { @@ -2560,7 +2715,8 @@ static DBusMessage *move_service(DBusConnection *conn, DBG("target %s", target->identifier); - if (target->state != service->state) + if (target->state_ipv4 != service->state_ipv4 && + target->state_ipv6 != service->state_ipv6) return __connman_error_invalid_service(msg); g_get_current_time(&service->modified); @@ -2740,7 +2896,9 @@ static void service_initialize(struct connman_service *service) service->type = CONNMAN_SERVICE_TYPE_UNKNOWN; service->mode = CONNMAN_SERVICE_MODE_UNKNOWN; service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN; - service->state = CONNMAN_SERVICE_STATE_UNKNOWN; + + service->state_ipv4 = CONNMAN_SERVICE_STATE_UNKNOWN; + service->state_ipv6 = CONNMAN_SERVICE_STATE_UNKNOWN; service->favorite = FALSE; service->immutable = FALSE; @@ -2843,7 +3001,9 @@ static gint service_compare(gconstpointer a, gconstpointer b, struct connman_service *service_a = (void *) a; struct connman_service *service_b = (void *) b; - if (service_a->state != service_b->state) { + if (service_a->state_ipv4 != service_b->state_ipv4 && + service_a->state_ipv6 != service_b->state_ipv6) { + if (is_connected(service_a) == TRUE) return -1; if (is_connected(service_b) == TRUE) @@ -3079,29 +3239,49 @@ static void report_error_cb(struct connman_service *service, } int __connman_service_indicate_state(struct connman_service *service, - enum connman_service_state state) + enum connman_service_state new_state, + enum connman_ipconfig_type type) { + enum connman_service_state service_state, + state = CONNMAN_SERVICE_STATE_IDLE; GSequenceIter *iter; - DBG("service %p state %d", service, state); - if (service == NULL) return -EINVAL; - if (service->state == state) - return -EALREADY; + if (type == CONNMAN_IPCONFIG_TYPE_IPV4) { + if (service->state_ipv4 == new_state) + return -EALREADY; + state = combine_state(new_state, service->state_ipv6); + } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) { + if (service->state_ipv6 == new_state) + return -EALREADY; + state = combine_state(new_state, service->state_ipv4); + } else + return -EINVAL; + + service_state = combine_state(service->state_ipv4, + service->state_ipv6); - if (service->state == CONNMAN_SERVICE_STATE_FAILURE && + DBG("service %p state %s/%s => %s new %s/%d => %s", + service, + state2string(service->state_ipv4), + state2string(service->state_ipv6), + state2string(service_state), + state2string(new_state), + type, + state2string(state)); + + if (service_state == CONNMAN_SERVICE_STATE_FAILURE && state == CONNMAN_SERVICE_STATE_IDLE) return -EINVAL; - if (service->state == CONNMAN_SERVICE_STATE_IDLE && + if (service_state == CONNMAN_SERVICE_STATE_IDLE && state == CONNMAN_SERVICE_STATE_DISCONNECT) return -EINVAL; if (state == CONNMAN_SERVICE_STATE_IDLE && - service->state != CONNMAN_SERVICE_STATE_DISCONNECT) { - service->state = CONNMAN_SERVICE_STATE_DISCONNECT; + service_state != CONNMAN_SERVICE_STATE_DISCONNECT) { state_changed(service); reply_pending(service, ECONNABORTED); @@ -3109,7 +3289,7 @@ int __connman_service_indicate_state(struct connman_service *service, __connman_service_disconnect(service); } - if (state == CONNMAN_SERVICE_STATE_CONFIGURATION) { + if (new_state == CONNMAN_SERVICE_STATE_CONFIGURATION) { if (__connman_stats_service_register(service) == 0) { __connman_stats_get(service, FALSE, &service->stats.data); @@ -3117,13 +3297,22 @@ int __connman_service_indicate_state(struct connman_service *service, &service->stats_roaming.data); } - if (service->ipconfig_ipv4) + if (type == CONNMAN_IPCONFIG_TYPE_IPV4 && + new_state == CONNMAN_SERVICE_STATE_CONFIGURATION) __connman_ipconfig_enable(service->ipconfig_ipv4); - if (service->ipconfig_ipv6) + else if (type == CONNMAN_IPCONFIG_TYPE_IPV6 && + new_state == CONNMAN_SERVICE_STATE_CONFIGURATION) __connman_ipconfig_enable(service->ipconfig_ipv6); } - service->state = state; + if (type == CONNMAN_IPCONFIG_TYPE_IPV4) + service->state_ipv4 = new_state; + else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) + service->state_ipv6 = new_state; + + if (state == service_state) + return -EALREADY; + state_changed(service); if (state == CONNMAN_SERVICE_STATE_ONLINE) { @@ -3227,10 +3416,12 @@ int __connman_service_indicate_state(struct connman_service *service, __connman_profile_changed(FALSE); - if (service->state == CONNMAN_SERVICE_STATE_ONLINE) + service_state = combine_state(service->state_ipv4, + service->state_ipv6); + if (service_state == CONNMAN_SERVICE_STATE_ONLINE) default_changed(); - if (service->state == CONNMAN_SERVICE_STATE_DISCONNECT) { + if (service_state == CONNMAN_SERVICE_STATE_DISCONNECT) { struct connman_service *def_service = get_default(); if (__connman_notifier_count_connected() == 0 && @@ -3239,8 +3430,8 @@ int __connman_service_indicate_state(struct connman_service *service, __connman_provider_disconnect(def_service->provider); } - if (service->state == CONNMAN_SERVICE_STATE_IDLE || - service->state == CONNMAN_SERVICE_STATE_FAILURE) + if (service_state == CONNMAN_SERVICE_STATE_IDLE || + service_state == CONNMAN_SERVICE_STATE_FAILURE) __connman_element_request_scan(CONNMAN_ELEMENT_TYPE_UNKNOWN); return 0; @@ -3260,27 +3451,37 @@ int __connman_service_indicate_error(struct connman_service *service, __connman_service_set_passphrase(service, NULL); return __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_FAILURE); + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_IPCONFIG_TYPE_IPV4); } int __connman_service_clear_error(struct connman_service *service) { + enum connman_service_state state; + DBG("service %p", service); if (service == NULL) return -EINVAL; - if (service->state != CONNMAN_SERVICE_STATE_FAILURE) + state = combine_state(service->state_ipv4, service->state_ipv6); + + if (state != CONNMAN_SERVICE_STATE_FAILURE) return -EINVAL; - service->state = CONNMAN_SERVICE_STATE_UNKNOWN; + service->state_ipv4 = service->state_ipv6 = + CONNMAN_SERVICE_STATE_UNKNOWN; service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;; if (service->favorite == TRUE) set_reconnect_state(service, TRUE); + __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV6); + return __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_IDLE); + CONNMAN_SERVICE_STATE_IDLE, + CONNMAN_IPCONFIG_TYPE_IPV4); } int __connman_service_indicate_default(struct connman_service *service) @@ -3475,9 +3676,12 @@ static int service_connect(struct connman_service *service) int __connman_service_connect(struct connman_service *service) { + enum connman_service_state state; int err; - DBG("service %p", service); + state = combine_state(service->state_ipv4, service->state_ipv6); + + DBG("service %p state %s", service, state2string(state)); if (is_connected(service) == TRUE) return -EISCONN; @@ -3512,7 +3716,11 @@ int __connman_service_connect(struct connman_service *service) reply_pending(service, err); __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_FAILURE); + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_IPCONFIG_TYPE_IPV4); + __connman_service_indicate_state(service, + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_IPCONFIG_TYPE_IPV6); return err; } @@ -4323,7 +4531,7 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne break; } - service->state = CONNMAN_SERVICE_STATE_IDLE; + service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE; update_from_network(service, network); @@ -4464,7 +4672,7 @@ __connman_service_create_from_provider(struct connman_provider *provider) service->provider = connman_provider_ref(provider); service->autoconnect = FALSE; - service->state = CONNMAN_SERVICE_STATE_IDLE; + service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE; str = connman_provider_get_string(provider, "Name"); if (str != NULL) { @@ -4627,7 +4835,8 @@ static int service_load(struct connman_service *service) service->identifier, "Failure", NULL); if (str != NULL) { if (service->favorite == FALSE) - service->state = CONNMAN_SERVICE_STATE_FAILURE; + service->state_ipv4 = service->state_ipv6 = + CONNMAN_SERVICE_STATE_FAILURE; service->error = string2error(str); } break; @@ -4801,7 +5010,8 @@ update: g_key_file_set_boolean(keyfile, service->identifier, "AutoConnect", service->autoconnect); - if (service->state == CONNMAN_SERVICE_STATE_FAILURE) { + if (service->state_ipv4 == CONNMAN_SERVICE_STATE_FAILURE || + service->state_ipv6 == CONNMAN_SERVICE_STATE_FAILURE) { const char *failure = error2string(service->error); if (failure != NULL) g_key_file_set_string(keyfile, -- 2.34.1