summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2009-08-07 21:33:07 -0700
committerMarcel Holtmann <marcel@holtmann.org>2009-08-07 21:33:07 -0700
commite77f2d1c63c96990529f4e4294337263b8738ff8 (patch)
tree14213f079a4597ee5e0239e68d1a6edbeffc2b3d
parent4957458bfb61b41451977feaad2761226d30585d (diff)
downloadconnman-e77f2d1c63c96990529f4e4294337263b8738ff8.tar.gz
connman-e77f2d1c63c96990529f4e4294337263b8738ff8.tar.bz2
connman-e77f2d1c63c96990529f4e4294337263b8738ff8.zip
Add initial steps for IPv4 monitoring via RTNL
-rw-r--r--include/ipconfig.h2
-rw-r--r--src/connman.h12
-rw-r--r--src/device.c19
-rw-r--r--src/ipconfig.c38
-rw-r--r--src/network.c14
-rw-r--r--src/rtnl.c164
-rw-r--r--src/service.c27
7 files changed, 237 insertions, 39 deletions
diff --git a/include/ipconfig.h b/include/ipconfig.h
index 66a260ba..08fe5588 100644
--- a/include/ipconfig.h
+++ b/include/ipconfig.h
@@ -47,7 +47,7 @@ enum connman_ipconfig_method {
struct connman_ipconfig;
-struct connman_ipconfig *connman_ipconfig_create(void);
+struct connman_ipconfig *connman_ipconfig_create(const char *interface);
struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig);
void connman_ipconfig_unref(struct connman_ipconfig *ipconfig);
diff --git a/src/connman.h b/src/connman.h
index bbe9e226..a5fb7091 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -91,6 +91,15 @@ int __connman_security_check_privilege(DBusMessage *message,
#include <connman/ipconfig.h>
+int __connman_ipconfig_get_index(struct connman_ipconfig *ipconfig);
+
+void __connman_ipconfig_add_address(struct connman_ipconfig *ipconfig,
+ const char *label, unsigned int prefixlen,
+ const char *address, const char *broadcast);
+void __connman_ipconfig_del_address(struct connman_ipconfig *ipconfig,
+ const char *label, unsigned int prefixlen,
+ const char *address, const char *broadcast);
+
const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method);
enum connman_ipconfig_method __connman_ipconfig_string2method(const char *method);
@@ -347,3 +356,6 @@ void __connman_rtnl_start(void);
void __connman_rtnl_cleanup(void);
int __connman_rtnl_send(const void *buf, size_t len);
+
+int __connman_rtnl_register_ipconfig(struct connman_ipconfig *ipconfig);
+void __connman_rtnl_unregister_ipconfig(struct connman_ipconfig *ipconfig);
diff --git a/src/device.c b/src/device.c
index 984f55f5..7ac2ab85 100644
--- a/src/device.c
+++ b/src/device.c
@@ -544,6 +544,9 @@ static DBusMessage *set_property(DBusConnection *conn,
} else if (g_str_has_prefix(name, "IPv4.") == TRUE) {
int err;
+ if (device->ipconfig == NULL)
+ return __connman_error_invalid_property(msg);
+
switch (device->mode) {
case CONNMAN_DEVICE_MODE_UNKNOWN:
case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
@@ -862,7 +865,10 @@ static void device_destruct(struct connman_element *element)
g_free(device->control);
g_free(device->interface);
- connman_ipconfig_unref(device->ipconfig);
+ if (device->ipconfig != NULL) {
+ connman_ipconfig_unref(device->ipconfig);
+ device->ipconfig = NULL;
+ }
g_free(device->last_network);
@@ -944,12 +950,6 @@ struct connman_device *connman_device_create(const char *node,
break;
}
- device->ipconfig = connman_ipconfig_create();
- if (device->ipconfig == NULL) {
- connman_device_unref(device);
- return NULL;
- }
-
device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, unregister_network);
@@ -1079,6 +1079,11 @@ void connman_device_set_interface(struct connman_device *device,
device->name = g_strdup_printf("%s (%s)", str,
device->interface);
}
+
+ if (device->ipconfig != NULL)
+ connman_ipconfig_unref(device->ipconfig);
+
+ device->ipconfig = connman_ipconfig_create(interface);
}
const char *connman_device_get_control(struct connman_device *device)
diff --git a/src/ipconfig.c b/src/ipconfig.c
index 6e4927d4..2e3d22bc 100644
--- a/src/ipconfig.c
+++ b/src/ipconfig.c
@@ -29,6 +29,8 @@
struct connman_ipconfig {
gint refcount;
+ int index;
+ char *interface;
enum connman_ipconfig_method method;
};
@@ -39,18 +41,28 @@ struct connman_ipconfig {
*
* Returns: a newly-allocated #connman_ipconfig structure
*/
-struct connman_ipconfig *connman_ipconfig_create(void)
+struct connman_ipconfig *connman_ipconfig_create(const char *interface)
{
struct connman_ipconfig *ipconfig;
+ int index;
DBG("");
+ index = connman_inet_ifindex(interface);
+ if (index < 0)
+ return NULL;
+
ipconfig = g_try_new0(struct connman_ipconfig, 1);
if (ipconfig == NULL)
return NULL;
+ ipconfig->index = index;
+ ipconfig->interface = g_strdup(interface);
+
DBG("ipconfig %p", ipconfig);
+ __connman_rtnl_register_ipconfig(ipconfig);
+
return ipconfig;
}
@@ -76,6 +88,9 @@ struct connman_ipconfig *connman_ipconfig_ref(struct connman_ipconfig *ipconfig)
void connman_ipconfig_unref(struct connman_ipconfig *ipconfig)
{
if (g_atomic_int_dec_and_test(&ipconfig->refcount) == TRUE) {
+ __connman_rtnl_unregister_ipconfig(ipconfig);
+
+ g_free(ipconfig->interface);
g_free(ipconfig);
}
}
@@ -95,6 +110,27 @@ int connman_ipconfig_set_method(struct connman_ipconfig *ipconfig,
return 0;
}
+int __connman_ipconfig_get_index(struct connman_ipconfig *ipconfig)
+{
+ return ipconfig->index;
+}
+
+void __connman_ipconfig_add_address(struct connman_ipconfig *ipconfig,
+ const char *label, unsigned int prefixlen,
+ const char *address, const char *broadcast)
+{
+ connman_info("%s {add} address %s/%d label %s", ipconfig->interface,
+ address, prefixlen, label);
+}
+
+void __connman_ipconfig_del_address(struct connman_ipconfig *ipconfig,
+ const char *label, unsigned int prefixlen,
+ const char *address, const char *broadcast)
+{
+ connman_info("%s {del} address %s/%d label %s", ipconfig->interface,
+ address, prefixlen, label);
+}
+
const char *__connman_ipconfig_method2string(enum connman_ipconfig_method method)
{
switch (method) {
diff --git a/src/network.c b/src/network.c
index c9f61886..932e1f26 100644
--- a/src/network.c
+++ b/src/network.c
@@ -205,6 +205,9 @@ static DBusMessage *set_property(DBusConnection *conn,
} else if (g_str_has_prefix(name, "IPv4.") == TRUE) {
int err;
+ if (network->ipconfig == NULL)
+ return __connman_error_invalid_property(msg);
+
err = __connman_ipconfig_set_ipv4(network->ipconfig,
name + 5, &value);
if (err < 0)
@@ -368,7 +371,10 @@ static void network_destruct(struct connman_element *element)
g_free(network->address);
g_free(network->identifier);
- connman_ipconfig_unref(network->ipconfig);
+ if (network->ipconfig) {
+ connman_ipconfig_unref(network->ipconfig);
+ network->ipconfig = NULL;
+ }
}
/**
@@ -425,12 +431,6 @@ struct connman_network *connman_network_create(const char *identifier,
network->secondary = FALSE;
network->identifier = g_strdup(temp);
- network->ipconfig = connman_ipconfig_create();
- if (network->ipconfig == NULL) {
- connman_network_unref(network);
- return NULL;
- }
-
return network;
}
diff --git a/src/rtnl.c b/src/rtnl.c
index 5b07865e..40b3ea93 100644
--- a/src/rtnl.c
+++ b/src/rtnl.c
@@ -244,6 +244,99 @@ static void process_delgateway(struct rtmsg *msg, int bytes)
g_free(gateway);
}
+static void extract_addr(struct ifaddrmsg *msg, int bytes,
+ const char **label,
+ struct in_addr *local,
+ struct in_addr *address,
+ struct in_addr *broadcast)
+{
+ struct rtattr *attr;
+
+ for (attr = IFA_RTA(msg); RTA_OK(attr, bytes);
+ attr = RTA_NEXT(attr, bytes)) {
+ switch (attr->rta_type) {
+ case IFA_ADDRESS:
+ if (address != NULL)
+ *address = *((struct in_addr *) RTA_DATA(attr));
+ break;
+ case IFA_LOCAL:
+ if (local != NULL)
+ *local = *((struct in_addr *) RTA_DATA(attr));
+ break;
+ case IFA_BROADCAST:
+ if (broadcast != NULL)
+ *broadcast = *((struct in_addr *) RTA_DATA(attr));
+ break;
+ case IFA_LABEL:
+ if (label != NULL)
+ *label = RTA_DATA(attr);
+ break;
+ }
+ }
+}
+
+static GSList *ipconfig_list = NULL;
+
+static void process_newaddr(int family, int prefixlen, int index,
+ struct ifaddrmsg *msg, int bytes)
+{
+ GSList *list;
+ const char *label;
+ struct in_addr address;
+
+ if (family != AF_INET)
+ return;
+
+ for (list = ipconfig_list; list; list = list->next) {
+ struct connman_ipconfig *ipconfig = list->data;
+
+ if (__connman_ipconfig_get_index(ipconfig) != index)
+ continue;
+
+ extract_addr(msg, bytes, &label, &address, NULL, NULL);
+ __connman_ipconfig_add_address(ipconfig, label, prefixlen,
+ inet_ntoa(address), NULL);
+ }
+}
+
+static void process_deladdr(int family, int prefixlen, int index,
+ struct ifaddrmsg *msg, int bytes)
+{
+ GSList *list;
+ const char *label;
+ struct in_addr address;
+
+ if (family != AF_INET)
+ return;
+
+ for (list = ipconfig_list; list; list = list->next) {
+ struct connman_ipconfig *ipconfig = list->data;
+
+ if (__connman_ipconfig_get_index(ipconfig) != index)
+ continue;
+
+ extract_addr(msg, bytes, &label, &address, NULL, NULL);
+ __connman_ipconfig_del_address(ipconfig, label, prefixlen,
+ inet_ntoa(address), NULL);
+ }
+}
+
+int __connman_rtnl_register_ipconfig(struct connman_ipconfig *ipconfig)
+{
+ DBG("ipconfig %p", ipconfig);
+
+ ipconfig_list = g_slist_append(ipconfig_list, ipconfig);
+
+ return 0;
+}
+
+void __connman_rtnl_unregister_ipconfig(struct connman_ipconfig *ipconfig)
+{
+ DBG("ipconfig %p", ipconfig);
+
+ ipconfig_list = g_slist_remove(ipconfig_list, ipconfig);
+}
+
static inline void print_inet(struct rtattr *attr, const char *name, int family)
{
if (family == AF_INET) {
@@ -384,6 +477,7 @@ static void rtnl_dellink(struct nlmsghdr *hdr)
static void rtnl_addr(struct nlmsghdr *hdr)
{
+#if 0
struct ifaddrmsg *msg;
struct rtattr *attr;
int bytes;
@@ -422,6 +516,35 @@ static void rtnl_addr(struct nlmsghdr *hdr)
break;
}
}
+#endif
+}
+
+static void rtnl_newaddr(struct nlmsghdr *hdr)
+{
+ struct ifaddrmsg *msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
+
+ DBG("ifa_family %d ifa_prefixlen %d ifa_index %d",
+ msg->ifa_family, msg->ifa_prefixlen, msg->ifa_index);
+
+ process_newaddr(msg->ifa_family, msg->ifa_prefixlen, msg->ifa_index,
+ msg, IFA_PAYLOAD(hdr));
+
+ rtnl_addr(hdr);
+}
+
+static void rtnl_deladdr(struct nlmsghdr *hdr)
+{
+ struct ifaddrmsg *msg;
+
+ msg = (struct ifaddrmsg *) NLMSG_DATA(hdr);
+
+ DBG("ifa_family %d ifa_prefixlen %d ifa_index %d",
+ msg->ifa_family, msg->ifa_prefixlen, msg->ifa_index);
+
+ process_deladdr(msg->ifa_family, msg->ifa_prefixlen, msg->ifa_index,
+ msg, IFA_PAYLOAD(hdr));
+
+ rtnl_addr(hdr);
}
static void rtnl_route(struct nlmsghdr *hdr)
@@ -476,9 +599,7 @@ static void rtnl_route(struct nlmsghdr *hdr)
static void rtnl_newroute(struct nlmsghdr *hdr)
{
- struct rtmsg *msg;
-
- msg = (struct rtmsg *) NLMSG_DATA(hdr);
+ struct rtmsg *msg = (struct rtmsg *) NLMSG_DATA(hdr);
if (msg->rtm_type == RTN_UNICAST && msg->rtm_table == RT_TABLE_MAIN &&
msg->rtm_scope == RT_SCOPE_UNIVERSE) {
@@ -493,9 +614,7 @@ static void rtnl_newroute(struct nlmsghdr *hdr)
static void rtnl_delroute(struct nlmsghdr *hdr)
{
- struct rtmsg *msg;
-
- msg = (struct rtmsg *) NLMSG_DATA(hdr);
+ struct rtmsg *msg = (struct rtmsg *) NLMSG_DATA(hdr);
if (msg->rtm_type == RTN_UNICAST && msg->rtm_table == RT_TABLE_MAIN &&
msg->rtm_scope == RT_SCOPE_UNIVERSE) {
@@ -648,8 +767,10 @@ static void rtnl_message(void *buf, size_t len)
rtnl_dellink(hdr);
break;
case RTM_NEWADDR:
+ rtnl_newaddr(hdr);
+ break;
case RTM_DELADDR:
- rtnl_addr(hdr);
+ rtnl_deladdr(hdr);
break;
case RTM_NEWROUTE:
rtnl_newroute(hdr);
@@ -708,6 +829,26 @@ int connman_rtnl_send_getlink(void)
return queue_request(req);
}
+static int send_getaddr(void)
+{
+ struct rtnl_request *req;
+
+ DBG("");
+
+ req = g_try_malloc0(RTNL_REQUEST_SIZE);
+ if (req == NULL)
+ return -ENOMEM;
+
+ req->hdr.nlmsg_len = RTNL_REQUEST_SIZE;
+ req->hdr.nlmsg_type = RTM_GETADDR;
+ req->hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ req->hdr.nlmsg_pid = 0;
+ req->hdr.nlmsg_seq = request_seq++;
+ req->msg.rtgen_family = AF_INET;
+
+ return queue_request(req);
+}
+
int connman_rtnl_send_getroute(void)
{
struct rtnl_request *req;
@@ -741,9 +882,7 @@ int __connman_rtnl_init(void)
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
- addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE;
- //addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
- //addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
+ addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;
if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(sk);
@@ -762,6 +901,8 @@ int __connman_rtnl_init(void)
void __connman_rtnl_start(void)
{
DBG("");
+
+ send_getaddr();
}
void __connman_rtnl_cleanup(void)
@@ -770,6 +911,9 @@ void __connman_rtnl_cleanup(void)
DBG("");
+ g_slist_free(ipconfig_list);
+ ipconfig_list = NULL;
+
for (list = watch_list; list; list = list->next) {
struct watch_data *watch = list->data;
diff --git a/src/service.c b/src/service.c
index dfb2149f..09d2534e 100644
--- a/src/service.c
+++ b/src/service.c
@@ -467,7 +467,9 @@ static DBusMessage *get_properties(DBusConnection *conn,
break;
}
- __connman_ipconfig_append_ipv4(service->ipconfig, &dict, "IPv4.");
+ if (service->ipconfig != NULL)
+ __connman_ipconfig_append_ipv4(service->ipconfig,
+ &dict, "IPv4.");
dbus_message_iter_close_container(&array, &dict);
@@ -541,6 +543,9 @@ static DBusMessage *set_property(DBusConnection *conn,
} else if (g_str_has_prefix(name, "IPv4.") == TRUE) {
int err;
+ if (service->ipconfig == NULL)
+ return __connman_error_invalid_property(msg);
+
err = __connman_ipconfig_set_ipv4(service->ipconfig,
name + 5, &value);
if (err < 0)
@@ -942,7 +947,10 @@ static void service_free(gpointer user_data)
if (service->network != NULL)
connman_network_unref(service->network);
- connman_ipconfig_unref(service->ipconfig);
+ if (service->ipconfig != NULL) {
+ connman_ipconfig_unref(service->ipconfig);
+ service->ipconfig = NULL;
+ }
g_free(service->profile);
g_free(service->name);
@@ -1011,15 +1019,6 @@ struct connman_service *connman_service_create(void)
__connman_service_initialize(service);
- service->ipconfig = connman_ipconfig_create();
- if (service->ipconfig == NULL) {
- g_free(service);
- return NULL;
- }
-
- connman_ipconfig_set_method(service->ipconfig,
- CONNMAN_IPCONFIG_METHOD_DHCP);
-
return service;
}
@@ -2087,7 +2086,8 @@ static int service_load(struct connman_service *service)
service->passphrase = str;
}
- __connman_ipconfig_load(service->ipconfig, keyfile,
+ if (service->ipconfig != NULL)
+ __connman_ipconfig_load(service->ipconfig, keyfile,
service->identifier, "IPv4.");
done:
@@ -2204,7 +2204,8 @@ update:
g_key_file_remove_key(keyfile, service->identifier,
"Passphrase", NULL);
- __connman_ipconfig_save(service->ipconfig, keyfile,
+ if (service->ipconfig != NULL)
+ __connman_ipconfig_save(service->ipconfig, keyfile,
service->identifier, "IPv4.");
data = g_key_file_to_data(keyfile, &length, NULL);