Add initial steps for IPv4 monitoring via RTNL
authorMarcel Holtmann <marcel@holtmann.org>
Sat, 8 Aug 2009 04:33:07 +0000 (21:33 -0700)
committerMarcel Holtmann <marcel@holtmann.org>
Sat, 8 Aug 2009 04:33:07 +0000 (21:33 -0700)
include/ipconfig.h
src/connman.h
src/device.c
src/ipconfig.c
src/network.c
src/rtnl.c
src/service.c

index 66a260b..08fe558 100644 (file)
@@ -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);
 
index bbe9e22..a5fb709 100644 (file)
@@ -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);
index 984f55f..7ac2ab8 100644 (file)
@@ -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)
index 6e4927d..2e3d22b 100644 (file)
@@ -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) {
index c9f6188..932e1f2 100644 (file)
@@ -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;
 }
 
index 5b07865..40b3ea9 100644 (file)
@@ -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;
 
index dfb2149..09d2534 100644 (file)
@@ -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);