X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fconnection.c;h=cb0b52817ced507415b0cb71d0b2dca72f21a3e8;hb=171d554c7fe91e9f9c266d466946b2eed43b7e7e;hp=7344cd4880cfbbd8386077a11c9a1ec51f153ccf;hpb=e10cccf70309a219f0068b636a5f466456008989;p=platform%2Fupstream%2Fconnman.git diff --git a/src/connection.c b/src/connection.c index 7344cd4..cb0b528 100644 --- a/src/connection.c +++ b/src/connection.c @@ -2,7 +2,7 @@ * * Connection Manager * - * Copyright (C) 2007-2009 Intel Corporation. All rights reserved. + * Copyright (C) 2007-2010 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -23,13 +23,8 @@ #include #endif -#include -#include #include -#include -#include #include -#include #include @@ -37,7 +32,14 @@ struct gateway_data { int index; - char *gateway; + char *ipv4_gateway; + struct connman_element *element; + unsigned int order; + gboolean active; + /* VPN extra data */ + gboolean vpn; + char *vpn_ip; + int vpn_phy_index; }; static GSList *gateway_list = NULL; @@ -52,38 +54,82 @@ static struct gateway_data *find_gateway(int index, const char *gateway) for (list = gateway_list; list; list = list->next) { struct gateway_data *data = list->data; - if (data->gateway == NULL) + if (data->ipv4_gateway == NULL) continue; if (data->index == index && - g_str_equal(data->gateway, gateway) == TRUE) + g_str_equal(data->ipv4_gateway, gateway) + == TRUE) return data; } return NULL; } -static void connection_newgateway(int index, const char *gateway) +static int del_routes(struct gateway_data *data) { - struct gateway_data *data; + if (data->vpn) { + if (data->vpn_phy_index >= 0) + connman_inet_del_host_route(data->vpn_phy_index, + data->ipv4_gateway); + return connman_inet_clear_gateway_address(data->index, + data->vpn_ip); + } else if (g_strcmp0(data->ipv4_gateway, "0.0.0.0") == 0) { + return connman_inet_clear_gateway_interface(data->index); + } else { + connman_inet_del_host_route(data->index, data->ipv4_gateway); + return connman_inet_clear_gateway_address(data->index, + data->ipv4_gateway); + } +} - DBG("index %d gateway %s", index, gateway); +static void find_element(struct connman_element *element, gpointer user_data) +{ + struct gateway_data *data = user_data; - data = find_gateway(index, gateway); - if (data != NULL) + DBG("element %p name %s", element, element->name); + + if (data->element != NULL) return; + if (element->index != data->index) + return; + + data->element = element; +} + +static struct gateway_data *add_gateway(int index, const char *gateway) +{ + struct gateway_data *data; + struct connman_service *service; + + if (strlen(gateway) == 0) + return NULL; + data = g_try_new0(struct gateway_data, 1); if (data == NULL) - return; + return NULL; data->index = index; - data->gateway = g_strdup(gateway); + data->ipv4_gateway = g_strdup(gateway); + data->active = FALSE; + data->element = NULL; + data->vpn_ip = NULL; + data->vpn = FALSE; + data->vpn_phy_index = -1; + + __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, + find_element, data); + + service = __connman_element_get_service(data->element); + data->order = __connman_service_get_order(service); gateway_list = g_slist_append(gateway_list, data); + + return data; } -static void connection_delgateway(int index, const char *gateway) +static void connection_newgateway(int index, const char *gateway) { struct gateway_data *data; @@ -93,285 +139,208 @@ static void connection_delgateway(int index, const char *gateway) if (data == NULL) return; - gateway_list = g_slist_remove(gateway_list, data); - - g_free(data->gateway); - g_free(data); + data->active = TRUE; } -static struct connman_rtnl connection_rtnl = { - .name = "connection", - .newgateway = connection_newgateway, - .delgateway = connection_delgateway, -}; - -static int set_route(struct connman_element *element, const char *gateway) +static void set_default_gateway(struct gateway_data *data) { - struct ifreq ifr; - struct rtentry rt; - struct sockaddr_in *addr; - int sk, err; - - DBG("element %p", element); + struct connman_element *element = data->element; + struct connman_service *service = NULL; - sk = socket(PF_INET, SOCK_DGRAM, 0); - if (sk < 0) - return -1; + DBG("gateway %s", data->ipv4_gateway); - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_ifindex = element->index; - - if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) { - close(sk); - return -1; + if (data->vpn == TRUE) { + connman_inet_set_gateway_address(data->index, data->vpn_ip); + data->active = TRUE; + /* vpn gateway going away no changes in services */ + return; } - DBG("ifname %s", ifr.ifr_name); - - memset(&rt, 0, sizeof(rt)); - rt.rt_flags = RTF_UP | RTF_GATEWAY; - - addr = (struct sockaddr_in *) &rt.rt_dst; - addr->sin_family = AF_INET; - addr->sin_addr.s_addr = INADDR_ANY; - - addr = (struct sockaddr_in *) &rt.rt_gateway; - addr->sin_family = AF_INET; - addr->sin_addr.s_addr = inet_addr(gateway); - - addr = (struct sockaddr_in *) &rt.rt_genmask; - addr->sin_family = AF_INET; - addr->sin_addr.s_addr = INADDR_ANY; - - err = ioctl(sk, SIOCADDRT, &rt); - if (err < 0) - DBG("default route setting failed (%s)", strerror(errno)); + if (g_strcmp0(data->ipv4_gateway, "0.0.0.0") == 0) { + if (connman_inet_set_gateway_interface(element->index) < 0) + return; + goto done; + } - close(sk); + if (connman_inet_set_gateway_address(element->index, + data->ipv4_gateway) < 0) + return; - return err; +done: + service = __connman_element_get_service(element); + __connman_service_indicate_default(service); } -static int del_route(struct connman_element *element, const char *gateway) +static struct gateway_data *find_default_gateway(void) { - struct ifreq ifr; - struct rtentry rt; - struct sockaddr_in *addr; - int sk, err; - - DBG("element %p", element); - - sk = socket(PF_INET, SOCK_DGRAM, 0); - if (sk < 0) - return -1; + struct gateway_data *found = NULL; + unsigned int order = 0; + GSList *list; - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_ifindex = element->index; + for (list = gateway_list; list; list = list->next) { + struct gateway_data *data = list->data; - if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) { - close(sk); - return -1; + if (found == NULL || data->order > order) { + found = data; + order = data->order; + } } - DBG("ifname %s", ifr.ifr_name); - - memset(&rt, 0, sizeof(rt)); - rt.rt_flags = RTF_UP | RTF_GATEWAY; - - addr = (struct sockaddr_in *) &rt.rt_dst; - addr->sin_family = AF_INET; - addr->sin_addr.s_addr = INADDR_ANY; - - addr = (struct sockaddr_in *) &rt.rt_gateway; - addr->sin_family = AF_INET; - addr->sin_addr.s_addr = inet_addr(gateway); - - addr = (struct sockaddr_in *) &rt.rt_genmask; - addr->sin_family = AF_INET; - addr->sin_addr.s_addr = INADDR_ANY; - - err = ioctl(sk, SIOCDELRT, &rt); - if (err < 0) - DBG("default route removal failed (%s)", strerror(errno)); - - close(sk); - - return err; + return found; } -static DBusMessage *get_properties(DBusConnection *conn, - DBusMessage *msg, void *data) +static int remove_gateway(struct gateway_data *data) { - struct connman_element *element = data; - DBusMessage *reply; - DBusMessageIter array, dict; - const char *type = NULL, *method = NULL; - const char *address = NULL, *netmask = NULL, *gateway = NULL; - - DBG("conn %p", conn); - - reply = dbus_message_new_method_return(msg); - if (reply == NULL) - return NULL; - - dbus_message_iter_init_append(reply, &array); - - dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY, - DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING - DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING - DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); - - connman_element_get_static_property(element, "Type", &type); - - if (type != NULL) - connman_dbus_dict_append_variant(&dict, "Type", - DBUS_TYPE_STRING, &type); - - if (element->devname != NULL) - connman_dbus_dict_append_variant(&dict, "Interface", - DBUS_TYPE_STRING, &element->devname); - - connman_dbus_dict_append_variant(&dict, "Default", - DBUS_TYPE_BOOLEAN, &element->enabled); - - connman_element_get_value(element, - CONNMAN_PROPERTY_ID_IPV4_METHOD, &method); - - connman_element_get_value(element, - CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &address); - connman_element_get_value(element, - CONNMAN_PROPERTY_ID_IPV4_NETMASK, &netmask); - connman_element_get_value(element, - CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway); - - if (method != NULL) - connman_dbus_dict_append_variant(&dict, "IPv4.Method", - DBUS_TYPE_STRING, &method); + int err; - if (address != NULL) - connman_dbus_dict_append_variant(&dict, "IPv4.Address", - DBUS_TYPE_STRING, &address); + DBG("gateway %s", data->ipv4_gateway); - if (netmask != NULL) - connman_dbus_dict_append_variant(&dict, "IPv4.Netmask", - DBUS_TYPE_STRING, &netmask); + gateway_list = g_slist_remove(gateway_list, data); - if (gateway != NULL) - connman_dbus_dict_append_variant(&dict, "IPv4.Gateway", - DBUS_TYPE_STRING, &gateway); + if (data->active == TRUE) + err = del_routes(data); + else + err = 0; - dbus_message_iter_close_container(&array, &dict); + g_free(data->ipv4_gateway); + g_free(data->vpn_ip); + g_free(data); - return reply; + return err; } -static DBusMessage *set_property(DBusConnection *conn, - DBusMessage *msg, void *data) +static void connection_delgateway(int index, const char *gateway) { - DBusMessageIter iter, value; - const char *name; - - DBG("conn %p", conn); - - if (dbus_message_iter_init(msg, &iter) == FALSE) - return __connman_error_invalid_arguments(msg); + struct gateway_data *data; - dbus_message_iter_get_basic(&iter, &name); - dbus_message_iter_next(&iter); - dbus_message_iter_recurse(&iter, &value); + DBG("index %d gateway %s", index, gateway); - if (__connman_security_check_privileges(msg) < 0) - return __connman_error_permission_denied(msg); + data = find_gateway(index, gateway); + if (data != NULL) + data->active = FALSE; - return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); + data = find_default_gateway(); + if (data != NULL) + set_default_gateway(data); } -static GDBusMethodTable connection_methods[] = { - { "GetProperties", "", "a{sv}", get_properties }, - { "SetProperty", "sv", "", set_property }, - { }, -}; - -static GDBusSignalTable connection_signals[] = { - { "PropertyChanged", "sv" }, - { }, +static struct connman_rtnl connection_rtnl = { + .name = "connection", + .newgateway = connection_newgateway, + .delgateway = connection_delgateway, }; -static DBusConnection *connection; - -static void emit_connections_signal(void) -{ -} - -static int register_interface(struct connman_element *element) +static struct gateway_data *find_active_gateway(void) { - DBG("element %p name %s", element, element->name); - - if (g_dbus_register_interface(connection, element->path, - CONNMAN_CONNECTION_INTERFACE, - connection_methods, connection_signals, - NULL, element, NULL) == FALSE) { - connman_error("Failed to register %s connection", element->path); - return -EIO; - } - - emit_connections_signal(); + GSList *list; - return 0; -} + DBG(""); -static void unregister_interface(struct connman_element *element) -{ - DBG("element %p name %s", element, element->name); + for (list = gateway_list; list; list = list->next) { + struct gateway_data *data = list->data; - emit_connections_signal(); + if (data->active == TRUE) + return data; + } - g_dbus_unregister_interface(connection, element->path, - CONNMAN_CONNECTION_INTERFACE); + return NULL; } static int connection_probe(struct connman_element *element) { + struct connman_service *service = NULL; const char *gateway = NULL; + const char *vpn_ip = NULL; + struct gateway_data *active_gateway = NULL; + struct gateway_data *new_gateway = NULL; DBG("element %p name %s", element, element->name); if (element->parent == NULL) return -ENODEV; - if (element->parent->type != CONNMAN_ELEMENT_TYPE_IPV4) - return -ENODEV; + /* FIXME: Remove temporarily for the static gateway support */ + /* if (element->parent->type != CONNMAN_ELEMENT_TYPE_IPV4) + return -ENODEV; */ connman_element_get_value(element, CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway); + connman_element_get_value(element, + CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &vpn_ip); + DBG("gateway %s", gateway); - if (register_interface(element) < 0) - return -ENODEV; + /* + * If gateway is NULL, it's a point to point link and the default + * gateway is 0.0.0.0, meaning the interface. + */ + if (gateway == NULL) { + gateway = "0.0.0.0"; + element->ipv4.gateway = g_strdup(gateway); + } - if (gateway == NULL) + connman_element_set_enabled(element, TRUE); + + active_gateway = find_active_gateway(); + new_gateway = add_gateway(element->index, gateway); + if (new_gateway == NULL) return 0; - if (g_slist_length(gateway_list) > 0) { - DBG("default gateway already present"); + service = __connman_element_get_service(element); + + connman_inet_add_host_route(element->index, + new_gateway->ipv4_gateway, NULL); + __connman_service_nameserver_add_routes(service, + new_gateway->ipv4_gateway); + + __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY); + + if (service == NULL) { + new_gateway->vpn = TRUE; + new_gateway->vpn_ip = g_strdup(vpn_ip); + /* make sure vpn gateway are at higher priority */ + new_gateway->order = 10; + if (active_gateway) + new_gateway->vpn_phy_index = active_gateway->index; + } else + new_gateway->vpn = FALSE; + + if (active_gateway == NULL) { + set_default_gateway(new_gateway); return 0; } - set_route(element, gateway); + if (new_gateway->vpn == TRUE) { + connman_inet_add_host_route(active_gateway->index, + new_gateway->ipv4_gateway, + active_gateway->ipv4_gateway); + } - connman_element_set_enabled(element, TRUE); + if (new_gateway->order >= active_gateway->order) { + del_routes(active_gateway); + return 0; + } return 0; } static void connection_remove(struct connman_element *element) { + struct connman_service *service; const char *gateway = NULL; + struct gateway_data *data = NULL; + gboolean set_default = FALSE; + int err; DBG("element %p name %s", element, element->name); - unregister_interface(element); + service = __connman_element_get_service(element); + __connman_service_nameserver_del_routes(service); + __connman_service_indicate_state(service, + CONNMAN_SERVICE_STATE_DISCONNECT); + + connman_element_set_enabled(element, FALSE); connman_element_get_value(element, CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway); @@ -381,7 +350,27 @@ static void connection_remove(struct connman_element *element) if (gateway == NULL) return; - del_route(element, gateway); + data = find_gateway(element->index, gateway); + if (data == NULL) + return; + + set_default = data->vpn; + + if (data->vpn == TRUE && data->vpn_phy_index >= 0) + connman_inet_del_host_route(data->vpn_phy_index, + data->ipv4_gateway); + err = remove_gateway(data); + + /* with vpn this will be called after the network was deleted, + * we need to call set_default here because we will not recieve any + * gateway delete notification. + * We hit the same issue if remove_gateway() fails. + */ + if (set_default || err < 0) { + data = find_default_gateway(); + if (data != NULL) + set_default_gateway(data); + } } static struct connman_driver connection_driver = { @@ -396,13 +385,9 @@ int __connman_connection_init(void) { DBG(""); - connection = connman_dbus_get_connection(); - if (connman_rtnl_register(&connection_rtnl) < 0) connman_error("Failed to setup RTNL gateway driver"); - connman_rtnl_send_getroute(); - return connman_driver_register(&connection_driver); } @@ -419,15 +404,48 @@ void __connman_connection_cleanup(void) for (list = gateway_list; list; list = list->next) { struct gateway_data *data = list->data; - DBG("index %d gateway %s", data->index, data->gateway); + DBG("index %d gateway %s", data->index, data->ipv4_gateway); - g_free(data->gateway); + g_free(data->ipv4_gateway); g_free(data); list->data = NULL; } g_slist_free(gateway_list); gateway_list = NULL; +} + +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; + + /* vpn gataway is not attached to a service. */ + if (data->vpn) + continue; + + service = __connman_element_get_service(data->element); + data->order = __connman_service_get_order(service); + } +} + +gboolean __connman_connection_update_gateway(void) +{ + struct gateway_data *active_gateway, *default_gateway; + gboolean updated = FALSE; + + update_order(); + + active_gateway = find_active_gateway(); + default_gateway = find_default_gateway(); + + if (active_gateway && active_gateway != default_gateway) { + del_routes(active_gateway); + updated = TRUE; + } - dbus_connection_unref(connection); + return updated; }