diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2009-06-26 14:33:56 +0200 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-06-26 14:33:56 +0200 |
commit | 95add56345f63e19ca7c1faa8fd908e0498f5df2 (patch) | |
tree | 549505b9440aca574e19e73d3b7072b4005d084f /src/connection.c | |
parent | 5a699f7b96116d0ff9bb193f0c0443408ebc031b (diff) | |
download | connman-95add56345f63e19ca7c1faa8fd908e0498f5df2.tar.gz connman-95add56345f63e19ca7c1faa8fd908e0498f5df2.tar.bz2 connman-95add56345f63e19ca7c1faa8fd908e0498f5df2.zip |
Add support for switching default route based on service order
Diffstat (limited to 'src/connection.c')
-rw-r--r-- | src/connection.c | 220 |
1 files changed, 128 insertions, 92 deletions
diff --git a/src/connection.c b/src/connection.c index 293b9111..d057d8a6 100644 --- a/src/connection.c +++ b/src/connection.c @@ -38,6 +38,9 @@ struct gateway_data { int index; char *gateway; + struct connman_element *element; + unsigned int order; + gboolean active; }; static GSList *gateway_list = NULL; @@ -63,17 +66,6 @@ static struct gateway_data *find_gateway(int index, const char *gateway) return NULL; } -static void remove_gateway(int index, const char *gateway) -{ - struct gateway_data *data; - - data = find_gateway(index, gateway); - if (data == NULL) - return; - - gateway_list = g_slist_remove(gateway_list, data); -} - static int set_route(struct connman_element *element, const char *gateway) { struct ifreq ifr; @@ -218,87 +210,99 @@ static void emit_default_signal(struct connman_element *element) g_dbus_send_message(connection, signal); } -static void set_default(struct connman_element *element, gpointer user_data) +static void find_element(struct connman_element *element, gpointer user_data) { struct gateway_data *data = user_data; DBG("element %p name %s", element, element->name); - if (element->index != data->index) + if (data->element != NULL) return; - if (element->enabled == TRUE) + if (element->index != data->index) return; - connman_element_set_enabled(element, TRUE); - emit_default_signal(element); + data->element = element; } -static void del_default(struct connman_element *element, gpointer user_data) +static struct gateway_data *add_gateway(int index, const char *gateway) { - struct gateway_data *data = user_data; + struct gateway_data *data; + struct connman_service *service; - DBG("element %p name %s", element, element->name); + data = g_try_new0(struct gateway_data, 1); + if (data == NULL) + return NULL; - if (element->index != data->index) - return; + data->index = index; + data->gateway = g_strdup(gateway); + data->active = FALSE; + data->element = NULL; - if (element->enabled == FALSE) - return; + __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, + find_element, data); - connman_element_set_enabled(element, FALSE); - emit_default_signal(element); + service = __connman_element_get_service(data->element); + if (service != NULL) + data->order = __connman_service_get_order(service); + + gateway_list = g_slist_append(gateway_list, data); + + return data; } -static void new_default(struct connman_element *element, gpointer user_data) +static void connection_newgateway(int index, const char *gateway) { - struct connman_service *service; - const char *gateway; + struct gateway_data *data; - DBG("element %p name %s", element, element->name); + DBG("index %d gateway %s", index, gateway); - if (g_slist_length(gateway_list) > 0) + data = find_gateway(index, gateway); + if (data == NULL) return; - connman_element_get_value(element, - CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway); + data->active = TRUE; +} - DBG("gateway %s", gateway); +static void set_default_gateway(struct gateway_data *data) +{ + struct connman_element *element = data->element; + struct connman_service *service = NULL; - if (gateway == NULL) - return; + DBG("gateway %s", data->gateway); - if (set_route(element, gateway) < 0) + if (set_route(element, data->gateway) < 0) return; service = __connman_element_get_service(element); __connman_service_indicate_default(service); - - connman_element_set_enabled(element, TRUE); - emit_default_signal(element); } -static void connection_newgateway(int index, const char *gateway) +static struct gateway_data *find_default_gateway(void) { - struct gateway_data *data; + struct gateway_data *found = NULL; + GSList *list; - DBG("index %d gateway %s", index, gateway); + for (list = gateway_list; list; list = list->next) { + struct gateway_data *data = list->data; + /* just return the last one for now */ + found = data; + } - data = find_gateway(index, gateway); - if (data != NULL) - return; + return found; +} - data = g_try_new0(struct gateway_data, 1); - if (data == NULL) - return; +static void remove_gateway(struct gateway_data *data) +{ + DBG("gateway %s", data->gateway); - data->index = index; - data->gateway = g_strdup(gateway); + gateway_list = g_slist_remove(gateway_list, data); - gateway_list = g_slist_append(gateway_list, data); + if (data->active == TRUE) + del_route(data->element, data->gateway); - __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, - set_default, data); + g_free(data->gateway); + g_free(data); } static void connection_delgateway(int index, const char *gateway) @@ -308,24 +312,12 @@ static void connection_delgateway(int index, const char *gateway) DBG("index %d gateway %s", index, gateway); data = find_gateway(index, gateway); - if (data == NULL) - return; - - gateway_list = g_slist_remove(gateway_list, data); - - __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, - del_default, data); - - g_free(data->gateway); - g_free(data); - - if (g_slist_length(gateway_list) > 0) - return; - - DBG("selecting new default gateway"); + if (data != NULL) + data->active = FALSE; - __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, - new_default, NULL); + data = find_default_gateway(); + if (data != NULL) + set_default_gateway(data); } static struct connman_rtnl connection_rtnl = { @@ -455,6 +447,8 @@ static void emit_connections_signal(void) DBusMessage *signal; DBusMessageIter entry; + DBG(""); + signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE, "PropertyChanged"); if (signal == NULL) @@ -469,7 +463,8 @@ static void emit_connections_signal(void) static int register_interface(struct connman_element *element) { - DBG("element %p name %s", element, element->name); + DBG("element %p name %s path %s", + element, element->name, element->path); if (g_dbus_register_interface(connection, element->path, CONNMAN_CONNECTION_INTERFACE, @@ -494,10 +489,27 @@ static void unregister_interface(struct connman_element *element) CONNMAN_CONNECTION_INTERFACE); } +static struct gateway_data *find_active_gateway(void) +{ + GSList *list; + + DBG(""); + + for (list = gateway_list; list; list = list->next) { + struct gateway_data *data = list->data; + if (data->active == TRUE) + return data; + } + + return NULL; +} + static int connection_probe(struct connman_element *element) { - struct connman_service *service; + struct connman_service *service = NULL; const char *gateway = NULL; + struct gateway_data *active_gateway = NULL; + struct gateway_data *new_gateway = NULL; DBG("element %p name %s", element, element->name); @@ -514,33 +526,27 @@ static int connection_probe(struct connman_element *element) if (register_interface(element) < 0) return -ENODEV; - service = __connman_element_get_service(element); __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY); + connman_element_set_enabled(element, TRUE); + emit_default_signal(element); if (gateway == NULL) return 0; - if (find_gateway(element->index, gateway) != NULL) { - DBG("previous gateway still present"); - goto done; - } + active_gateway = find_active_gateway(); + new_gateway = add_gateway(element->index, gateway); - if (g_slist_length(gateway_list) > 0) { - DBG("default gateway already present"); + if (active_gateway == NULL) { + set_default_gateway(new_gateway); return 0; } - if (set_route(element, gateway) < 0) + if (new_gateway->order >= active_gateway->order) { + del_route(active_gateway->element, active_gateway->gateway); return 0; - -done: - service = __connman_element_get_service(element); - __connman_service_indicate_default(service); - - connman_element_set_enabled(element, TRUE); - emit_default_signal(element); + } return 0; } @@ -549,6 +555,7 @@ static void connection_remove(struct connman_element *element) { struct connman_service *service; const char *gateway = NULL; + struct gateway_data *data = NULL; DBG("element %p name %s", element, element->name); @@ -556,6 +563,9 @@ static void connection_remove(struct connman_element *element) __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_DISCONNECT); + connman_element_set_enabled(element, FALSE); + emit_default_signal(element); + unregister_interface(element); connman_element_get_value(element, @@ -566,12 +576,11 @@ static void connection_remove(struct connman_element *element) if (gateway == NULL) return; - remove_gateway(element->index, gateway); - - connman_element_set_enabled(element, FALSE); - emit_default_signal(element); + data = find_gateway(element->index, gateway); + if (data == NULL) + return; - del_route(element, gateway); + remove_gateway(data); } static struct connman_driver connection_driver = { @@ -621,3 +630,30 @@ void __connman_connection_cleanup(void) dbus_connection_unref(connection); } + +static void update_order(void) +{ + GSList *list = NULL; + + for (list = gateway_list; list; list = list->next) { + struct gateway_data *data = list->data; + struct connman_service *service; + + service = __connman_element_get_service(data->element); + + data->order = __connman_service_get_order(service); + } +} + +void __connman_connection_update_gateway(void) +{ + struct gateway_data *active_gateway, *default_gateway; + + update_order(); + + active_gateway = find_active_gateway(); + default_gateway = find_default_gateway(); + + if (active_gateway != default_gateway) + del_route(active_gateway->element, active_gateway->gateway); +} |