summaryrefslogtreecommitdiff
path: root/src/connection.c
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2009-01-05 17:50:04 +0100
committerMarcel Holtmann <marcel@holtmann.org>2009-01-05 17:50:04 +0100
commitd68748fc6f4e5b87f88b73519e353d4c2f21f4ba (patch)
treee37fa8132163fe5a757050f80edca37b3aa8a862 /src/connection.c
parentf48005d81c0983c77740c16abde90e02d9505304 (diff)
downloadconnman-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.c236
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);
}