diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2009-01-05 17:50:04 +0100 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2009-01-05 17:50:04 +0100 |
commit | d68748fc6f4e5b87f88b73519e353d4c2f21f4ba (patch) | |
tree | e37fa8132163fe5a757050f80edca37b3aa8a862 /src/connection.c | |
parent | f48005d81c0983c77740c16abde90e02d9505304 (diff) | |
download | connman-d68748fc6f4e5b87f88b73519e353d4c2f21f4ba.tar.gz connman-d68748fc6f4e5b87f88b73519e353d4c2f21f4ba.tar.bz2 connman-d68748fc6f4e5b87f88b73519e353d4c2f21f4ba.zip |
Remove gateway setup into the core connection handling
Diffstat (limited to 'src/connection.c')
-rw-r--r-- | src/connection.c | 236 |
1 files changed, 235 insertions, 1 deletions
diff --git a/src/connection.c b/src/connection.c index 6c7e03b8..9cd0f64c 100644 --- a/src/connection.c +++ b/src/connection.c @@ -23,10 +23,182 @@ #include <config.h> #endif +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <net/route.h> + #include <gdbus.h> #include "connman.h" +struct gateway_data { + int index; + char *gateway; +}; + +static GSList *gateway_list = NULL; + +static struct gateway_data *find_gateway(int index, const char *gateway) +{ + GSList *list; + + if (gateway == NULL) + return NULL; + + for (list = gateway_list; list; list = list->next) { + struct gateway_data *data = list->data; + + if (data->gateway == NULL) + continue; + + if (data->index == index && + g_str_equal(data->gateway, gateway) == TRUE) + return data; + } + + return NULL; +} + +static void connection_newgateway(int index, const char *gateway) +{ + struct gateway_data *data; + + DBG("index %d gateway %s", index, gateway); + + data = find_gateway(index, gateway); + if (data != NULL) + return; + + data = g_try_new0(struct gateway_data, 1); + if (data == NULL) + return; + + data->index = index; + data->gateway = g_strdup(gateway); + + gateway_list = g_slist_append(gateway_list, data); +} + +static void connection_delgateway(int index, const char *gateway) +{ + struct gateway_data *data; + + DBG("index %d gateway %s", index, gateway); + + data = find_gateway(index, gateway); + if (data == NULL) + return; + + gateway_list = g_slist_remove(gateway_list, data); + + g_free(data->gateway); + g_free(data); +} + +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) +{ + 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; + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_ifindex = element->index; + + if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) { + close(sk); + return -1; + } + + 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)); + + close(sk); + + return err; +} + +static int del_route(struct connman_element *element, const char *gateway) +{ + 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; + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_ifindex = element->index; + + if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) { + close(sk); + return -1; + } + + 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; +} + static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -118,16 +290,56 @@ static void unregister_interface(struct connman_element *element) static int connection_probe(struct connman_element *element) { + const char *gateway = NULL; + DBG("element %p name %s", element, element->name); - return register_interface(element); + if (element->parent == NULL) + return -ENODEV; + + if (element->parent->type != CONNMAN_ELEMENT_TYPE_IPV4) + return -ENODEV; + + connman_element_get_value(element, + CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway); + + DBG("gateway %s", gateway); + + if (register_interface(element) < 0) + return -ENODEV; + + if (gateway == NULL) + return 0; + + if (g_slist_length(gateway_list) > 0) { + DBG("default gateway already present"); + return 0; + } + + set_route(element, gateway); + + connman_element_set_enabled(element, TRUE); + + return 0; } static void connection_remove(struct connman_element *element) { + const char *gateway = NULL; + DBG("element %p name %s", element, element->name); unregister_interface(element); + + connman_element_get_value(element, + CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway); + + DBG("gateway %s", gateway); + + if (gateway == NULL) + return; + + del_route(element, gateway); } static struct connman_driver connection_driver = { @@ -144,14 +356,36 @@ int __connman_connection_init(void) 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); } void __connman_connection_cleanup(void) { + GSList *list; + DBG(""); connman_driver_unregister(&connection_driver); + connman_rtnl_unregister(&connection_rtnl); + + for (list = gateway_list; list; list = list->next) { + struct gateway_data *data = list->data; + + DBG("index %d gateway %s", data->index, data->gateway); + + g_free(data->gateway); + g_free(data); + list->data = NULL; + } + + g_slist_free(gateway_list); + gateway_list = NULL; + dbus_connection_unref(connection); } |