return tech_data.preferred_list;
}
-void __connman_service_auto_connect(void)
+static connman_bool_t auto_connect_service(GSequenceIter* iter,
+ connman_bool_t preferred)
{
struct connman_service *service = NULL;
- GSequenceIter *iter;
-
- DBG("");
-
- if (__connman_session_mode() == TRUE) {
- DBG("Session mode enabled: auto connect disabled");
- return;
- }
-
- iter = g_sequence_get_begin_iter(service_list);
while (g_sequence_iter_is_end(iter) == FALSE) {
service = g_sequence_get(iter);
if (service->pending != NULL)
- return;
+ return TRUE;
if (is_connecting(service) == TRUE)
- return;
+ return TRUE;
- if (service->favorite == FALSE)
- return;
+ if (service->favorite == FALSE) {
+ if (preferred == TRUE)
+ goto next_service;
+ return FALSE;
+ }
- if (is_connected(service) == TRUE)
- return;
+ if (is_connected(service) == TRUE) {
+ if (preferred == TRUE && service->state !=
+ CONNMAN_SERVICE_STATE_ONLINE)
+ goto next_service;
+ return TRUE;
+ }
if (is_ignore(service) == FALSE && service->state ==
- CONNMAN_SERVICE_STATE_IDLE)
+ CONNMAN_SERVICE_STATE_IDLE)
break;
+ next_service:
service = NULL;
iter = g_sequence_iter_next(iter);
}
if (service != NULL) {
+
+ DBG("service %p %s %s", service, service->name,
+ (preferred == TRUE)? "preferred": "auto");
+
service->userconnect = FALSE;
__connman_service_connect(service);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void __connman_service_auto_connect(void)
+{
+ GSequenceIter *iter = NULL;
+ GSequence *preferred_tech;
+
+ DBG("");
+
+ if (__connman_session_mode() == TRUE) {
+ DBG("Session mode enabled: auto connect disabled");
+ return;
}
+
+ preferred_tech = preferred_tech_list_get(service_list);
+ if (preferred_tech != NULL)
+ iter = g_sequence_get_begin_iter(preferred_tech);
+
+ if (iter == NULL || auto_connect_service(iter, TRUE) == FALSE)
+ iter = g_sequence_get_begin_iter(service_list);
+
+ if (iter != NULL)
+ auto_connect_service(iter, FALSE);
+
+ if (preferred_tech != NULL)
+ g_sequence_free(preferred_tech);
}
static void remove_timeout(struct connman_service *service)
def_service->state = CONNMAN_SERVICE_STATE_READY;
}
+static void switch_default_service(struct connman_service *default_service,
+ struct connman_service *downgrade_service)
+{
+ GSequenceIter *src, *dst;
+
+ apply_relevant_default_downgrade(default_service);
+ src = g_hash_table_lookup(service_hash, downgrade_service->identifier);
+ dst = g_hash_table_lookup(service_hash, default_service->identifier);
+ g_sequence_move(src, dst);
+ downgrade_state(downgrade_service);
+}
+
static DBusMessage *move_service(DBusConnection *conn,
DBusMessage *msg, void *user_data,
gboolean before)
struct connman_service *service = user_data;
struct connman_service *target;
const char *path;
- GSequenceIter *src, *dst;
enum connman_ipconfig_method target4, target6;
enum connman_ipconfig_method service4, service6;
service_save(service);
service_save(target);
- src = g_hash_table_lookup(service_hash, service->identifier);
- dst = g_hash_table_lookup(service_hash, target->identifier);
-
/*
* If the service which goes down is the default service and is
* online, we downgrade directly its state to ready so:
* the service which goes up, needs to recompute its state which
* is triggered via downgrading it - if relevant - to state ready.
*/
- if (before == TRUE) {
- apply_relevant_default_downgrade(target);
- g_sequence_move(src, dst);
- downgrade_state(service);
- } else {
- apply_relevant_default_downgrade(service);
- g_sequence_move(dst, src);
- downgrade_state(target);
- }
+ if (before == TRUE)
+ switch_default_service(target, service);
+ else
+ switch_default_service(service, target);
__connman_connection_update_gateway();
}
}
+static int service_update_preferred_order(struct connman_service *default_service,
+ struct connman_service *new_service,
+ enum connman_service_state new_state)
+{
+ unsigned int *tech_array;
+ int i;
+
+ if (default_service == NULL || default_service == new_service ||
+ default_service->state != new_state )
+ return 0;
+
+ tech_array = connman_setting_get_uint_list("PreferredTechnologies");
+ if (tech_array != NULL) {
+
+ for (i = 0; tech_array[i] != 0; i += 1) {
+ if (default_service->type == tech_array[i])
+ return -EALREADY;
+
+ if (new_service->type == tech_array[i]) {
+ switch_default_service(new_service,
+ default_service);
+ return 0;
+ }
+ }
+ return -EAGAIN;
+ }
+
+ return -EALREADY;
+}
+
static int service_indicate_state(struct connman_service *service)
{
enum connman_service_state old_state, new_state;
struct connman_service *def_service;
+ int result;
GSequenceIter *iter;
if (service == NULL)
def_service = __connman_service_get_default();
if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
- if (def_service != NULL && def_service != service &&
- def_service->state == CONNMAN_SERVICE_STATE_ONLINE)
- return -EALREADY;
+ result = service_update_preferred_order(def_service,
+ service, new_state);
+ if (result == -EALREADY)
+ return result;
+ if (result == -EAGAIN)
+ __connman_service_auto_connect();
}
service->state = new_state;
if (new_state == CONNMAN_SERVICE_STATE_READY) {
enum connman_ipconfig_method method;
+ service_update_preferred_order(def_service, service, new_state);
+
set_reconnect_state(service, TRUE);
__connman_service_set_favorite(service, TRUE);
DBG("service %p type %d count %d", service, type,
service->online_check_count);
- if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
- /* currently we only retry IPv6 stuff */
- return 0;
-
- if (service->online_check_count != 1)
+ /* currently we only retry IPv6 stuff */
+ if (type == CONNMAN_IPCONFIG_TYPE_IPV4 ||
+ service->online_check_count != 1) {
+ __connman_service_auto_connect();
return 0;
+ }
service->online_check_count = 0;