In the Connection Manager, completion of a valid IP configuration
excites the service state machine to move from the "configuration" to
the "ready" state.
However, the existing implementation of IP configuration completion
explicitly attempts to directly manipulate service state, rather than
hinting at an excitation event.
As a consequence, a late IP configuration completion after the service
state machine has transitioned from "ready" to "online" can lead to an
incorrect transition back to the "ready" state. This causes the
connection count for the technology associated with that service to
increment again, unnecessarily.
This patch avoids this issue by providing a service object interface
that simply hints that an IP configuration is complete for a given IP
type, allowing the service object and its state machine to either hold
fast in the present state, returning an advisory error or advancing,
as before.
All prior invocations of __connman_service_indicate_state outside of
the service module for the CONNMAN_SERVICE_STATE_READY are replaced
with calls to this new interface.
Thanks to Daniel Wagner and Marcel Holtmann for offline IRC discussion
that helped motivate this fix.
* v2: Incorporated feedback from Samuel Ortiz about combining IPv4
and IPv6 states before checking state readiness.
__connman_service_nameserver_add_routes(service,
new_gateway->ipv4_gateway);
__connman_service_nameserver_add_routes(service,
new_gateway->ipv4_gateway);
- __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY,
- CONNMAN_IPCONFIG_TYPE_IPV4);
+ __connman_service_set_ipconfig_ready(service, CONNMAN_IPCONFIG_TYPE_IPV4);
if (connman_service_get_type(service) == CONNMAN_SERVICE_TYPE_VPN) {
new_gateway->vpn = TRUE;
if (connman_service_get_type(service) == CONNMAN_SERVICE_TYPE_VPN) {
new_gateway->vpn = TRUE;
void __connman_service_set_string(struct connman_service *service,
const char *key, const char *value);
void __connman_service_set_string(struct connman_service *service,
const char *key, const char *value);
+int __connman_service_set_ipconfig_ready(struct connman_service *service,
+ enum connman_ipconfig_type type);
int __connman_service_indicate_state(struct connman_service *service,
enum connman_service_state new_state,
enum connman_ipconfig_type type);
int __connman_service_indicate_state(struct connman_service *service,
enum connman_service_state new_state,
enum connman_ipconfig_type type);
- __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY,
- CONNMAN_IPCONFIG_TYPE_IPV4);
+ __connman_service_set_ipconfig_ready(service, CONNMAN_IPCONFIG_TYPE_IPV4);
- __connman_service_indicate_state(service,
- CONNMAN_SERVICE_STATE_READY,
- CONNMAN_IPCONFIG_TYPE_IPV4);
+ __connman_service_set_ipconfig_ready(service, CONNMAN_IPCONFIG_TYPE_IPV4);
+
connman_network_set_associating(network, FALSE);
connman_network_set_associating(network, FALSE);
- __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY,
- CONNMAN_IPCONFIG_TYPE_IPV4);
+ __connman_service_set_ipconfig_ready(service, CONNMAN_IPCONFIG_TYPE_IPV4);
network->connecting = FALSE;
network->connecting = FALSE;
- __connman_service_indicate_state(service,
- CONNMAN_SERVICE_STATE_READY,
- CONNMAN_IPCONFIG_TYPE_IPV6);
+ __connman_service_set_ipconfig_ready(service, CONNMAN_IPCONFIG_TYPE_IPV6);
}
static gboolean set_connected(gpointer user_data)
}
static gboolean set_connected(gpointer user_data)
__connman_ipconfig_gateway_add(ipconfig);
__connman_ipconfig_gateway_add(ipconfig);
- __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY,
- CONNMAN_IPCONFIG_TYPE_IPV4);
+ __connman_service_set_ipconfig_ready(service, CONNMAN_IPCONFIG_TYPE_IPV4);
+int __connman_service_set_ipconfig_ready(struct connman_service *service,
+ enum connman_ipconfig_type type)
+{
+ enum connman_service_state state;
+ int err = 0;
+
+ DBG("service %p (%s) type %d (%s)",
+ service, service ? service->identifier : NULL,
+ type, __connman_ipconfig_type2string(type));
+
+ if (service == NULL)
+ return -EINVAL;
+
+ state = combine_state(service->state_ipv4, service->state_ipv6);
+
+ if (state == CONNMAN_SERVICE_STATE_READY ||
+ state == CONNMAN_SERVICE_STATE_ONLINE) {
+ err = -EALREADY;
+ } else {
+ err = __connman_service_indicate_state(service,
+ CONNMAN_SERVICE_STATE_READY, type);
+ }
+
+ return err;
+}
+
int __connman_service_indicate_state(struct connman_service *service,
enum connman_service_state new_state,
enum connman_ipconfig_type type)
int __connman_service_indicate_state(struct connman_service *service,
enum connman_service_state new_state,
enum connman_ipconfig_type type)
if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
method == CONNMAN_IPCONFIG_METHOD_AUTO)
if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
method == CONNMAN_IPCONFIG_METHOD_AUTO)
- __connman_service_indicate_state(service,
- CONNMAN_SERVICE_STATE_READY,
+ __connman_service_set_ipconfig_ready(service,
CONNMAN_IPCONFIG_TYPE_IPV6);
settings_changed(service, ipconfig);
CONNMAN_IPCONFIG_TYPE_IPV6);
settings_changed(service, ipconfig);