--- src/connection.c | 6 +- src/connman.h | 3 +- src/location.c | 3 +- src/network.c | 24 +++-- src/provider.c | 27 +++-- src/service.c | 335 +++++++++++++++++++++++++++++++++++++++++++---------- 6 files changed, 313 insertions(+), 85 deletions(-)
diff --git a/src/connection.c b/src/connection.c index 789a242..844c279 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_SERVICE_STATE_UNKNOWN); 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_SERVICE_STATE_UNKNOWN); connman_element_set_enabled(element, FALSE); diff --git a/src/connman.h b/src/connman.h index 12566aa..45f600f 100644 --- a/src/connman.h +++ b/src/connman.h @@ -484,7 +484,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 state_ipv4, + enum connman_service_state state_ipv6); int __connman_service_indicate_error(struct connman_service *service, enum connman_service_error error); int __connman_service_indicate_default(struct connman_service *service); diff --git a/src/location.c b/src/location.c index e7bfdc0..46928b5 100644 --- a/src/location.c +++ b/src/location.c @@ -186,7 +186,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_SERVICE_STATE_UNKNOWN); break; } } diff --git a/src/network.c b/src/network.c index 612e923..05ee0c1 100644 --- a/src/network.c +++ b/src/network.c @@ -497,7 +497,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_SERVICE_STATE_UNKNOWN); } return 0; @@ -515,7 +516,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_SERVICE_STATE_UNKNOWN); } static void set_configure_error(struct connman_network *network) @@ -527,7 +529,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_SERVICE_STATE_UNKNOWN); } void connman_network_set_ipv4_method(struct connman_network *network, @@ -601,7 +604,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_SERVICE_STATE_UNKNOWN); } static int set_connected_fixed(struct connman_network *network) @@ -677,7 +681,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_SERVICE_STATE_UNKNOWN); } static int set_connected_dhcp(struct connman_network *network) @@ -806,7 +811,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_SERVICE_STATE_UNKNOWN); } network->connecting = FALSE; @@ -1007,7 +1013,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_SERVICE_STATE_UNKNOWN); return 0; } @@ -1041,7 +1048,8 @@ int __connman_network_clear_ipconfig(struct connman_network *network, } __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_CONFIGURATION); + CONNMAN_SERVICE_STATE_CONFIGURATION, + CONNMAN_SERVICE_STATE_UNKNOWN); return 0; } diff --git a/src/provider.c b/src/provider.c index 53b3ddd..6d42426 100644 --- a/src/provider.c +++ b/src/provider.c @@ -177,7 +177,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_SERVICE_STATE_UNKNOWN); if (err < 0) { if (err != -EINPROGRESS) return err; @@ -218,7 +219,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_SERVICE_STATE_UNKNOWN); return -EINPROGRESS; } @@ -272,7 +274,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_SERVICE_STATE_UNKNOWN); type = CONNMAN_ELEMENT_TYPE_IPV4; @@ -288,13 +291,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_SERVICE_STATE_UNKNOWN); return err; } __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_READY); + CONNMAN_SERVICE_STATE_READY, + CONNMAN_SERVICE_STATE_UNKNOWN); __connman_service_set_domainname(service, provider->domain); @@ -332,7 +337,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_SERVICE_STATE_UNKNOWN); } return 0; @@ -351,15 +357,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_SERVICE_STATE_UNKNOWN); 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_SERVICE_STATE_UNKNOWN); case CONNMAN_PROVIDER_STATE_FAILURE: return __connman_service_indicate_state(provider->vpn_service, - CONNMAN_SERVICE_STATE_FAILURE); + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_SERVICE_STATE_UNKNOWN); } return -EINVAL; diff --git a/src/service.c b/src/service.c index 0ea1223..98f824b 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; @@ -303,9 +304,126 @@ 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: +#if 0 + /* Enable this only if needed, it prints too much data */ + DBG("%s | %s => %s", state2string(state_a), state2string(state_b), + state2string(result)); +#endif + return result; +} + +static connman_bool_t is_connecting(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: @@ -324,9 +442,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(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: @@ -356,7 +475,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: @@ -578,7 +697,8 @@ static struct connman_service *get_default(void) service = g_sequence_get(iter); - if (is_connected(service) == FALSE) + if (is_connected(service, combine_state(service->state_ipv4, + service->state_ipv6)) == FALSE) return NULL; return service; @@ -619,7 +739,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; @@ -772,7 +893,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(service, service->state_ipv4) == FALSE) return; if (service->ipconfig_ipv4 != NULL) @@ -783,7 +907,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(service, service->state_ipv6) == FALSE) return; if (service->ipconfig_ipv6 != NULL) @@ -812,7 +939,8 @@ static void append_dns(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; - if (is_connected(service) == FALSE) + if (is_connected(service, combine_state(service->state_ipv4, + service->state_ipv6)) == FALSE) return; if (service->nameservers != NULL) { @@ -848,8 +976,12 @@ static void append_dnsconfig(DBusMessageIter *iter, void *user_data) static void append_domain(DBusMessageIter *iter, void *user_data) { struct connman_service *service = user_data; + enum connman_service_state state; + + state = combine_state(service->state_ipv4, service->state_ipv6); - if (is_connected(service) == FALSE && is_connecting(service) == FALSE) + if (is_connected(service, state) == FALSE && + is_connecting(service, state) == FALSE) return; if (service->domainname == NULL) @@ -908,7 +1040,8 @@ static void append_proxy(DBusMessageIter *iter, void *user_data) DBG(""); - if (is_connected(service) == FALSE) + if (is_connected(service, combine_state(service->state_ipv4, + service->state_ipv6)) == FALSE) return; proxy = connman_service_get_proxy_method(service); @@ -997,7 +1130,8 @@ static void append_provider(DBusMessageIter *iter, void *user_data) DBG("%p %p", service, service->provider); - if (is_connected(service) == FALSE) + if (is_connected(service, combine_state(service->state_ipv4, + service->state_ipv6)) == FALSE) return; if (service->provider != NULL) @@ -1250,7 +1384,8 @@ void __connman_service_notify(struct connman_service *service, if (service == NULL) return; - if (is_connected(service) == FALSE) + if (is_connected(service, combine_state(service->state_ipv4, + service->state_ipv6)) == FALSE) return; stats_update(service, @@ -1346,7 +1481,8 @@ static void append_properties(DBusMessageIter *dict, dbus_bool_t limited, connman_dbus_dict_append_basic(dict, "Security", DBUS_TYPE_STRING, &str); - 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); @@ -2066,6 +2202,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); @@ -2075,7 +2213,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(service, state) || + is_connected(service, state)) __connman_network_clear_ipconfig( service->network, service->ipconfig_ipv4); @@ -2084,7 +2224,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(service, state) || + is_connected(service, state)) __connman_network_clear_ipconfig( service->network, service->ipconfig_ipv6); @@ -2094,7 +2236,8 @@ static DBusMessage *set_property(DBusConnection *conn, } if (err < 0) { - if (is_connected(service) || is_connecting(service)) + if (is_connected(service, state) || + is_connecting(service, state)) __connman_network_set_ipconfig(service->network, ipv4, ipv6); return __connman_error_failed(msg, -err); @@ -2105,7 +2248,10 @@ static DBusMessage *set_property(DBusConnection *conn, else if (ipv6) ipv6_configuration_changed(service); - if (is_connecting(service) || is_connected(service)) + state = combine_state(service->state_ipv4, + service->state_ipv6); + if (is_connecting(service, state) || + is_connected(service, state)) __connman_network_set_ipconfig(service->network, ipv4, ipv6); @@ -2118,7 +2264,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); } @@ -2166,7 +2312,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; @@ -2182,22 +2329,26 @@ void __connman_service_auto_connect(void) iter = g_sequence_get_begin_iter(service_list); while (g_sequence_iter_is_end(iter) == FALSE) { + enum connman_service_state state; + service = g_sequence_get(iter); if (service->pending != NULL) return; - if (is_connecting(service) == TRUE) + state = combine_state(service->state_ipv4, + service->state_ipv6); + if (is_connecting(service, state) == TRUE) return; if (service->favorite == FALSE) return; - if (is_connected(service) == TRUE) + if (is_connected(service, state) == TRUE) return; if (is_ignore(service) == FALSE && - service->state == CONNMAN_SERVICE_STATE_IDLE) + state == CONNMAN_SERVICE_STATE_IDLE) break; service = NULL; @@ -2270,6 +2421,7 @@ static gboolean connect_timeout(gpointer user_data) autoconnect = TRUE; __connman_service_indicate_state(service, + CONNMAN_SERVICE_STATE_FAILURE, CONNMAN_SERVICE_STATE_FAILURE); if (autoconnect == TRUE && service->userconnect == FALSE) @@ -2322,6 +2474,7 @@ struct connman_service * __connman_service_connect_type(enum connman_service_type type) { struct connman_service *service; + enum connman_service_state state; GSequenceIter *iter; int err; @@ -2337,13 +2490,15 @@ __connman_service_connect_type(enum connman_service_type type) return NULL; service = g_sequence_get(iter); + state = combine_state(service->state_ipv4, service->state_ipv6); + /* * If the first service is connected or about to be * connected, we return it, regardless of the type. */ if ((g_sequence_iter_is_end(iter) == FALSE) && - (is_connecting(service) == TRUE || - is_connected(service) == TRUE)) + (is_connecting(service, state) == TRUE || + is_connected(service, state) == TRUE)) return service; while (g_sequence_iter_is_end(iter) == FALSE) { @@ -2397,7 +2552,9 @@ static DBusMessage *connect_service(DBusConnection *conn, struct connman_service *temp = g_sequence_get(iter); if (service->type == temp->type && - is_connecting(temp) == TRUE) + is_connecting(temp, + combine_state(temp->state_ipv4, + temp->state_ipv6)) == TRUE) return __connman_error_in_progress(msg); iter = g_sequence_iter_next(iter); @@ -2472,7 +2629,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) { @@ -2530,7 +2688,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); @@ -2710,7 +2869,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; @@ -2811,15 +2972,25 @@ 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 (is_connected(service_a) == TRUE) + if (service_a->state_ipv4 != service_b->state_ipv4 && + service_a->state_ipv6 != service_b->state_ipv6) { + + if (is_connected(service_a, service_a->state_ipv4) == TRUE) + return -1; + if (is_connected(service_a, service_a->state_ipv6) == TRUE) return -1; - if (is_connected(service_b) == TRUE) + if (is_connected(service_b, service_b->state_ipv4) == TRUE) + return 1; + if (is_connected(service_b, service_b->state_ipv6) == TRUE) return 1; - if (is_connecting(service_a) == TRUE) + if (is_connecting(service_a, service_a->state_ipv4) == TRUE) + return -1; + if (is_connecting(service_a, service_a->state_ipv6) == TRUE) return -1; - if (is_connecting(service_b) == TRUE) + if (is_connecting(service_b, service_b->state_ipv4) == TRUE) + return 1; + if (is_connecting(service_b, service_b->state_ipv6) == TRUE) return 1; } @@ -3039,29 +3210,44 @@ 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 state_ipv4, + enum connman_service_state state_ipv6) { + enum connman_service_state service_state, state; GSequenceIter *iter; - DBG("service %p state %d", service, state); - if (service == NULL) return -EINVAL; - if (service->state == state) + if ((service->state_ipv4 == state_ipv4 || + state_ipv4 == CONNMAN_SERVICE_STATE_UNKNOWN) && + (service->state_ipv6 == state_ipv6 || + state_ipv6 == CONNMAN_SERVICE_STATE_UNKNOWN)) return -EALREADY; - if (service->state == CONNMAN_SERVICE_STATE_FAILURE && + state = combine_state(state_ipv4, state_ipv6); + service_state = combine_state(service->state_ipv4, + service->state_ipv6); + + DBG("service %p state %s/%s => %s new %s/%s => %s", + service, + state2string(service->state_ipv4), + state2string(service->state_ipv6), + state2string(service_state), + state2string(state_ipv4), + state2string(state_ipv6), + 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); @@ -3077,13 +3263,19 @@ int __connman_service_indicate_state(struct connman_service *service, &service->stats_roaming.data); } - if (service->ipconfig_ipv4) + if (state_ipv4 == CONNMAN_SERVICE_STATE_CONFIGURATION) __connman_ipconfig_enable(service->ipconfig_ipv4); - if (service->ipconfig_ipv6) + + if (state_ipv6 == CONNMAN_SERVICE_STATE_CONFIGURATION) __connman_ipconfig_enable(service->ipconfig_ipv6); } - service->state = state; + if (state_ipv4 != CONNMAN_SERVICE_STATE_UNKNOWN) + service->state_ipv4 = state_ipv4; + + if (state_ipv6 != CONNMAN_SERVICE_STATE_UNKNOWN) + service->state_ipv6 = state_ipv6; + state_changed(service); if (state == CONNMAN_SERVICE_STATE_ONLINE) { @@ -3173,10 +3365,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 && @@ -3185,8 +3379,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; @@ -3203,7 +3397,8 @@ int __connman_service_indicate_error(struct connman_service *service, service->error = error; return __connman_service_indicate_state(service, - CONNMAN_SERVICE_STATE_FAILURE); + CONNMAN_SERVICE_STATE_FAILURE, + CONNMAN_SERVICE_STATE_UNKNOWN); } int __connman_service_indicate_default(struct connman_service *service) @@ -3304,14 +3499,17 @@ static void prepare_8021x(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); - if (is_connected(service) == TRUE) + DBG("service %p state %s", service, state2string(state)); + + if (is_connected(service, state) == TRUE) return -EISCONN; - if (is_connecting(service) == TRUE) + if (is_connecting(service, state) == TRUE) return -EALREADY; switch (service->type) { @@ -3543,6 +3741,7 @@ int __connman_service_create_and_connect(DBusMessage *msg) struct connman_service *service; struct connman_network *network; struct connman_device *device; + enum connman_service_state state; DBusMessageIter iter, array; const char *mode = "managed", *security = "none", *group_security; const char *type = NULL, *ssid = NULL, *passphrase = NULL; @@ -3651,12 +3850,14 @@ done: goto failed; } - if (is_connected(service) == TRUE) { + state = combine_state(service->state_ipv4, service->state_ipv6); + + if (is_connected(service, state) == TRUE) { err = -EISCONN; goto failed; } - if (is_connecting(service) == TRUE) { + if (is_connecting(service, state) == TRUE) { err = -EALREADY; goto failed; } @@ -4082,15 +4283,19 @@ static void update_from_network(struct connman_service *service, struct connman_network *network) { connman_uint8_t strength = service->strength; + enum connman_service_state state; GSequenceIter *iter; const char *str; - DBG("service %p network %p", service, network); + state = combine_state(service->state_ipv4, service->state_ipv6); + + DBG("service %p network %p state %s", service, network, + state2string(state)); - if (is_connected(service) == TRUE) + if (is_connected(service, state) == TRUE) return; - if (is_connecting(service) == TRUE) + if (is_connecting(service, state) == TRUE) return; str = connman_network_get_string(network, "Name"); @@ -4211,7 +4416,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); @@ -4349,7 +4554,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) { @@ -4512,7 +4717,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; @@ -4686,7 +4892,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, -- 1.7.0.4 _______________________________________________ connman mailing list connman@connman.net http://lists.connman.net/listinfo/connman